arduinomicrocontrolleresp32arduino-idearduino-c++

Deep Sleep wakeup w/ ESP32-C3


buttonPin starts from a pressed state initially. Thus when the code is uploaded with the button pressed at the start, the esp32-c3 goes to sleep. The other button (buttonPin2) wakes the esp up from deep sleep when the gpio goes high. Upon wake up, the esp runs a BLE script and connects to a phone (using a ble scanner for testing). The deviceConnected callback puts the esp back to sleep once a successful connection has been made (after some delay). Now when the device goes back to sleep, the wake-up should occur via the first button (buttonPin). The code contains the lines for waking up the esp upon a gpio going low. However, once the button is released, the esp is reset (it takes an additional press of the button to print the wake-up reason and toggle the LEDs). Why is the ESP reset and not woken up from the button? How can I fix this? I want buttonPin2 to wake up the esp initially to pair it via bluetooth then want buttonPin to wake it up after it has gone back to sleep again (and toggle the LEDs upon wake up).

#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <Wire.h>
#include <Preferences.h>
#include <WiFi.h>
#include <WiFiMulti.h>


const int buttonPin = 3;  // # for button pin for States/Interrupt
const int buttonPin2 = 2; // # for button pin for BLE
const int ledPin =  5;   // # for the Green LED pin
const int ledPin2 = 6;   // # for the Red LED pin
const int ledPin3 = 7;    // # for the Blue LED pin


// variables will change:
int buttonState = 0;    
int lastButtonState = 0;
int buttonState2 = 0;
int lastButtonState2 = 0;  
int ledState = 0;
int state = 0;
//int BLEcounter = 0;
RTC_DATA_ATTR int counter = 0;


#define SERVICE_UUID        "f0e279fc-a979-4ffd-924c-59ced5392948"
#define CHARACTERISTIC_UUID "7f98738e-382d-43d9-b256-3cf8bd3120b7"


BLEServer *pServer = NULL;
BLEService *pService = NULL;
BLECharacteristic *pCharacteristic = NULL;


Preferences preferences;
WiFiMulti wifimulti;


bool deviceConnected = false;
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      Serial.println("True");
      state = preferences.getInt("state", 0);
      Serial.print("State: ");
      Serial.println(counter);
      delay(5000);
      Serial.println("Going to Sleep");
      digitalWrite(ledPin3, LOW);  // Turn off LED
      esp_deep_sleep_start();  // Enter deep sleep mode
    };


    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      Serial.println("Disconnected!");
      Serial.println("Advertising...");
      pServer->getAdvertising()->start();
    }
};


class MyCallbacks: public BLECharacteristicCallbacks
{
  void onWrite(BLECharacteristic *pCharacteristic)
  {
    std::string value = pCharacteristic->getValue();


    if (value.length() > 0)
    {
      Serial.println("*********");
      Serial.print("New value: ");
      for (int i = 0; i < value.length(); i++)
      {
        Serial.print(value[i]);
      }


      Serial.println();
      Serial.println("*********");
    }
  }
};


void setupBLEServer(void) {


  Serial.println("Starting BLE Server!");
  BLEDevice::init("Pirouette-IoT-Device");
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());


  pService = pServer->createService(SERVICE_UUID);


  pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY);


  pCharacteristic->setCallbacks(new MyCallbacks());


  pCharacteristic->setValue("device_state_0_stored");
  pService->start();
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  pAdvertising->start();
}


void pairing(){


  digitalWrite(ledPin3, HIGH);
  setupBLEServer();
}


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;
    case ESP_SLEEP_WAKEUP_GPIO: //New wakeup reason <--
      Serial.println("Wakeup caused by a GPIO");
      if(lastButtonState == HIGH && buttonState == LOW){
        counter++;
        Serial.print("Counter: ");
        Serial.println(counter);
      }
     
      if(counter == 1){
        digitalWrite(ledPin, HIGH);
      }


      //digitalWrite(ledPin, HIGH);
      //Serial.println("Advertising...");
      //pServer->startAdvertising();
      if(deviceConnected){
        if(pCharacteristic != NULL){
          pCharacteristic->setValue("device_state_1_ready"); //add code for device state 1 ready once buttonPin1 is pushed/released
          pCharacteristic->notify();
        }
      }
      break;
    default:
      Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
      break;
  }
}


void setup() {
 
  Serial.begin(115200);
 
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
 
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  pinMode(buttonPin2, INPUT_PULLUP);


  //Enable GPIO Wakeup from buttonPin
  esp_deep_sleep_enable_gpio_wakeup(1 << buttonPin, ESP_GPIO_WAKEUP_GPIO_LOW);
  esp_deep_sleep_enable_gpio_wakeup(1 << buttonPin2, ESP_GPIO_WAKEUP_GPIO_HIGH);
  gpio_set_direction((gpio_num_t)buttonPin, GPIO_MODE_INPUT);  // <<<=== Add this line
  gpio_set_direction((gpio_num_t)buttonPin2, GPIO_MODE_INPUT);  // <<<=== Add this line




  preferences.begin("dev-states", false);


  state = preferences.getInt("state", 0);
  Serial.print("State: ");
  Serial.println(counter);


  buttonState2 = digitalRead(buttonPin2);
  if(buttonState2 == HIGH && lastButtonState2 == LOW){
    print_wakeup_reason();
    pairing();
  }


  buttonState = digitalRead(buttonPin);
  buttonState2 = digitalRead(buttonPin2);
  if(buttonState == HIGH && buttonState2 == LOW){
    Serial.println("Going to Sleep");
    esp_deep_sleep_start();
  }


}


void loop() {


  // read the state of the BLE pushbutton
  buttonState2 = digitalRead(buttonPin2);
  if (lastButtonState2 == HIGH && buttonState2 == LOW) {
    print_wakeup_reason();
    Serial.println("The button is pressed");
    pairing();
  }
  lastButtonState2 = buttonState2;
 
  // read the state of the internal pushbutton:
  buttonState = digitalRead(buttonPin);


  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (lastButtonState == HIGH && buttonState == LOW) {
      print_wakeup_reason();
      //counter++;
      Serial.print("Number of button pushes:  ");
      Serial.println(counter);
      // if the current state is HIGH then the button went from off to on:
      ledState = !ledState;
    }
    if(counter == 2){
      buttonState = lastButtonState;
    }
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  // sets the LED to the button's state
  if(counter == 1){
    digitalWrite(ledPin, HIGH);
    digitalWrite(ledPin2, LOW);
   
    if(pCharacteristic != NULL){
      pCharacteristic->setValue("device_state_3_locked"); //add code for device state 1 ready once buttonPin1 is pushed/released
      pCharacteristic->notify();
    }
  }


  if(counter == 3){
    digitalWrite(ledPin2, HIGH);
    digitalWrite(ledPin, LOW);
   
    if(pCharacteristic != NULL){
      pCharacteristic->setValue("device_state_3_locked"); //add code for device state 3 used once buttonPin1 is pushed/released
      pCharacteristic->notify();
    }
  }


  if(counter >= 4){
    digitalWrite(ledPin, LOW);
    digitalWrite(ledPin2, LOW);
  }


  delay(50);


}

Solution

  • Silly suggestion but one possible reason that comes to mind based on your description is that you may be inadvertently firing a pin that is actually a reset pin on the ESP.

    If you look at your board's pin diagram it will show you which pin is labeled "RST", depending on your wiring if you send power to that pin it will reset the chip.

    The problems is that some boards will have just numbers printed 1,2,3... but only if you look at the actual pinout diagram it tells you which pin does what.

    I do that all the time but on-purpose though, if I can't have a physical on-off switch but rather use a push button I put the ESP to sleep and when the device needs to be used the user presses a push button that sends an impulse to the RST which effectively restarts he unit as if it was freshly plugged into power.

    As some people have commented, you have posted a bit toooo much code, best thing is to isolate the problem, ditch everything in the code except the sleep/wake-up part and test it either until that part of the mechanism works or if it doesn't post just that code. Better chance of getting quality help if it's down to the point (otherwise you will just get grumpy comments :-)