I’ve made further progress on my solution and discovered that using GPIO_FLOATING might not be the best approach for detecting the VOUT signal from the PIR sensor. This option can be unreliable for detection purposes. When I tested how the signal travels from the PIR sensor’s VOUT wire to GPIO2, I had the positive test probe of my multimeter connected to GPIO2. Surprisingly, the wakeup from the PIR worked reliably without floating (I changed GPIO_FLOATING to GPIO_PULLUP_PULLDOWN). It appears that the inner resistance of the multimeter had an impact on the reliability of the pulldown.
As a solution, I added a 22 kΩ resistor to the connection leading to GPIO2 and connected its other end to the 3.3V output of the ESP32-C3. That did the trick! Now GPIO2 operates reliably.
Here’s the setup:
Additional points of interest:
- Some PIR sensors have excellent standby current consumption: for example, the AM312 (8 uA) and the Panasonic EKMB1303111K (6 uA). The AM312 costs only about £2 in the UK while Panasonic’s sensor can cost over £20. I am using the AM312.
- I was able to connect the surface-mountable ESP32C3 to a breadboard using just jumper cable pins, which meant no soldering was needed for this quick test.
- I found it impossible to upload newly compiled firmware to the ESP32-C3 when either the resistor or the data wire of the PIR sensor (or both) was connected to GPIO2. This pin is also involved in the boot process.
- Below is the latest test code I used:
#define LED 10
#define INTERRUPT_PIN 2
RTC_DATA_ATTR int bootCount = 0;
void setup() {
Serial.begin(115200);
delay(1000);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
++bootCount;
Serial.println("Boot number: " + String(bootCount));
print_wakeup_reason();
Serial.println("Going to blink the LED 3 times");
blink(3);
Serial.println("Going to sleep now");
delay (1000);
gpio_sleep_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_PULLDOWN);
esp_deep_sleep_enable_gpio_wakeup(1 << INTERRUPT_PIN, ESP_GPIO_WAKEUP_GPIO_HIGH);
delay (1000);
esp_deep_sleep_start();
}
void loop() { }
void blink(int times) {
for (int i = 0; i < times; i++) {
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
Serial.print("Blink ");
Serial.println(i + 1);
}
}
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
char reason_description[100];
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_GPIO:
strcpy(reason_description, "Wakeup caused by GPIO");
break;
case ESP_SLEEP_WAKEUP_EXT0:
strcpy(reason_description, "Wakeup caused by external signal using RTC_IO");
break;
case ESP_SLEEP_WAKEUP_EXT1:
strcpy(reason_description, "Wakeup caused by external signal using RTC_CNTL");
break;
case ESP_SLEEP_WAKEUP_TIMER:
strcpy(reason_description, "Wakeup caused by timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
strcpy(reason_description, "Wakeup caused by touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP:
strcpy(reason_description, "Wakeup caused by ULP program");
break;
default:
snprintf(reason_description, sizeof(reason_description), "Wakeup was not caused by deep sleep: %d", wakeup_reason);
}
Serial.println(reason_description);
}