AM312 PIR Sensor?

gamename
Posts: 31
Joined: Fri Dec 08, 2023 11:33 pm

AM312 PIR Sensor?

Postby gamename » Fri Jul 19, 2024 12:36 am

Hi,

Does anyone have a code example of the am312 PIR sensor? I've found them to be very reliable in MicroPython, but I can't get them to work in an ESP-IDF/FreeRTOS app written in C. Keep getting random motion detection for no reason (even when the sensor is completely covered).

Since this PIR sensor is so popular, I'm hoping someone would have a working example out there.

For the curious, here is my (randomly triggering) code. Any suggestions would be welcome.

Thanks,
-T

MicroController
Posts: 1515
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: AM312 PIR Sensor?

Postby MicroController » Fri Jul 19, 2024 1:26 pm

Apart from the overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic, and the use of ESP_LOGx inside an ISR which should be avoided, the code looks all right to me.
Could you be having an issue with wiring/an unreliable connection (breadboard?) between the sensor and the ESP?

gamename
Posts: 31
Joined: Fri Dec 08, 2023 11:33 pm

Re: AM312 PIR Sensor?

Postby gamename » Fri Jul 19, 2024 4:14 pm

MicroController wrote:
Fri Jul 19, 2024 1:26 pm
Apart from the overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic, and the use of ESP_LOGx inside an ISR which should be avoided, the code looks all right to me.
Could you be having an issue with wiring/an unreliable connection (breadboard?) between the sensor and the ESP?
Thanks for the response. Its much appreciated. I'll make the change you suggested, but not sure what was meant by "overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic". Could you expand on that?

As for the breadboard + connections, I've tried this same code on 2 completely different setups (breadboard, wires, sensor, microprocessor, everything). Still get the same behavior.

This is so puzzling. The am312 obviously works in C because MicroPython works (which is written in C). So, wtf?

Thanks again,
-T

MicroController
Posts: 1515
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: AM312 PIR Sensor?

Postby MicroController » Fri Jul 19, 2024 7:28 pm

gamename wrote:
Fri Jul 19, 2024 4:14 pm
"overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic". Could you expand on that?
It's likely only a theoretical problem, but FreeRTOS's 32-bit tick counter will overflow at some point after the system has been running without a restart for a long time (months, or a year, depending on tick rate).
To correctly handle that situation it is advisable to do

Code: Select all

if( (now - previous) > SOME_TIME ) { ... }
instead of

Code: Select all

if ( now > (previous + SOME_TIME) ) {...}
because, in case of an overflow, (previous + SOME_TIME) may turn out to be < previous.

MicroController
Posts: 1515
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: AM312 PIR Sensor?

Postby MicroController » Fri Jul 19, 2024 7:43 pm

gamename wrote:
Fri Jul 19, 2024 4:14 pm
The am312 obviously works in C because MicroPython works (which is written in C). So, wtf?
You could try disabling the ESP's pull-up resistor. Datasheets seem to imply that the sensor doesn't need it.

gamename
Posts: 31
Joined: Fri Dec 08, 2023 11:33 pm

Re: AM312 PIR Sensor?

Postby gamename » Fri Jul 19, 2024 8:58 pm

MicroController wrote:
Fri Jul 19, 2024 7:43 pm
gamename wrote:
Fri Jul 19, 2024 4:14 pm
The am312 obviously works in C because MicroPython works (which is written in C). So, wtf?
You could try disabling the ESP's pull-up resistor. Datasheets seem to imply that the sensor doesn't need it.
Great point! I'll try that.

Thanks!

gamename
Posts: 31
Joined: Fri Dec 08, 2023 11:33 pm

Re: AM312 PIR Sensor?

Postby gamename » Sat Jul 20, 2024 12:52 am

MicroController wrote:
Fri Jul 19, 2024 7:43 pm
gamename wrote:
Fri Jul 19, 2024 4:14 pm
The am312 obviously works in C because MicroPython works (which is written in C). So, wtf?
You could try disabling the ESP's pull-up resistor. Datasheets seem to imply that the sensor doesn't need it.

Tried the disable. The behavior is better, but not yet fixed. There are still random "motion detected" events, but fewer.

Here's the code:

Code: Select all

#include "motion_sensor.h"

#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"  // Include semaphore header
#include "freertos/task.h"

#define DEBOUNCE_PERIOD_MS 1000

static const char* TAG = "MOTION_SENSOR";

extern QueueHandle_t motion_event_queue;  // Declare the queue handle

static volatile uint32_t last_motion_time = 0;
static volatile uint32_t debounce_end_time = 0;

static volatile bool log_event_queue_full = false;
static volatile bool log_debounce_event = false;
static volatile bool log_motion_detected = false;

static void IRAM_ATTR motion_sensor_isr_handler(void* arg) {
    uint32_t motion_detected = 1;
    uint32_t current_time = xTaskGetTickCountFromISR();

    // Software debounce logic
    if (current_time > debounce_end_time) {
        debounce_end_time = current_time + pdMS_TO_TICKS(DEBOUNCE_PERIOD_MS);
        last_motion_time = current_time;
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;

        if (xQueueSendFromISR(motion_event_queue, &motion_detected, &xHigherPriorityTaskWoken) !=
            pdPASS) {
            log_event_queue_full = true;
        } else {
            log_motion_detected = true;
        }

    } else {
        log_debounce_event = true;
    }
}

void motion_logging_task(void* pvParameters) {
    while (1) {
        if (log_motion_detected) {
            ESP_LOGW(TAG, "Motion detected!");
            log_motion_detected = false;
        }
        if (log_event_queue_full) {
            ESP_LOGW(TAG, "Motion event queue full, event lost.");
            log_event_queue_full = false;
        }
        if (log_debounce_event) {
            ESP_LOGI(TAG, "Motion event debounced.");
            log_debounce_event = false;
        }
        vTaskDelay(pdMS_TO_TICKS(100));  // Adjust the delay as needed
    }
}

void motion_sensor_init(void) {
    gpio_config_t io_conf = {.intr_type = GPIO_INTR_POSEDGE,  // Trigger on rising edge
                             .mode = GPIO_MODE_INPUT,         // Set as input mode
                             .pin_bit_mask = (1ULL << MOTION_SENSOR_PIN),
                             .pull_down_en = GPIO_PULLDOWN_DISABLE,
                             .pull_up_en = GPIO_PULLUP_DISABLE};

    gpio_config(&io_conf);

    // Install ISR service with default configuration
    gpio_install_isr_service(0);
    // Attach the interrupt service routine
    gpio_isr_handler_add(MOTION_SENSOR_PIN, motion_sensor_isr_handler, NULL);

    ESP_LOGI(TAG, "PIR sensor initialized.");

    // Create the logging task
    xTaskCreate(motion_logging_task, "motion_logging_task", 2048, NULL, 10, NULL);
}


Who is online

Users browsing this forum: No registered users and 48 guests