Unable to wake the XIAO ESP32C3 up from deep sleep with a PIR sensor

I started working with Seeed Studio ESP32C3 MCU boards and apperciate the small size and available options. I have been experimenting with deep sleep and waking up from PIR sensor output. For some reason it does not work. The PIR sensor I have is is U1 HW-740, connected to 3V3, GND and D3 pins. The board successfully goes into deep sleep but fails to wake up. Without deep sleep, the D3 pin works fine with this PIR sensor.

Here is the code for this test:

RTC_DATA_ATTR int bootCount = 0;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000);
  ++bootCount;

  Serial.println("Boot number: " + String(bootCount));

  print_wakeup_reason();
  esp_deep_sleep_enable_gpio_wakeup((1ULL << D3), ESP_GPIO_WAKEUP_GPIO_HIGH);
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){}

Tested this in Arduino IDE v. 2.1.1 and
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json added into “Additional boards manager URLs”.

Hi there,
5ven and welcome,
I have this code working with a button on D0, Blinks 10 times , Sleeps and wakes up If you press the button.
Here’s the code and the Output and a picture of the hardware setup

#define LED 10  // or use LED_BUILTIN for on-board LED
#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 10 times");
  blink(10);  // Allow time for wakeup
  Serial.println("Going to sleep now");
  delay (250);
 // esp_sleep_enable_bt_wakeup(void)
  esp_deep_sleep_enable_gpio_wakeup(1 << INTERRUPT_PIN, ESP_GPIO_WAKEUP_GPIO_HIGH);
    delay (250);
  esp_deep_sleep_start();

  Serial.println("This will never be printed");
}

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;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason) {
    case ESP_SLEEP_WAKEUP_EXT0:
      Serial.println("Wakeup caused by external signal using RTC_IO");
      break;
    case ESP_SLEEP_WAKEUP_EXT1:
      Serial.println("Wakeup caused by external signal using RTC_CNTL");
      break;
    case ESP_SLEEP_WAKEUP_TIMER:
      Serial.println("Wakeup caused by timer");
      break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD:
      Serial.println("Wakeup caused by touchpad");
      break;
    case ESP_SLEEP_WAKEUP_ULP:
      Serial.println("Wakeup caused by ULP program");
      break;
    default:
      Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
      break;
  }
}

The Serial Out.

ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4200f3a4
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd5810,len:0x438
load:0x403cc710,len:0x918
load:0x403ce710,len:0x25f4
entry 0x403cc710
Boot number: 1
Wakeup was not caused by deep sleep: 0
Going to blink the LED 10 times
Blink 1
Blink 2
Blink 3
Blink 4
Blink 5
Blink 6
Blink 7
Blink 8
Blink 9
Blink 10
Going to sleep now

push the button it wakes up.
HTH
GL :slight_smile: PJ

1 Like

Thanks! :smiley: Your example helped me further! GPIO2 seems to be the kind of a pin that needs a sudden pulse (that the pushbutton sends), not continuous current as coming through PIR sensor during 2 seconds. When I boot the system with the PIR sensor data wire disconnected, touch the PIR sensor and then in 2 seconds “hit” the GPIO2 pin with the jumper wire’s metal head, the ESP32-C3 awakes from deep sleep and the LED starts blinking.

My setup:

1 Like

Nice, Onward ! :person_fencing:
GL :slight_smile: PJ

Cheers, now it works! Added longer delays and
gpio_sleep_set_pull_mode(GPIO_NUM_2, GPIO_FLOATING);

like this:

Serial.println("Going to sleep now");
  delay (1000);
  gpio_sleep_set_pull_mode(GPIO_NUM_2, GPIO_FLOATING);
  esp_deep_sleep_enable_gpio_wakeup(1 << INTERRUPT_PIN, ESP_GPIO_WAKEUP_GPIO_HIGH);
  delay (1000);
  esp_deep_sleep_start();

Thanks for all the help and best wishes for the New Year!

1 Like

Awesome, don’t forget to mark as solution ,Others with Samd21 can find it also. Good sleuthing
and Same to you and Yours…
GL :slight_smile: PJ :v:

1 Like

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);
}
1 Like