Reputation: 3640
I'm using the FreeRTOS Task Notifications as a lightweight event-group, as described in the FreeRTOS documentation here. The idea is to make two simple tasks print Ping
and Pong
in an alternating sequence, each notifying each other when they have finished printing.
The program compiles successfully, but crashes moments after startup with the following stack trace:
assertion "coreID == mux->owner" failed: file "/home/micrified/Documents/Somnox/esp-idf/components/freertos/portmux_impl.inc.h", line 157, function: vPortCPUReleaseMutexIntsDisabledInternal
abort() was called at PC 0x400d58cf on core 1
0x400d58cf: __assert_func at /builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)
ELF file SHA256: bd56229aae2c8bfb3479e7a47ebb97d9be7e36483cea95737781c99e1daa0200
Backtrace: 0x400849cd:0x3ffb69a0 0x40084d41:0x3ffb69c0 0x400d58cf:0x3ffb69e0 0x400883ab:0x3ffb6a10 0x40087a3a:0x3ffb6a30 0x40087af9:0x3ffb6a70 0x40082755:0x3ffb6a90 0x40082841:0x3ffb6ac0 0x400d3697:0x3ffb6ae0 0x400d2609:0x3ffb6b00 0x4000bd83:0x3ffb6b20 |<-CORRUPTED
0x400849cd: invoke_abort at /home/micrified/Documents/Somnox/esp-idf/components/esp32/panic.c:155
0x40084d41: abort at /home/micrified/Documents/Somnox/esp-idf/components/esp32/panic.c:172
0x400d58cf: __assert_func at /builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:62 (discriminator 8)
0x400883ab: vPortCPUReleaseMutexIntsDisabledInternal at /home/micrified/Documents/Somnox/esp-idf/components/freertos/portmux_impl.inc.h:157
(inlined by) vPortCPUReleaseMutexIntsDisabled at /home/micrified/Documents/Somnox/esp-idf/components/freertos/portmux_impl.h:110
(inlined by) vTaskExitCritical at /home/micrified/Documents/Somnox/esp-idf/components/freertos/tasks.c:4261
0x40087a3a: xQueueGenericReceive at /home/micrified/Documents/Somnox/esp-idf/components/freertos/queue.c:1542
0x40087af9: xQueueTakeMutexRecursive at /home/micrified/Documents/Somnox/esp-idf/components/freertos/queue.c:635
0x40082755: lock_acquire_generic at /home/micrified/Documents/Somnox/esp-idf/components/newlib/locks.c:157
0x40082841: _lock_acquire_recursive at /home/micrified/Documents/Somnox/esp-idf/components/newlib/locks.c:171
0x400d3697: uart_write at /home/micrified/Documents/Somnox/esp-idf/components/vfs/vfs_uart.c:194
0x400d2609: esp_vfs_write at /home/micrified/Documents/Somnox/esp-idf/components/vfs/vfs.c:420 (discriminator 4)
I'm not directly interfacing with any FreeRTOS semaphores or mutex types myself, so I'm unsure what the cause of this error is.
My program code is fairly simple. I'm running it on an ESP-32 development board and building with the ESP-IDF tool-suite.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#define A_BIT 0x1
#define B_BIT 0x2
TaskHandle_t handle_task_a;
TaskHandle_t handle_task_b;
void a_task (void *pvParameters) {
BaseType_t xResult;
uint32_t value;
while (1) {
// Block waiting for notification
xResult = xTaskNotifyWait(pdFALSE, // Don't clear bits on entry
A_BIT, // Clear own bit on exit
&value, // Save value
portMAX_DELAY); // Block indefinitely
if (xResult != pdPASS) {
fprintf(stderr, "Err: Task A bad notify!\n");
return;
}
// Ignore if bit not set
if ((value & A_BIT) == 0) {
continue;
}
// Otherwise wait a second
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Show message
printf("Task A: Ping!\n");
// Dispatch notification to task B
xTaskNotify(handle_task_b, B_BIT, eSetBits);
}
}
void b_task (void *pvParameters) {
BaseType_t xResult;
uint32_t value;
while (1) {
// Block waiting for notification
xResult = xTaskNotifyWait(pdFALSE, // Don't clear bits on entry
B_BIT, // Clear own bit on exit
&value, // Save value
portMAX_DELAY); // Block indefinitely
if (xResult != pdPASS) {
fprintf(stderr, "Err: Task B bad notify!\n");
return;
}
// Ignore if bit not set
if ((value & B_BIT) == 0) {
continue;
}
// Otherwise wait a second
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Show message
printf("Task B: Pong!\n");
// Dispatch notification to task A
xTaskNotify(handle_task_a, A_BIT, eSetBits);
}
}
void app_main(void)
{
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
// Create task A
if(xTaskCreate(a_task, "Task A", 512, NULL, tskIDLE_PRIORITY, &handle_task_a) != pdPASS) {
fprintf(stderr, "Error creating task A!\n");
return;
}
// Create task B
if (xTaskCreate(b_task, "Task B", 512, NULL, tskIDLE_PRIORITY, &handle_task_b) != pdPASS) {
fprintf(stderr, "Error creating task B!\n");
return;
}
// Kick off by notifying task A
xTaskNotify(handle_task_a, A_BIT, eSetBits);
}
Upvotes: 1
Views: 2538
Reputation: 2469
There are actually 2 errors here, and the error message doesn't tell much about either one.
Problem 1: Scheduler
In app_main() you create the tasks but never start the scheduler. If the scheduler isn't running, it never starts the tasks. You need something like
//ERROR: you cant call this before the scheduler starts
// Kick off by notifying task A
//xTaskNotify(handle_task_a, A_BIT, eSetBits);
// Start the real time scheduler.
vTaskStartScheduler();
// Will not get here unless there is insufficient RAM.
}
https://www.freertos.org/a00132.html
That is only part of the problem, even with that your code will not run. There is another error: you can't call xTaskNotify before you start the scheduler which leads us to the next point...
Problem 2: Deadlock
Since we couldn't call xTaskNotify before running the scheduler, nothing will ever happen. The way your tasks are written will create a deadlock.
So the question is where to put the xTaskNotify to prevent deadlock?
There are a few solutions, you can use a button, or a timer interrupt to trigger the first xTaskNotify (if you do this from an ISR make sure to use xTaskNotifyFromISR) and get the whole system running. The easier way is to add it to the startup code of one of your tasks.
void b_task (void *pvParameters) {
BaseType_t xResult;
uint32_t value;
//First we wait a little for the scheduler to settle
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Kick off by notifying task A
xTaskNotify(handle_task_a, A_BIT, eSetBits);
while (1) {
At this point your code should run as expected.
Upvotes: 1