How to use GPIOs in stub function [Example blink led]
Posted: Fri Feb 24, 2023 10:32 pm
Hi all, I'm doing this topic to help and make easier to find the awnser that I wanted when I had to do this and couldn't find it, and had to dig around for awnsers, so here it is
I wanted to blink a led every 5 secs in deepsleep, and to do that I had to wake up the device every 5 secs, since waking up the device takes an average of 200ms I tried to use the stub function. To do this, and check if the wake up procedure was triggered by the EXT1 since I have 3 pins that I want to use for this. Below is the code that I used, since it was not easy to find this information I want to give an example for future developers in order to have a easier starting point.
The board that I am using is the ESP32-WROOM-32E, and I used platformIO to compile this code
Other important links that helped me a lot are:
- One of the last awnsers give me the foundation to understand how to control the two GPIOs that I needed it, in order to blink the LED, https://esp32.com/viewtopic.php?t=1674.
- The technical manual is a must, there you will find what registers you need to change in order to get what you want, its not easy, but if you cross check it with my code you will understand what I'm doing, https://www.espressif.com/sites/default ... section.30.
- The code of this dude was what I used to set the wake up timer, you can find in one of is awnsers the code for the "deepsleep_for_us" function, viewtopic.php?f=19&t=15216 and a lot of good info on the github topic that he created and got help with this function, https://gist.github.com/igrr/54f7fbe051 ... d7fbecfeab
I wanted to blink a led every 5 secs in deepsleep, and to do that I had to wake up the device every 5 secs, since waking up the device takes an average of 200ms I tried to use the stub function. To do this, and check if the wake up procedure was triggered by the EXT1 since I have 3 pins that I want to use for this. Below is the code that I used, since it was not easy to find this information I want to give an example for future developers in order to have a easier starting point.
The board that I am using is the ESP32-WROOM-32E, and I used platformIO to compile this code
Other important links that helped me a lot are:
- One of the last awnsers give me the foundation to understand how to control the two GPIOs that I needed it, in order to blink the LED, https://esp32.com/viewtopic.php?t=1674.
- The technical manual is a must, there you will find what registers you need to change in order to get what you want, its not easy, but if you cross check it with my code you will understand what I'm doing, https://www.espressif.com/sites/default ... section.30.
- The code of this dude was what I used to set the wake up timer, you can find in one of is awnsers the code for the "deepsleep_for_us" function, viewtopic.php?f=19&t=15216 and a lot of good info on the github topic that he created and got help with this function, https://gist.github.com/igrr/54f7fbe051 ... d7fbecfeab
- void RTC_IRAM_ATTR blink_led (void)
- {
- // See this example if needed to add more GPIOs as inputs or outputs : https://esp32.com/viewtopic.php?t=1674
- // GPIO14 - RTC_GPIO6 GREEN
- // GPIO27 - RTC_GPIO7 RED
- // Enable GPIO function in RTC, after reset this is disabled, for what I understad, this must be done to the pins that could be used as touch pads
- CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M);
- CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M);
- // Enable GPIO function in IO_MUX
- PIN_FUNC_SELECT(GPIO_PIN_REG_14, PIN_FUNC_GPIO);
- PIN_FUNC_SELECT(GPIO_PIN_REG_27, PIN_FUNC_GPIO);
- // Set as Output pins GPIO14 and GPIO27
- REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT14);
- REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT27);
- REG_WRITE(GPIO_OUT_W1TC_REG, BIT14); // Set GPIO14 HIGH
- REG_WRITE(GPIO_OUT_W1TS_REG, BIT27); // Set GPIO27 LOW
- // Delay 0.5ms to blink led
- ets_delay_us(500);
- REG_WRITE(GPIO_OUT_W1TS_REG, BIT27); // Set GPIO27 LOW
- }
- void RTC_IRAM_ATTR deepsleep_for_us(uint64_t duration_us)
- {
- // Calculate sleep duration in microseconds
- int64_t sleep_duration = (int64_t)duration_us - (int64_t)DEEP_SLEEP_TIME_OVERHEAD_US;
- if (sleep_duration < 0) sleep_duration = 0;
- // Get RTC calibration
- uint32_t period = REG_READ(RTC_SLOW_CLK_CAL_REG);
- // Convert microseconds to RTC clock cycles
- int64_t rtc_count_delta = (sleep_duration << RTC_CLK_CAL_FRACT) / period;
- // Get current RTC time
- SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE);
- while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { ets_delay_us(1); }
- SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR);
- uint64_t now = READ_PERI_REG(RTC_CNTL_TIME0_REG) | ((uint64_t)READ_PERI_REG(RTC_CNTL_TIME1_REG) << 32);
- // Set wakeup time
- uint64_t future = now + rtc_count_delta;
- WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, future & UINT32_MAX);
- WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, future >> 32);
- WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, 0); // Clear sleep rejection cause
- }
- static char RTC_RODATA_ATTR strSleep[] = "Wake Up %lu\n\r";
- static char RTC_RODATA_ATTR strGPIO[] = "EXT1 TRIGGED %lu\n\r";
- void RTC_IRAM_ATTR wake_stub()
- {
- // Get wake up source, similar to esp_sleep_get_wakeup_cause, but the wake index are different, check manual Table 31-2. Wakeup Source
- uint32_t wakeUpSource = GET_PERI_REG_MASK(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);
- // if wake up source is from the ext pins wake up device
- if (wakeUpSource == RTC_EXT1_TRIG_EN)
- {
- ets_printf(strGPIO, wakeUpSource);
- while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {}
- esp_default_wake_deep_sleep();
- }
- // Otherwise, blink led and go to sleep again
- else
- {
- blink_led();
- // Set wake uop timer again with time in us (5000000us = 5s)
- deepsleep_for_us(5000000);
- // Set EXT1 Trigger
- // GPIO4 - RTC_GPIO10
- // GPIO36 - RTC_GPIO0
- WRITE_PERI_REG(RTC_CNTL_EXT_WAKEUP1_REG , (BIT0 | BIT10) ); // Wake up on pins
- WRITE_PERI_REG(RTC_CNTL_EXT_WAKEUP_CONF_REG , RTC_CNTL_EXT_WAKEUP1_LV); // Wake up on pins
- // Wake up on timer and GPIO pins
- REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, (RTC_TIMER_TRIG_EN | RTC_EXT1_TRIG_EN));
- // Print some debug data, just to check
- ets_printf(strSleep, wakeUpSource);
- while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {}
- // Set the pointer of the wake stub function.
- REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);
- // Go to sleep again
- CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
- SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
- }
- }
- void setup()
- {
- // Set wake stub function
- esp_set_deep_sleep_wake_stub(&wake_stub);
- // Wake up on timer and GPIO pins
- esp_sleep_enable_timer_wakeup(5000000);
- esp_sleep_enable_ext1_wakeup(WAKE_SOURCES, ESP_EXT1_WAKEUP_ANY_HIGH);
- // Go to deepsleep
- esp_deep_sleep_start();
- }