How to use GPIOs in stub function [Example blink led]

GoncaloGarcia
Posts: 1
Joined: Fri Feb 24, 2023 9:59 pm

How to use GPIOs in stub function [Example blink led]

Postby GoncaloGarcia » 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 :D

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

  1. void RTC_IRAM_ATTR blink_led (void)
  2. {
  3.     // See this example if needed to add more GPIOs as inputs or outputs : https://esp32.com/viewtopic.php?t=1674    
  4.     // GPIO14 - RTC_GPIO6 GREEN
  5.     // GPIO27 - RTC_GPIO7 RED    
  6.    
  7.     // 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
  8.     CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M);
  9.     CLEAR_PERI_REG_MASK(RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M);
  10.  
  11.     // Enable GPIO function in IO_MUX
  12.     PIN_FUNC_SELECT(GPIO_PIN_REG_14, PIN_FUNC_GPIO);
  13.     PIN_FUNC_SELECT(GPIO_PIN_REG_27, PIN_FUNC_GPIO);
  14.      
  15.     // Set as Output pins GPIO14 and GPIO27
  16.     REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT14);
  17.     REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT27);
  18.        
  19.     REG_WRITE(GPIO_OUT_W1TC_REG, BIT14); // Set GPIO14 HIGH
  20.     REG_WRITE(GPIO_OUT_W1TS_REG, BIT27); // Set GPIO27 LOW
  21.  
  22.     // Delay 0.5ms to blink led
  23.     ets_delay_us(500);
  24.  
  25.     REG_WRITE(GPIO_OUT_W1TS_REG, BIT27); // Set GPIO27 LOW
  26. }
  27.  
  28. void RTC_IRAM_ATTR deepsleep_for_us(uint64_t duration_us)
  29. {        
  30.     // Calculate sleep duration in microseconds
  31.     int64_t sleep_duration = (int64_t)duration_us - (int64_t)DEEP_SLEEP_TIME_OVERHEAD_US;
  32.    
  33.     if (sleep_duration < 0) sleep_duration = 0;    
  34.    
  35.     // Get RTC calibration
  36.     uint32_t period = REG_READ(RTC_SLOW_CLK_CAL_REG);
  37.  
  38.     // Convert microseconds to RTC clock cycles
  39.     int64_t rtc_count_delta = (sleep_duration << RTC_CLK_CAL_FRACT) / period;    
  40.    
  41.     // Get current RTC time
  42.     SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE);    
  43.     while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { ets_delay_us(1); }
  44.     SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR);
  45.    
  46.     uint64_t now  = READ_PERI_REG(RTC_CNTL_TIME0_REG) | ((uint64_t)READ_PERI_REG(RTC_CNTL_TIME1_REG) << 32);
  47.    
  48.     // Set wakeup time
  49.     uint64_t future = now + rtc_count_delta;
  50.     WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, future & UINT32_MAX);
  51.     WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, future >> 32);
  52.    
  53.     WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, 0);                                  // Clear sleep rejection cause
  54. }
  55.  
  56. static char RTC_RODATA_ATTR strSleep[] = "Wake Up %lu\n\r";
  57. static char RTC_RODATA_ATTR strGPIO[]  = "EXT1 TRIGGED %lu\n\r";
  58.  
  59. void RTC_IRAM_ATTR wake_stub()
  60. {
  61.     // Get wake up source, similar to esp_sleep_get_wakeup_cause, but the wake index are different, check manual Table 31-2. Wakeup Source
  62.     uint32_t wakeUpSource = GET_PERI_REG_MASK(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);
  63.  
  64.    // if wake up source is from the ext pins wake up device
  65.     if (wakeUpSource == RTC_EXT1_TRIG_EN)
  66.     {
  67.         ets_printf(strGPIO, wakeUpSource);    
  68.         while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {}
  69.  
  70.         esp_default_wake_deep_sleep();
  71.     }
  72.     // Otherwise, blink led and go to sleep again
  73.     else
  74.     {        
  75.         blink_led();
  76.        
  77.         // Set wake uop timer again with time in us (5000000us = 5s)
  78.         deepsleep_for_us(5000000);
  79.  
  80.         // Set EXT1 Trigger
  81.         // GPIO4  - RTC_GPIO10
  82.         // GPIO36 - RTC_GPIO0
  83.  
  84.         WRITE_PERI_REG(RTC_CNTL_EXT_WAKEUP1_REG     , (BIT0 | BIT10)         ); // Wake up on pins
  85.         WRITE_PERI_REG(RTC_CNTL_EXT_WAKEUP_CONF_REG , RTC_CNTL_EXT_WAKEUP1_LV); // Wake up on pins
  86.        
  87.         //  Wake up on timer and GPIO pins
  88.         REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, (RTC_TIMER_TRIG_EN | RTC_EXT1_TRIG_EN));
  89.  
  90.     // Print some debug data, just to check
  91.         ets_printf(strSleep, wakeUpSource);        
  92.         while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {}
  93.  
  94.         // Set the pointer of the wake stub function.
  95.         REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);
  96.  
  97.         // Go to sleep again
  98.         CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
  99.         SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
  100.     }
  101. }
  102.  
  103. void setup()
  104. {
  105.     // Set wake stub function
  106.     esp_set_deep_sleep_wake_stub(&wake_stub);
  107.  
  108.     //  Wake up on timer and GPIO pins
  109.     esp_sleep_enable_timer_wakeup(5000000);
  110.     esp_sleep_enable_ext1_wakeup(WAKE_SOURCES, ESP_EXT1_WAKEUP_ANY_HIGH);
  111.    
  112.     // Go to deepsleep
  113.     esp_deep_sleep_start();    
  114. }
Last edited by GoncaloGarcia on Tue Jun 27, 2023 3:31 pm, edited 1 time in total.

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

Re: How to use GPIOs in stub function [Example blink led]

Postby MicroController » Sat Feb 25, 2023 11:15 pm

This may be a better fit for the "Sample Code" sub-forum (viewforum.php?f=18) :)

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

Re: How to use GPIOs in stub function [Example blink led]

Postby ESP_Sprite » Sun Feb 26, 2023 5:41 am

Agree, I'll move it to there.

Who is online

Users browsing this forum: No registered users and 14 guests