Values in argument struct change after xQueueReceive

magesing
Posts: 3
Joined: Tue Sep 03, 2024 6:42 pm

Values in argument struct change after xQueueReceive

Postby magesing » Tue Sep 03, 2024 7:42 pm

I'm working on a project involving timing button presses of a button attached to GPIO pin 23 of an ESP32 board. In my project, I need to be able to pass some state to my interrupt handler, as well as to my debounce timers. According to the FreeRTOS documentation:
https://github.com/FreeRTOS/FreeRTOS-Ke ... v1.1.0.pdf and https://www.freertos.org/media/2018/Fr ... 0.0.0.pdf ; the void * type arguments to xTaskCreate are intended for this purpose.

The problem I'm having is that after `xQueueReceive` is called in my interrupt handling function, the values in the struct pointed to by my argument pointer get corrupted.

Here is the smallest code I could write to replicate the problem:

Code: Select all

#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "hal/gpio_types.h"

#define GPIO_INPUT_PIN 23
#define GPIO_INPUT_PIN_SEL (1ULL<<GPIO_INPUT_PIN)
#define ESP_INTR_FLAG_DEFAULT 0
static QueueHandle_t gpio_evt_queue = NULL;

typedef struct {
    uint8_t foo;
    uint32_t bar;
} my_t;

static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

static void gpioTask(void * args)
{
    my_t *B = (my_t *)args;
    uint32_t io_num;
    printf("in gpioTask, outside of queue\n");
    printf("    B->foo = %d\n", (int)B->foo);
    printf("    B->bar = %d\n", (int)B->bar);
    printf("\n");
    for (;;) {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            printf("in gpioTask, inside loop, inside queue\n");
            printf("    B->foo = %d\n", (int)B->foo);
            printf("    B->bar = %d\n", (int)B->bar);
            gpio_isr_handler_remove(GPIO_INPUT_PIN);
        }
    }
}

void app_main(void)
{
    my_t baz;
    baz.foo = 3;
    baz.bar = 2;

    gpio_evt_queue = xQueueCreate(8, sizeof(uint32_t));
    if (gpio_evt_queue == NULL){
        printf("ERROR: xQueueCreate failed!");
    }

    gpio_config_t ioConf = {};
    ioConf.intr_type = GPIO_INTR_POSEDGE;
    ioConf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    ioConf.mode = GPIO_MODE_INPUT;
    ioConf.pull_up_en = 0;
    ioConf.pull_down_en = 1;
    gpio_config(&ioConf);
    printf("Hello world!\n");
    if (xTaskCreate(
            gpioTask,
            "gpioTask",
            2048,
            &baz,
            10, //configMAX_PRIORITIES - 5,
            NULL) != pdPASS) {
        printf("Failed to create task!");}
    if(gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT) != ESP_OK){
        printf("ERROR: gpio_install_isr_service failed!\n");
    }
    if(gpio_isr_handler_add(
            GPIO_INPUT_PIN, gpio_isr_handler, (void*) GPIO_INPUT_PIN) != ESP_OK){
        printf("ERROR: hpio_isr_handler_add failed!\n");
    }
}
Here is the output that I get monitoring the code running on my esp32:

Code: Select all

Hello world!
in gpioTask, outside of queue
    B->foo = 3
    B->bar = 2

I (328) main_task: Returned from app_main()
in gpioTask, inside loop, inside queue
    B->foo = 108
    B->bar = 393507
in gpioTask, inside loop, inside queue
    B->foo = 108
    B->bar = 393507

Why are my parameter values being overwritten?

Thanks.

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

Re: Values in argument struct change after xQueueReceive

Postby ESP_Sprite » Wed Sep 04, 2024 1:56 am

You're allocating the my_t structure you're using as a stack variable in app_main, then you pass the address of that variable to your gpio task. However, stack variables become invalid as soon as the scope they're in is exited (in your case, when app_main finishes). So your gpio task now uses a pointer that points to undefined RAM, leading to this weirdness.

Solution is to allocate your my_t in a way that can't go out of scope, e.g. by allocating it globally or using malloc().

magesing
Posts: 3
Joined: Tue Sep 03, 2024 6:42 pm

Re: Values in argument struct change after xQueueReceive

Postby magesing » Wed Sep 04, 2024 3:10 pm

Thank you for the reply, indeed, making my variable a global variable does make the code behave as I intended! :D

Coming from a single-threaded procedural background, the idea that my main function goes out of scope while any part of my code is still executing had never occurred to me!

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

Re: Values in argument struct change after xQueueReceive

Postby ESP_Sprite » Thu Sep 05, 2024 2:07 am

You're welcome. Yeah, variable lifetime (and ownership) suddenly gets a lot more important as you're passing pointers between tasks.

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Majestic-12 [Bot] and 143 guests