Page 1 of 1

ESP32 crashes when calling xQueueSendFromISR

Posted: Fri Feb 28, 2020 8:24 pm
by Devenda
After changing the touchpad example to also call xQueueSendFromISR, the ESP32 crashes each time the ISR is executed.

This is the code:

Code: Select all

/* Touch Pad Interrupt Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"

#include "driver/touch_pad.h"
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"

static const char *TAG = "Touch pad";

#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_THRESH_PERCENT (80)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)

static bool s_pad_activated[TOUCH_PAD_MAX];
static uint32_t s_pad_init_val[TOUCH_PAD_MAX];
static xQueueHandle touchQueueStatic;
/*
  Read values sensed at all available touch pads.
  Use 2 / 3 of read value as the threshold
  to trigger interrupt when the pad is touched.
  Note: this routine demonstrates a simple way
  to configure activation threshold for the touch pads.
  Do not touch any pads when this routine
  is running (on application start).
 */
static void tp_example_set_thresholds(void)
{
    uint16_t touch_value;
    for (int i = 0; i < TOUCH_PAD_MAX; i++)
    {
        //read filtered value
        touch_pad_read_filtered(i, &touch_value);
        s_pad_init_val[i] = touch_value;
        ESP_LOGI(TAG, "test init: touch pad [%d] val is %d", i, touch_value);
        //set interrupt threshold.
        ESP_ERROR_CHECK(touch_pad_set_thresh(i, touch_value * 2 / 3));
    }
}

/*
  Check if any of touch pads has been activated
  by reading a table updated by rtc_intr()
  If so, then print it out on a serial monitor.
  Clear related entry in the table afterwards

  In interrupt mode, the table is updated in touch ISR.

  In filter mode, we will compare the current filtered value with the initial one.
  If the current filtered value is less than 80% of the initial value, we can
  regard it as a 'touched' event.
  When calling touch_pad_init, a timer will be started to run the filter.
  This mode is designed for the situation that the pad is covered
  by a 2-or-3-mm-thick medium, usually glass or plastic.
  The difference caused by a 'touch' action could be very small, but we can still use
  filter mode to detect a 'touch' event.
 */
static void tp_example_read_task(void *pvParameter)
{
    static int show_message;
    int change_mode = 0;
    int filter_mode = 0;
    while (1)
    {
        if (filter_mode == 0)
        {
            //interrupt mode, enable touch interrupt
            touch_pad_intr_enable();
            for (int i = 0; i < TOUCH_PAD_MAX; i++)
            {
                if (s_pad_activated[i] == true)
                {
                    ESP_LOGI(TAG, "T%d activated!", i);
                    // Wait a while for the pad being released
                    vTaskDelay(200 / portTICK_PERIOD_MS);
                    // Clear information on pad activation
                    s_pad_activated[i] = false;
                    // Reset the counter triggering a message
                    // that application is running
                    show_message = 1;
                }
            }
        }
        else
        {
            //filter mode, disable touch interrupt
            touch_pad_intr_disable();
            touch_pad_clear_status();
            for (int i = 0; i < TOUCH_PAD_MAX; i++)
            {
                uint16_t value = 0;
                touch_pad_read_filtered(i, &value);
                if (value < s_pad_init_val[i] * TOUCH_THRESH_PERCENT / 100)
                {
                    ESP_LOGI(TAG, "T%d activated!", i);
                    ESP_LOGI(TAG, "value: %d; init val: %d", value, s_pad_init_val[i]);
                    vTaskDelay(200 / portTICK_PERIOD_MS);
                    // Reset the counter to stop changing mode.
                    change_mode = 1;
                    show_message = 1;
                }
            }
        }

        vTaskDelay(10 / portTICK_PERIOD_MS);

        // If no pad is touched, every couple of seconds, show a message
        // that application is running
        if (show_message++ % 500 == 0)
        {
            ESP_LOGI(TAG, "Waiting for any pad being touched...");
        }
        // Change mode if no pad is touched for a long time.
        // We can compare the two different mode.
        if (change_mode++ % 2000 == 0)
        {
            filter_mode = !filter_mode;
            ESP_LOGW(TAG, "Change mode...%s", filter_mode == 0 ? "interrupt mode" : "filter mode");
        }
    }
}

/*
  Handle an interrupt triggered when a pad is touched.
  Recognize what pad has been touched and save it in a table.
 */
static void tp_example_rtc_intr(void *arg)
{
    BaseType_t xHigherPriorityTaskWoken;

    /* We have not woken a task at the start of the ISR. */
    xHigherPriorityTaskWoken = pdFALSE;
    uint32_t pad_intr = touch_pad_get_status();
    //clear interrupt
    touch_pad_clear_status();
    for (int i = 0; i < TOUCH_PAD_MAX; i++)
    {
        if ((pad_intr >> i) & 0x01)
        {
            xQueueSendFromISR(touchQueueStatic, (void *)i, NULL);
            s_pad_activated[i] = true;
        }
    }
}

/*
 * Before reading touch pad, we need to initialize the RTC IO.
 */
static void tp_example_touch_pad_init(void)
{
    for (int i = 0; i < TOUCH_PAD_MAX; i++)
    {
        //init RTC IO and mode for touch pad.
        touch_pad_config(i, TOUCH_THRESH_NO_USE);
    }
}

void app_main(void)
{
    // Initialize touch pad peripheral, it will start a timer to run a filter
    ESP_LOGI(TAG, "Initializing touch pad");
    touch_pad_init();
    // If use interrupt trigger mode, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'.
    touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
    // Set reference voltage for charging/discharging
    // For most usage scenarios, we recommend using the following combination:
    // the high reference valtage will be 2.7V - 1V = 1.7V, The low reference voltage will be 0.5V.
    touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
    // Init touch pad IO
    tp_example_touch_pad_init();
    // Initialize and start a software filter to detect slight change of capacitance.
    touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
    // Set thresh hold
    tp_example_set_thresholds();
    // Register touch interrupt ISR
    touch_pad_isr_register(tp_example_rtc_intr, NULL);
    // Start a task to show what pads have been touched
    xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL);

    touchQueueStatic = xQueueCreate(10, sizeof(int));
}
After pressing one of the touchpads when in interrupt mode (not in filter mode):

Code: Select all

W (42569) Touch pad: Change mode...filter mode
I (47569) Touch pad: Waiting for any pad being touched...
I (52569) Touch pad: Waiting for any pad being touched...
I (57569) Touch pad: Waiting for any pad being touched...
I (62569) Touch pad: Waiting for any pad being touched...
W (62569) Touch pad: Change mode...interrupt mode
I (67569) Touch pad: Waiting for any pad being touched...
I (72569) Touch pad: Waiting for any pad being touched...
I (77569) Touch pad: Waiting for any pad being touched...
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x4000c310  PS      : 0x00060033  A0      : 0x80087730  A1      : 0x3ffb05f0  
A2      : 0x3ffb66b0  A3      : 0x00000008  A4      : 0x00000004  A5      : 0x3ffb66b0  
A6      : 0x00000001  A7      : 0x00000000  A8      : 0x00000000  A9      : 0x3ffb5980  
A10     : 0x3ffb64c0  A11     : 0x40087340  A12     : 0x3ffb4fb0  A13     : 0x3ffb4f90
0x40087340: _frxt_int_enter at C:/Users/tinus/esp/esp-idf/components/freertos/xtensa/portasm.S:119

A14     : 0x00000000  A15     : 0x00000000  SAR     : 0x00000000  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000008  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff
Core 0 was running in ISR context:
EPC1    : 0x4000c310  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x00000000

ELF file SHA256: 1d7ebc082521113e2f20cde608f0d831ff883d04d41874a1bbda2d52c6fc6740

Backtrace: 0x4000c30d:0x3ffb05f0 0x4008772d:0x3ffb0600 0x40087c71:0x3ffb0620 0x400d3a51:0x3ffb0640 0x400d4a9a:0x3ffb0660 0x40082139:0x3ffb0680 0x400e3bf7:0x3ffb4f50 0x400d1c43:0x3ffb4f70 0x4008832a:0x3ffb4f90 0x400870bd:0x3ffb4fb0
0x4008772d: prvCopyDataToQueue at C:/Users/tinus/esp/esp-idf/components/freertos/queue.c:1893

0x40087c71: xQueueGenericSendFromISR at C:/Users/tinus/esp/esp-idf/components/freertos/queue.c:1199

0x400d3a51: tp_example_rtc_intr at C:\Users\tinus\Documents\Projects_no_backup\touch_pad_interrupt\build/../main/esp32/tp_interrupt_main.c:152

0x400d4a9a: rtc_isr at C:/Users/tinus/esp/esp-idf/components/driver/rtc_module.c:71

0x40082139: _xt_lowint1 at C:/Users/tinus/esp/esp-idf/components/freertos/xtensa/xtensa_vectors.S:1164

0x400e3bf7: esp_pm_impl_waiti at C:/Users/tinus/esp/esp-idf/components/esp32/pm_esp32.c:484

0x400d1c43: esp_vApplicationIdleHook at C:/Users/tinus/esp/esp-idf/components/esp_common/src/freertos_hooks.c:63

0x4008832a: prvIdleTask at C:/Users/tinus/esp/esp-idf/components/freertos/tasks.c:3385 (discriminator 1)

0x400870bd: vPortTaskWrapper at C:/Users/tinus/esp/esp-idf/components/freertos/xtensa/port.c:143


Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:4
load:0x3fff0034,len:7188
load:0x40078000,len:14352
load:0x40080400,len:4448
0x40080400: _init at ??:?

entry 0x400806f0
I (29) boot: ESP-IDF v4.2-dev-318-g605da33c3-dirty 2nd stage bootloader
I (29) boot: compile time 17:01:16
I (30) boot: chip revision: 1
I (34) boot_comm: chip revision: 1, min. bootloader chip revision: 0
What am I doing wrong?

Thanks in advance!

Re: ESP32 crashes when calling xQueueSendFromISR

Posted: Fri Feb 28, 2020 8:41 pm
by Devenda
When trying to send to the queue from the filter mode it also crashes the ESP32, so it seems to be a problem with sending to queue's and not necessarily with the ISR.

Re: ESP32 crashes when calling xQueueSendFromISR

Posted: Sat Feb 29, 2020 9:50 am
by ESP_Sprite
If any, you have a big-ass race condition where you initialize touchQueueStatic after you initialize the ISR and task that use it.

Re: ESP32 crashes when calling xQueueSendFromISR

Posted: Sat Feb 29, 2020 12:13 pm
by Devenda
ESP_Sprite wrote:
Sat Feb 29, 2020 9:50 am

If any, you have a big-ass race condition where you initialize touchQueueStatic after you initialize the ISR and task that use it.
Sadly moving:

Code: Select all

touchQueueStatic = xQueueCreate(10, sizeof(int));
to the top of app_main does not help.

Re: ESP32 crashes when calling xQueueSendFromISR

Posted: Sat Feb 29, 2020 1:32 pm
by Devenda
The error was in the xQueueSendFromISR call. The cast to (void *) is wrong, the call should have been:

Code: Select all

xQueueSendFromISR(touchQueueStatic, &i, NULL);

Re: ESP32 crashes when calling xQueueSendFromISR

Posted: Tue Mar 03, 2020 2:08 pm
by ESP_Sprite
Ah, those mistakes are tricky, glad you caught it!