Hi All,
I’ve been pounding my head on a wall for a while with this one.
I have a simple loop that sets up to use a timer and a gpio to wake up from light sleep.
Whenever the gpio causes the wake, I swap the sense of the DIO that will cause the next wake, then put the loop back to sleep with the remaining time until the next timer wake up.
Everything works great – most of the time.
Every once in a while, the timer wakes up after 15 msec install of 2000 msec. My code is not currently checking for this error I increment the the next wake time and put it back to sleep (now for 4 sec. it again wakes up in around 15 msec. this repeats until the sleep time is 15 to 60 seconds in the future and then it actually sleeps for that long and everything is back to normal.
My best guess is that there is a GPIO wake up event at the same time as the timer wake up.
The cause sent back is timer-wakeup. And there are no gpio wake ups during the time the the rapid wake up is occurring.
So the question is, is this a bug in the library or am I doing something wrong?
I’m developing with Eclipse 2022-03 and ESP-IDF v4.4.1 using the ESP32-c3-DevKitC-02, which has the esp32-c3-wroom-02.
I’m using the on board LED to reflect the state of the button, which does not get out of sync.
There are a lot of prints, but the error occurs with them commented out.
I’m catching the case where the time to sleep is less than zero. It occurs very rarely and does not cause the problem.
#include <stdio.h>
#include “freertos/FreeRTOS.h”
#include “freertos/task.h”
#include “esp_sleep.h”
#include “driver/uart.h”
#include “driver/gpio.h”
#include “esp_timer.h”
#include “led_strip.h”
#define BUTTON_GPIO_NUM_DEFAULT 4
/* “Boot” button is active low */
#define BUTTON_WAKEUP_LEVEL_DEFAULT 0
#define TICK_TIME 2000000
static uint64_t next_tick = TICK_TIME;
static uint64_t last_time_timestamp = 0;
#define BLINK_GPIO 8
#define NUM_LEDS 1
static led_strip_t *pStrip_a;
static void configure_led(void)
{
pStrip_a = led_strip_init(0, BLINK_GPIO, NUM_LEDS);
pStrip_a->clear(pStrip_a, NUM_LEDS);
}
void printfcomma (uint64_t n) {
if (n < 1000) {
printf (“%llu”, n);
return;
}
printfcomma (n/1000);
printf (“,%03llu”, n%1000);
}
static void set_led(bool state)
{
if (state)
pStrip_a->set_pixel(pStrip_a, 0, 16, 0, 0);
else
pStrip_a->set_pixel(pStrip_a, 0, 0, 16, 0);
pStrip_a->refresh(pStrip_a, NUM_LEDS);
}
void app_main(void)
{
uint64_t t_after_us = 0;
bool gpio04_low = false;
printf(“Started Program!!\n”);
configure_led();
/* Configure the button GPIO as input, enable wakeup */
const uint8_t button_gpio_num = BUTTON_GPIO_NUM_DEFAULT;
gpio_config_t config = {
.pin_bit_mask = BIT64(button_gpio_num),
.mode = GPIO_MODE_INPUT,
.pull_up_en = true
};
ESP_ERROR_CHECK(gpio_config(&config));
while (true) {
/* Wake up in 2 seconds, or when button is pressed */
gpio_wakeup_enable(button_gpio_num,
gpio04_low ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL);
esp_sleep_enable_gpio_wakeup();
uint64_t sleep_time;
if (next_tick < t_after_us)
{
sleep_time = 0;
printf(“Time to sleep is less than zero\n”);
}
else
sleep_time = next_tick – t_after_us;
printf(“Entering light sleep. Last Tick:”);
printfcomma(t_after_us);
printf(” Next Tick:”);
printfcomma(next_tick);
printf(” Sleep time:”);
printfcomma(sleep_time);
printf(“\n”);
/* To make sure the complete line is printed before entering sleep mode,
* need to wait until UART TX FIFO is empty:
*/
uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
if(sleep_time > 2000000)
{
printf(“Time is greater the 2 seconds\n”);
uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
}
/* Enter sleep mode */
esp_sleep_enable_timer_wakeup(sleep_time);
esp_light_sleep_start();
/* Execution continues here after wakeup */
/* Get timestamp after waking up from sleep */
t_after_us = esp_timer_get_time();
/* Determine wake up reason */
switch (esp_sleep_get_wakeup_cause())
{
case ESP_SLEEP_WAKEUP_TIMER:
next_tick += TICK_TIME;
printf(“Returned from light sleep, reason: timer, t=%lld ms, slept for %lld ms\n”,
t_after_us / 1000, (t_after_us – last_time_timestamp) / 1000);
last_time_timestamp = t_after_us;
break;
case ESP_SLEEP_WAKEUP_GPIO:
printf(“Returned from light sleep, reason: pin, t=%lld ms, slept for %lld ms\n”,
t_after_us / 1000, (t_after_us – last_time_timestamp) / 1000);
set_led(gpio04_low);
gpio04_low = !gpio04_low;
break;
default:
printf(“something else woke us up. ——————————–\n”); // this is never hit
break;
}
}
}
———- Here is what it looks like when it is good ———-
Returned from light sleep, reason: timer, t=8013 ms, slept for 1999 ms
Entering light sleep. Last Tick:8,013,709 Next Tick:10,000,000 Sleep time:1,986,291
Returned from light sleep, reason: timer, t=10013 ms, slept for 2000 ms
Entering light sleep. Last Tick:10,013,798 Next Tick:12,000,000 Sleep time:1,986,202
Returned from light sleep, reason: pin, t=10913 ms, slept for 900 ms
Entering light sleep. Last Tick:10,913,841 Next Tick:12,000,000 Sleep time:1,086,159
Returned from light sleep, reason: pin, t=11005 ms, slept for 991 ms
Entering light sleep. Last Tick:11,005,474 Next Tick:12,000,000 Sleep time:994,526
Returned from light sleep, reason: pin, t=11143 ms, slept for 1129 ms
Entering light sleep. Last Tick:11,143,638 Next Tick:12,000,000 Sleep time:856,362
Returned from light sleep, reason: pin, t=11207 ms, slept for 1193 ms
Entering light sleep. Last Tick:11,207,586 Next Tick:12,000,000 Sleep time:792,414
Returned from light sleep, reason: pin, t=11294 ms, slept for 1281 ms
Entering light sleep. Last Tick:11,294,959 Next Tick:12,000,000 Sleep time:705,041
Returned from light sleep, reason: pin, t=11382 ms, slept for 1368 ms
Entering light sleep. Last Tick:11,382,712 Next Tick:12,000,000 Sleep time:617,288
Returned from light sleep, reason: pin, t=11479 ms, slept for 1465 ms
Entering light sleep. Last Tick:11,479,663 Next Tick:12,000,000 Sleep time:520,337
Returned from light sleep, reason: pin, t=11554 ms, slept for 1540 ms
Entering light sleep. Last Tick:11,554,762 Next Tick:12,000,000 Sleep time:445,238
Returned from light sleep, reason: timer, t=12013 ms, slept for 2000 ms
Entering light sleep. Last Tick:12,013,808 Next Tick:14,000,000 Sleep time:1,986,192
Returned from light sleep, reason: timer, t=14013 ms, slept for 2000 ms
Entering light sleep. Last Tick:14,013,969 Next Tick:16,000,000 Sleep time:1,986,031
——– Here is a failure ———–
Returned from light sleep, reason: pin, t=41818 ms, slept for 1804 ms
Entering light sleep. Last Tick:41,818,763 Next Tick:42,000,000 Sleep time:181,237
Returned from light sleep, reason: pin, t=41917 ms, slept for 1903 ms
Entering light sleep. Last Tick:41,917,707 Next Tick:42,000,000 Sleep time:82,293
Returned from light sleep, reason: timer, t=42013 ms, slept for 1999 ms
Entering light sleep. Last Tick:42,013,715 Next Tick:44,000,000 Sleep time:1,986,285 (good)
Returned from light sleep, reason: timer, t=42028 ms, slept for 15 ms (bad)
Entering light sleep. Last Tick:42,028,821 Next Tick:46,000,000 Sleep time:3,971,179
Time is greater the 2 seconds
Returned from light sleep, reason: timer, t=42046 ms, slept for 17 ms
Entering light sleep. Last Tick:42,046,435 Next Tick:48,000,000 Sleep time:5,953,565
Time is greater the 2 seconds
Returned from light sleep, reason: timer, t=42064 ms, slept for 17 ms
Entering light sleep. Last Tick:42,064,066 Next Tick:50,000,000 Sleep time:7,935,934
Time is greater the 2 seconds
Returned from light sleep, reason: timer, t=42081 ms, slept for 17 ms
Entering light sleep. Last Tick:42,081,691 Next Tick:52,000,000 Sleep time:9,918,309
Time is greater the 2 seconds
Returned from light sleep, reason: timer, t=42099 ms, slept for 17 ms
Entering light sleep. Last Tick:42,099,315 Next Tick:54,000,000 Sleep time:11,900,685
Time is greater the 2 seconds
Returned from light sleep, reason: pin, t=42223 ms, slept for 124 ms
Entering light sleep. Last Tick:42,223,720 Next Tick:54,000,000 Sleep time:11,776,280
Time is greater the 2 seconds
Returned from light sleep, reason: pin, t=42308 ms, slept for 209 ms
Entering light sleep. Last Tick:42,308,473 Next Tick:54,000,000 Sleep time:11,691,527
Time is greater the 2 seconds
So…
I was over designing the loop (or at least over designing it in the wrong way). In my code I was setting up the time until wake each time I put the processor to sleep. That was not needed and in fact was wrong. As long as the original time has not passed yet, the wake up time is still valid. so…
When it wakes up because of a GPIO toggle, when I put it back to sleep I don’t need to give it a new duration.
My concern is, what happens if I verify that it has not passed yet, but by the time I call sleep it has? Will it immediately wake up or will it not wake up until the GPIO event?
A main loop like this seems to work well. I’ll continue to check the edge condition and post what I find.
void app_main(void)
{
bool gpio04_low = false;
bool awake = false;
uint8_t rotation_index = 0;
init_GPIO();
configure_led();
ticks = esp_timer_get_time();
seconds = -1;
while (true)
{
while(awake)
{
}
// get ready to sleep
gpio_wakeup_enable(BUTTON_GPIO_NUM_DEFAULT, gpio04_low ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL);
esp_sleep_enable_gpio_wakeup();
uint64_t next_tick = subtract(ticks + TICK_INTERVAL, esp_timer_get_time());
esp_sleep_enable_timer_wakeup(next_tick);
while(!awake)
{
uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
esp_light_sleep_start();
if(esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO)
{
acc_count++;
gpio04_low = !gpio04_low;
//printf(“GPIO:%u\n”, gpio04_low);
set_led(gpio04_low);
gpio_wakeup_enable(BUTTON_GPIO_NUM_DEFAULT, gpio04_low ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL);
esp_sleep_enable_gpio_wakeup();
}
// catch the fact a tick occurred in either the wake-up or interrupt
if(esp_timer_get_time() > ticks)
{
ticks += TICK_INTERVAL;
rotations[rotation_index++]= acc_count;
acc_count = 0;
if (rotation_index >= NUM_ROTATIONS)
{
for (int i = 0; i<NUM_ROTATIONS; i++)
printf(“%u\n”, rotations[i]);
rotation_index = 0;
set_led_report();
seconds = -1;
}
set_led_seconds();
uint64_t next_tick = subtract(ticks + TICK_INTERVAL, esp_timer_get_time());
esp_sleep_enable_timer_wakeup(next_tick);
}
}
}