Power Management: problems when combining GPIO wakeup with GPIO interrupt in light sleep mode

FrancoB
Posts: 5
Joined: Thu Mar 14, 2024 5:58 pm

Power Management: problems when combining GPIO wakeup with GPIO interrupt in light sleep mode

Postby FrancoB » Thu Mar 21, 2024 3:39 pm

Greetings.

I'm trying to combine the use of a GPIO interrupt with the use of the Power Management mode that ESP-IDF provides. So, what I did was to enable the PM via the menuconfig, configure and enable the light sleep mode with the "esp_pm_configure()" function, configure a GPIO interrupt of "GPIO_INTR_LOW_LEVEL" type (in this case, in GPIO 18), and enable a GPIO wakeup with "gpio_wakeup_enable()".

In addition, when configuring the GPIO interrupt, I also set an IRQ handler function. In that handler, I check the state of the mentioned GPIO, and if it's LOW, I change both the interrupt and wakeup type to "GPIO_INTR_HIGH_LEVEL". Additionally, when the state of the GPIO is LOW, I send a Task Notify to a task which, for the moment, just prints a message to the console.

If I do all of the above mentioned, and if the state of the GPIO 18 pin is the same as the level configured in the interrupt and wakeup type (LOW level in this case) at the time that the program starts, it crashes.

I set the following "menuconfig" options, regarding the Power Management functionality:

-FreeRTOS:
+Tickless Idle Support

-PM:
+Support for power management
+Enable dynamic frequency scaling (DFS) at startup


The code is the following:

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include "esp_log.h"
#include "esp_pm.h"
#include "esp_sleep.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "driver/gpio.h"
#include "driver/uart.h"


#define GPIO_TO_ISR 18


static TaskHandle_t xTestTask1Handle = NULL;
static TaskHandle_t xTestTaskGpioIsrHandle = NULL;

const char *TAG = "MAIN";



void isr_handler(void *args);
esp_err_t init_gpio(void);
void vTestTaskGpioIsr(void *pvParameters);
void vTestTask1(void *pvParameters);



void isr_handler(void *args)
{
    BaseType_t xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;

    if(gpio_get_level(GPIO_TO_ISR))
    {
        gpio_wakeup_enable(GPIO_TO_ISR, GPIO_INTR_LOW_LEVEL);
        gpio_set_intr_type(GPIO_TO_ISR, GPIO_INTR_LOW_LEVEL);
    }

    else if(!gpio_get_level(GPIO_TO_ISR))
    {
        gpio_wakeup_enable(GPIO_TO_ISR, GPIO_INTR_HIGH_LEVEL);
        gpio_set_intr_type(GPIO_TO_ISR, GPIO_INTR_HIGH_LEVEL);
        vTaskNotifyGiveFromISR(xTestTaskGpioIsrHandle, &xHigherPriorityTaskWoken);
    }

    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}



esp_err_t init_gpio(void)
{
    gpio_config_t pGPIOConfig;

    pGPIOConfig.pin_bit_mask = (1ULL << GPIO_TO_ISR);
    pGPIOConfig.mode = GPIO_MODE_DEF_INPUT;
    pGPIOConfig.pull_up_en = GPIO_PULLUP_DISABLE;
    pGPIOConfig.pull_down_en = GPIO_PULLDOWN_DISABLE;
    pGPIOConfig.intr_type = GPIO_INTR_LOW_LEVEL;
    
    gpio_config(&pGPIOConfig);

     gpio_install_isr_service(0);

    gpio_isr_handler_add(GPIO_TO_ISR, isr_handler, NULL);

    ESP_LOGI(TAG,"Interrupt configured correctly.");

    return ESP_OK;
}



void vTestTaskGpioIsr(void *pvParameters)
{
    while(1)
    {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        ESP_LOGW(TAG, "DESPERTADO POR GPIO");

        fsync(fileno(stdout));
    }
}



void vTestTask1(void *pvParameters)
{
    while(1)
    {
        ESP_LOGI(TAG, "TASK 1 BLOCKS");

        fsync(fileno(stdout));

        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}


void app_main(void)
{
    esp_pm_config_esp32_t pm_config = {
        .max_freq_mhz = 160,
        .min_freq_mhz = 80,
        .light_sleep_enable = true,
    };

    if(xTestTask1Handle == NULL)
    {
        xTaskCreate(
            vTestTask1,
            "vTestTask1",
            2048,
            NULL,
            2,
            &xTestTask1Handle);
        
       if(xTestTask1Handle == NULL)
        {
            ESP_LOGE(TAG, "Error when creating vTestTask1 task.");
        }
    }

    if(xTestTaskGpioIsrHandle == NULL)
    {
        xTaskCreate(
            vTestTaskGpioIsr,
            "vTestTaskGpioIsr",
            2048,
            NULL,
            2,
            &xTestTaskGpioIsrHandle);
        
       if(xTestTaskGpioIsrHandle == NULL)
        {
            ESP_LOGE(TAG, "Error when creating vTestTaskGpioIsr task.");
        }
    }

    esp_sleep_enable_gpio_wakeup();
    gpio_wakeup_enable(GPIO_TO_ISR, GPIO_INTR_LOW_LEVEL);
    init_gpio();

    if(esp_pm_configure(&pm_config) != ESP_OK)
    {
        ESP_LOGE(TAG, "ERROR WHEN CONFIGURING PM");
    }

    while(1)
    {
        ESP_LOGI(TAG, "MAIN TASK BLOCKS");

        fsync(fileno(stdout));

        vTaskDelay(pdMS_TO_TICKS(20000));
        
        const char* wakeup_reason;
        switch (esp_sleep_get_wakeup_cause()) {
            case ESP_SLEEP_WAKEUP_TIMER:
                wakeup_reason = "timer";
                break;
            case ESP_SLEEP_WAKEUP_GPIO:
                wakeup_reason = "pin";
                break;
            case ESP_SLEEP_WAKEUP_UART:
                wakeup_reason = "uart";
                break;
            default:
                wakeup_reason = "other";
                break;
        }

        ESP_LOGW(TAG, "WAKEUP REASON: %s", wakeup_reason);
    }

}




And the debug logs are the following:

entry 0x4008069c
I (29) boot: ESP-IDF v4.4.6-dirty 2nd stage bootloader
I (29) boot: compile time 11:41:47
I (29) boot: Multicore bootloader
I (33) boot: chip revision: v1.0
I (36) boot.esp32: SPI Speed : 40MHz
I (41) boot.esp32: SPI Mode : DIO
I (46) boot.esp32: SPI Flash Size : 4MB
I (50) boot: Enabling RNG early entropy source...
I (56) boot: Partition Table:
I (59) boot: ## Label Usage Type ST Offset Length
I (66) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (74) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 2 factory factory app 00 00 00010000 00100000
I (89) boot: End of partition table
I (93) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=0a118h ( 41240) map
I (117) esp_image: segment 1: paddr=0001a140 vaddr=3ff80000 size=00004h ( 4) load
I (117) esp_image: segment 2: paddr=0001a14c vaddr=3ffb0000 size=01e94h ( 7828) load
I (125) esp_image: segment 3: paddr=0001bfe8 vaddr=40080000 size=04030h ( 16432) load
I (138) esp_image: segment 4: paddr=00020020 vaddr=400d0020 size=18090h ( 98448) map
I (175) esp_image: segment 5: paddr=000380b8 vaddr=40084030 size=0b05ch ( 45148) load
I (201) boot: Loaded app from partition at offset 0x10000
I (201) boot: Disabling RNG early entropy source...
I (212) cpu_start: Multicore app
I (213) cpu_start: Pro cpu up.
I (213) cpu_start: Starting app cpu, entry point is 0x40081198
0x40081198: call_start_cpu1 at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_system/port/cpu_start.c:151

I (201) cpu_start: App cpu up.
I (231) cpu_start: Pro cpu start user code
I (231) cpu_start: cpu freq: 160000000
I (231) cpu_start: Application information:
I (235) cpu_start: Project name: ESP32_PRUEBA_POWER_MANAGEMENT
I (242) cpu_start: App version: 1
I (247) cpu_start: Compile time: Mar 21 2024 09:25:10
I (253) cpu_start: ELF file SHA256: 6a29fef5692d4171...
I (259) cpu_start: ESP-IDF: v4.4.6-dirty
I (264) cpu_start: Min chip rev: v0.0
I (269) cpu_start: Max chip rev: v3.99
I (274) cpu_start: Chip rev: v1.0
I (279) heap_init: Initializing. RAM available for dynamic allocation:
I (286) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (292) heap_init: At 3FFB2A90 len 0002D570 (181 KiB): DRAM
I (298) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (304) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (311) heap_init: At 4008F08C len 00010F74 (67 KiB): IRAM
I (318) spi_flash: detected chip: generic
I (322) spi_flash: flash io: dio
I (337) pm: Frequency switching config: CPU_MAX: 160, APB_MAX: 80, APB_MIN: 40, Light sleep: DISABLED
I (338) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (0) MAIN: MAIN TASK BLOCKS
I (349) gpio: GPIO[18]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:4
Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0).

Core 0 register dump:
PC : 0x40082e11 PS : 0x00050034 A0 : 0x4000bff0 A1 : 0x3ffb0bb0
0x40082e11: _xt_lowint1 at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/xtensa_vectors.S:1114

A2 : 0x00000000 A3 : 0x0000000d A4 : 0x00000012 A5 : 0x3ffb0b90
A6 : 0x00000000 A7 : 0x00050021 A8 : 0x3ffb612c A9 : 0x40088de6
0x40088de6: _frxt_int_enter at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/portasm.S:119

A10 : 0x00000000 A11 : 0x3ffb6150 A12 : 0x0000cdcd A13 : 0x3ffb0b80
A14 : 0x00000003 A15 : 0x00060023 SAR : 0x0000000e EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000
Core 0 was running in ISR context:
EPC1 : 0x400d2093 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40082e11
0x400d2093: uart_hal_write_txfifo at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/hal/uart_hal_iram.c:35

0x40082e11: _xt_lowint1 at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/xtensa_vectors.S:1114



Backtrace: 0x40082e0e:0x3ffb0bb0 0x4000bfed:0x3ffaf5b0 0x4008bba6:0x3ffaf5c0 0x400d47a7:0x3ffaf5e0 0x400d4805:0x3ffaf620 0x400d5ea1:0x3ffaf650 0x40083365:0x3ffaf670 0x4008b8f5:0x3ffaf690
0x40082e0e: _xt_lowint1 at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/xtensa_vectors.S:1114

0x4008bba6: vPortClearInterruptMaskFromISR at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/include/freertos/portmacro.h:571
(inlined by) vPortExitCritical at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/port.c:332

0x400d47a7: esp_intr_alloc_intrstatus at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_hw_support/intr_alloc.c:584

0x400d4805: esp_intr_alloc at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_hw_support/intr_alloc.c:604

0x400d5ea1: gpio_isr_register_on_core_static at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/driver/gpio.c:519

0x40083365: ipc_task at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_ipc/src/esp_ipc.c:77

0x4008b8f5: vPortTaskWrapper at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/port.c:142



Core 1 register dump:
PC : 0x400d7e36 PS : 0x00060234 A0 : 0x800d1c4f A1 : 0x3ffb5ee0
0x400d7e36: esp_pm_impl_waiti at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_pm/pm_impl.c:843

A2 : 0x00000001 A3 : 0x00000001 A4 : 0x00060220 A5 : 0x00000004
A6 : 0x00000003 A7 : 0x00060423 A8 : 0x00000001 A9 : 0x3ffb5ed0
A10 : 0x00000003 A11 : 0x00060223 A12 : 0x00060220 A13 : 0x00060223
A14 : 0x00000000 A15 : 0x3ffe7cc4 SAR : 0x0000001d EXCCAUSE: 0x00000005
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000


Backtrace: 0x400d7e33:0x3ffb5ee0 0x400d1c4c:0x3ffb5f00 0x4008a1d2:0x3ffb5f20 0x4008b8f5:0x3ffb5f40
0x400d7e33: cpu_ll_waiti at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/hal/esp32/include/hal/cpu_ll.h:183
(inlined by) esp_pm_impl_waiti at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_pm/pm_impl.c:838

0x400d1c4c: esp_vApplicationIdleHook at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/esp_system/freertos_hooks.c:63

0x4008a1d2: prvIdleTask at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/tasks.c:3987

0x4008b8f5: vPortTaskWrapper at C:/Espressif/esp-idf/v4.4.6/esp-idf/components/freertos/port/xtensa/port.c:142



Any idea what could be wrong?

Thank you all in advance.

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

Re: Power Management: problems when combining GPIO wakeup with GPIO interrupt in light sleep mode

Postby ESP_Sprite » Fri Mar 22, 2024 2:12 am

Looks like the GPIO ISR keeps triggering for some reason, causing an interrupt timeout... Just to check: if you disable the automatic light sleep functions, does it still crash in this way? Also, can you try moving the gpio_config line to after the gpio_isr_handler_add one?

FrancoB
Posts: 5
Joined: Thu Mar 14, 2024 5:58 pm

Re: Power Management: problems when combining GPIO wakeup with GPIO interrupt in light sleep mode

Postby FrancoB » Fri Mar 22, 2024 2:11 pm

Greetings Sprite. Thanks for your answer.

1)
if you disable the automatic light sleep functions, does it still crash in this way?
Yes, it seems that is not a problem of the PM or sleep functionalities.


2)
Also, can you try moving the gpio_config line to after the gpio_isr_handler_add one?
So, I tried this approch, and ineed, it seems to stop the crashing issue.

The code that I used:

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include "esp_log.h"
#include "esp_pm.h"
#include "esp_sleep.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "driver/gpio.h"
#include "driver/uart.h"


#define GPIO_TO_ISR 18


static TaskHandle_t xTestTask1Handle = NULL;
static TaskHandle_t xTestTaskGpioIsrHandle = NULL;

static esp_pm_lock_handle_t pm_handle = NULL;

const char *TAG = "MAIN";



void isr_handler(void *args);
esp_err_t init_gpio(void);
void vTestTaskGpioIsr(void *pvParameters);
void vTestTask1(void *pvParameters);



void isr_handler(void *args)
{
    BaseType_t xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;

    if(gpio_get_level(GPIO_TO_ISR))
    {
        gpio_set_intr_type(GPIO_TO_ISR, GPIO_INTR_LOW_LEVEL);
    }

    else if(!gpio_get_level(GPIO_TO_ISR))
    {
        gpio_set_intr_type(GPIO_TO_ISR, GPIO_INTR_HIGH_LEVEL);
        vTaskNotifyGiveFromISR(xTestTaskGpioIsrHandle, &xHigherPriorityTaskWoken);
    }

    vTaskNotifyGiveFromISR(xTestTaskGpioIsrHandle, &xHigherPriorityTaskWoken);

    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}





esp_err_t init_gpio(void)
{
    gpio_config_t pGPIOConfig;

    pGPIOConfig.pin_bit_mask = (1ULL << GPIO_TO_ISR);
    pGPIOConfig.mode = GPIO_MODE_DEF_INPUT;
    pGPIOConfig.pull_up_en = GPIO_PULLUP_ENABLE;
    pGPIOConfig.intr_type = GPIO_INTR_LOW_LEVEL;
    
    gpio_install_isr_service(0);

    gpio_isr_handler_add(GPIO_TO_ISR, isr_handler, NULL);

    gpio_config(&pGPIOConfig);

    ESP_LOGI(TAG,"Interrupt configured correctly.");

    return ESP_OK;
}



void vTestTaskGpioIsr(void *pvParameters)
{
    while(1)
    {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        ESP_LOGW(TAG, "GPIO WAKEUP");

        const char* wakeup_reason;
        switch (esp_sleep_get_wakeup_cause()) {
            case ESP_SLEEP_WAKEUP_TIMER:
                wakeup_reason = "timer";
                break;
            case ESP_SLEEP_WAKEUP_GPIO:
                wakeup_reason = "pin";
                break;
            case ESP_SLEEP_WAKEUP_UART:
                wakeup_reason = "uart";
                break;
            default:
                wakeup_reason = "other";
                break;
        }

        ESP_LOGW(TAG, "WAKEUP REASON: %s", wakeup_reason);

        fsync(fileno(stdout));
    }
}



void vTestTask1(void *pvParameters)
{
    while(1)
    {
        ESP_LOGI(TAG, "BLOCKING TASK 1");

        fsync(fileno(stdout));

        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}


void app_main(void)
{

    if(xTestTask1Handle == NULL)
    {
        xTaskCreate(
            vTestTask1,
            "vTestTask1",
            2048,
            NULL,
            2,
            &xTestTask1Handle);
        
        if(xTestTask1Handle == NULL)
        {
            ESP_LOGE(TAG, "Error when creating vTestTask1 task.");
        }
    }

    if(xTestTaskGpioIsrHandle == NULL)
    {
        xTaskCreate(
            vTestTaskGpioIsr,
            "vTestTaskGpioIsr",
            2048,
            NULL,
            2,
            &xTestTaskGpioIsrHandle);
        
        if(xTestTaskGpioIsrHandle == NULL)
        {
            ESP_LOGE(TAG, "Error when creating vTestTaskGpioIsr task.");
        }
    }


    init_gpio();



    while(1)
    {
        ESP_LOGI(TAG, "BLOCKING MAIN TASK");

        fsync(fileno(stdout));

        vTaskDelay(pdMS_TO_TICKS(20000));
        
        const char* wakeup_reason;
        switch (esp_sleep_get_wakeup_cause()) {
            case ESP_SLEEP_WAKEUP_TIMER:
                wakeup_reason = "timer";
                break;
            case ESP_SLEEP_WAKEUP_GPIO:
                wakeup_reason = "pin";
                break;
            case ESP_SLEEP_WAKEUP_UART:
                wakeup_reason = "uart";
                break;
            default:
                wakeup_reason = "other";
                break;
        }

        ESP_LOGW(TAG, "WAKEUP REASON: %s", wakeup_reason);
    }

}


But I don't understand what the problem is. Maybe a problem with the "gpio_isr_handler_add()" function?


Also, in this post that I created with the same topic in GitHub:

https://github.com/espressif/esp-idf/issues/13444

Someone replied to me that the "gpio_set_intr_type()" function is not supposed to be used in a IRQ handler. Is this true?

FrancoB
Posts: 5
Joined: Thu Mar 14, 2024 5:58 pm

Re: Power Management: problems when combining GPIO wakeup with GPIO interrupt in light sleep mode

Postby FrancoB » Thu Apr 11, 2024 12:33 pm

Topic resolved in the GitHub ESP-IDF forum:

https://github.com/espressif/esp-idf/issues/13444

Who is online

Users browsing this forum: Bing [Bot] and 207 guests