FreeRTOS xSemaphoreTake assert failed

User avatar
SSSSSteven
Posts: 11
Joined: Tue Dec 05, 2023 1:53 pm
Location: Shanghai, China
Contact:

FreeRTOS xSemaphoreTake assert failed

Postby SSSSSteven » Sat Apr 13, 2024 9:32 pm

I'm using ESP32-S3 to calculate RMS of sine wave signal input from ADC. I use ADC 1 continuous mode, trigger adc_continuous_read by GPTimer and FreeRTOS task, then pass ADC conversion result to another task by queue, store all conversion results, finally calculate root-mean-square after getting enough samples. I use binary semaphore as a flag of "it's time to calculate RMS". But when I call xSemaphoreGive(sem) in the first task then call xSemaphoreTake(sem, 0) in the second task, the FreeRTOS crashed and the board rebooted.

I want to know what's going wrong and how to fix it. Following is my code:

Code: Select all

static adc_continuous_handle_t handle = NULL;
static adc_cali_handle_t cali_handle = NULL;
static SemaphoreHandle_t adc_read_call = NULL;
static SemaphoreHandle_t rms_call = NULL;
static QueueHandle_t rms_data_queue = NULL;
uint32_t frequency; // Will be edited by other tasks

typedef struct {
    int channel;
    int value;
} adc_output_t;

typedef struct {
    uint32_t ret_num;
    adc_output_t data[2048];
} adc_cali_output_t;

static bool IRAM_ATTR adc_read(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) {
    xSemaphoreGiveFromISR(adc_read_call, NULL);
    return true;
}

void adc_read_task(void *pvParameter) {
    int freq_count = 0;
    uint32_t *freq = (uint32_t*)pvParameter;
    while(true) {
        if(xSemaphoreTake(adc_read_call, portMAX_DELAY)) {
            uint8_t results[2048] = {0};
            uint32_t ret_num = 0;
            adc_cali_output_t cali_output;
            memset(&cali_output, 0, sizeof(adc_cali_output_t));
            if(adc_continuous_read(handle, results, 2048, &ret_num, 100) == ESP_OK) {
                int count = 0;
                for(int i = 0; i < ret_num; i += SOC_ADC_DIGI_RESULT_BYTES) {
                    adc_digi_output_data_t *data = (adc_digi_output_data_t*)&results[i];
                    adc_output_t output = {
                        .channel = data->type2.channel - 3, // ADC 1 Channel 3, 4, 5
                    };
                    int voltage = 0;
                    adc_cali_raw_to_voltage(cali_handle, data->type2.data, &voltage);
                    output.value = voltage;
                    cali_output.data[count] = output;
                    count++;
                }
                cali_output.ret_num = count;
                freq_count++;
                xQueueSend(rms_data_queue, &cali_output, portMAX_DELAY);
                if(!(freq_count < *freq)) {
                    freq_count = 0;
                    xSemaphoreGive(rms_call);
                }
            } else {
                ESP_LOGE(TAG, "ADC read failed");
            }
        }
    }
}

uint32_t binpow(long long a, long long b) {
	... // Binary Exponentiation, working fine
}

void adc_rms_task(void* pvParameter) {
    static uint32_t data[3][2000] = {0};
    static float sum_squares[3] = {0};
    static int count[3] = {0};
    adc_cali_output_t cali_output;
    while(true) {
        if(xQueueReceive(rms_data_queue, &cali_output, portMAX_DELAY)) {
            for(int i = 0; i < cali_output.ret_num; i++) {
                data[cali_output.data[i].channel][count[cali_output.data[i].channel]] = cali_output.data[i].value;
                count[cali_output.data[i].channel]++;
            }
            if(xSemaphoreTake(rms_call, 0)) { // assert failed after xSemaphoreGive(rms_call) was called in adc_read_task
                float rms[3] = {0};
                for(int i = 0; i < 3; i++) {
                    for(int j = 0; j < count[i]; j++) {
                        sum_squares[i] += binpow(data[i][j], 2);
                    }
                    rms[i] = sqrt(sum_squares[i] / count[i]);
                }
                memset(sum_squares, 0, sizeof(sum_squares));
                ESP_LOGI(TAG, "RMS: %1fmV, %1fmV, %1fmV", rms[0], rms[1], rms[2]);
                memset(count, 0, sizeof(count));
                memset(data, 0, sizeof(data));
            }
        }
    }
}

esp_err_t adc_init(uint8_t *results) {
    queue = xSemaphoreCreateBinary();
    rms_data_queue = xQueueCreate(10, 2048 * sizeof(adc_digi_output_data_t));
    rms_call = xSemaphoreCreateBinary();
    xTaskCreatePinnedToCore(adc_read_task, "adc_read_task", 32768, (void*)results, 10, NULL, 1);
    xTaskCreatePinnedToCore(adc_rms_task, "adc_voltage_rms_task", 32768, NULL, 10, NULL, 0);
    esp_err_t ret = ESP_OK;

    ... // ADC initalize

    ESP_ERROR_CHECK(adc_continuous_start(handle));

    gptimer_handle_t gptimer = NULL;
    ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
    gptimer_event_callbacks_t callback_config = {
        .on_alarm = adc_read,
    };
    gptimer_config_t timer_config = {
        .clk_src = GPTIMER_CLK_SRC_DEFAULT,
        .direction = GPTIMER_COUNT_UP,
        .resolution_hz = 1000000, // 1MHz, 1 tick=1us
    };
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &callback_config, results));
    ESP_ERROR_CHECK(gptimer_enable(gptimer));
    ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
    ESP_ERROR_CHECK(gptimer_start(gptimer));

    return ret;
}

void app_main() {
	adc_init(&frequency);
}
and backtrace:

Code: Select all

assert failed: xQueueSemaphoreTake queue.c:1709 (( pxQueue ))


Backtrace: 0x40375b5e:0x3fccd120 0x4037b961:0x3fccd140 0x40382079:0x3fccd160 0x4037c1ce:0x3fccd280 0x42009ba5:0x3fccd2c0 0x4037c3f5:0x3fcd1320
None
Waiting for the device to reconnect0x40375b5e: panic_abort at C:/Espressif/frameworks/esp-idf-v5.2.1/components/esp_system/panic.c:472
0x4037b961: esp_system_abort at C:/Espressif/frameworks/esp-idf-v5.2.1/components/esp_system/port/esp_system_chip.c:93
0x40382079: __assert_func at C:/Espressif/frameworks/esp-idf-v5.2.1/components/newlib/assert.c:81
0x4037c1ce: xQueueSemaphoreTake at C:/Espressif/frameworks/esp-idf-v5.2.1/components/freertos/FreeRTOS-Kernel/queue.c:1709 (discriminator 1)
0x42009ba5: adc_voltage_rms_task at C:/Users/littl/Workspace/ESP/measurer/main/adc.c:101
0x4037c3f5: vPortTaskWrapper at C:/Espressif/frameworks/esp-idf-v5.2.1/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:134





ELF file SHA256: bf510f105

Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40375ad4
0x40375ad4: esp_restart_noos at C:/Espressif/frameworks/esp-idf-v5.2.1/components/esp_system/port/soc/esp32s3/system_internal.c:159

SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcbc
load:0x403cc700,len:0x2da0
entry 0x403c9914

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

Re: FreeRTOS xSemaphoreTake assert failed

Postby ESP_Sprite » Sun Apr 14, 2024 1:09 am

It's likely a buffer overflow or some other memory corruption somewhere, but between the magic values that you use (3? 2000? 2048?) I have a hard time squirreling out what's happening exactly.

User avatar
SSSSSteven
Posts: 11
Joined: Tue Dec 05, 2023 1:53 pm
Location: Shanghai, China
Contact:

Re: FreeRTOS xSemaphoreTake assert failed

Postby SSSSSteven » Sun Apr 14, 2024 3:29 am

ESP_Sprite wrote:
Sun Apr 14, 2024 1:09 am
It's likely a buffer overflow or some other memory corruption somewhere, but between the magic values that you use (3? 2000? 2048?) I have a hard time squirreling out what's happening exactly.
3 means there're 3 ADC channels running, 2048 is the max buffer size of ADC, in bytes (BTW my ADC conversion frame size is 128 bytes and the sampling frequency is 10000Hz).

2000 is a real magic number, because I need an array to store all conversion results, but I have no idea about how many conversion frames will be copied in one read, so I just take the array size randomly and make sure it's enough to store all results. Actually, I want to reduce it, since the heap memory is not such many...

Who is online

Users browsing this forum: No registered users and 85 guests