I'm creating a demonstration to show how spinlocks can be used to block tasks in a different core (for a video about multicore programming). I recognize that waiting in an ISR is terrible practice, but I found it useful for this particular demonstration.
In the code below, I have an ISR periodically run in Core 1 and take a spinlock for about 20 ms. The idea is to have the task in Core 0 try to take the same spinlock and spin for a while. However, it seems that the interrupt watchdog timer for Core 1 is triggering and causing a reset, even though the 20 ms wait is much less than the 300 ms default IWDT timeout specified for the Arduino ESP32 build.
Did I miss something? Any help would be appreciated.
Here is my code:
Code: Select all
// Core definitions (assuming you have dual-core ESP32)
static const BaseType_t pro_cpu = 0;
static const BaseType_t app_cpu = 1;
// Settings
static const uint16_t timer_divider = 80; // 1 MHz hardware timer
static const uint64_t timer_max_count = 100000; // 1 second ISR interval
static const TickType_t task_wait = 10; // Time (ms) hogging the CPU
static const TickType_t isr_wait = 20; // Time (ms) hogging the CPU
// Globals
static SemaphoreHandle_t bin_sem;
static hw_timer_t *timer = NULL;
static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
//*****************************************************************************
// Interrupt Service Routines (ISRs)
// This function executes when timer reaches max (and resets)
void IRAM_ATTR onTimer() {
TickType_t timestamp;
// Hog the CPU in the ISR (remember: this is a terrible idea)
Serial.print("ISR...");
portENTER_CRITICAL_ISR(&spinlock);
timestamp = xTaskGetTickCount() * portTICK_PERIOD_MS;
while ((xTaskGetTickCount() * portTICK_PERIOD_MS) - timestamp < isr_wait);
portEXIT_CRITICAL_ISR(&spinlock);
Serial.println("Done");
}
//*****************************************************************************
// Tasks
// Task L (low priority)
void doTaskL(void *parameters) {
TickType_t timestamp;
char str[20];
// Do forever
while (1) {
// Say something
Serial.println("L");
// Hog the processor for a while doing nothing
timestamp = xTaskGetTickCount() * portTICK_PERIOD_MS;
while ((xTaskGetTickCount() * portTICK_PERIOD_MS) - timestamp < task_wait);
}
}
// Task H (high priority)
void doTaskH(void *parameters) {
TickType_t timestamp;
char str[20];
// Do forever
while (1) {
// Say something
Serial.print("spinning...");
portENTER_CRITICAL(&spinlock);
Serial.println("H");
portEXIT_CRITICAL(&spinlock);
// Hog the processor for a while doing nothing
timestamp = xTaskGetTickCount() * portTICK_PERIOD_MS;
while ((xTaskGetTickCount() * portTICK_PERIOD_MS) - timestamp < task_wait);
}
}
//*****************************************************************************
// Main (runs as its own task with priority 1 on core 1)
void setup() {
// Configure Serial
Serial.begin(115200);
// Wait a moment to start (so we don't miss Serial output)
vTaskDelay(1000 / portTICK_PERIOD_MS);
Serial.println();
Serial.println("---FreeRTOS Priority Inheritance Demo---");
// Hardware timer (core 1) triggers ISR every 2 seconds
timer = timerBegin(0, timer_divider, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, timer_max_count, true);
timerAlarmEnable(timer);
// Start Task L (low priority)
xTaskCreatePinnedToCore(doTaskL,
"Task L",
1024,
NULL,
1,
NULL,
app_cpu);
// Start Task H (low priority)
xTaskCreatePinnedToCore(doTaskH,
"Task H",
1024,
NULL,
2,
NULL,
pro_cpu);
// Delete "setup and loop" task
vTaskDelete(NULL);
}
void loop() {
// Execution should never get here
}
Code: Select all
L
spinning...H
L
spinning...H
L
spinning...H
L
spinning...H
ISR...spinning...Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)
Core 1 register dump:
PC : 0x40088af8 PS : 0x00060734 A0 : 0x80080f2c A1 : 0x3ffbe790
A2 : 0x3ffc0150 A3 : 0x3ffbebe8 A4 : 0x00000013 A5 : 0x0000046c
A6 : 0x00000000 A7 : 0x00000001 A8 : 0x80080ea0 A9 : 0x3ffbe770
A10 : 0x0000000a A11 : 0x3ffb889c A12 : 0x00000001 A13 : 0x00000001
A14 : 0x00060721 A15 : 0x00000000 SAR : 0x0000001e EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffe
Core 1 was running in ISR context:
EPC1 : 0x400d121b EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40088af8
Backtrace: 0x40088af8:0x3ffbe790 0x40080f29:0x3ffbe7b0 0x400846bd:0x3ffbe7d0 0x400d0bed:0x3ffb87e0 0x400882e5:0x3ffb8800
Core 0 register dump:
PC : 0x40088ffa PS : 0x00060834 A0 : 0x800d0c12 A1 : 0x3ffb8d30
A2 : 0x3ffbebe8 A3 : 0x0000cdcd A4 : 0xb33fffff A5 : 0x00000001
A6 : 0x00060820 A7 : 0x0000abab A8 : 0x0000abab A9 : 0x3ffb8d20
A10 : 0x0000000b A11 : 0x3f400f04 A12 : 0x3ffc0ed4 A13 : 0x3ffbe150
A14 : 0x00000003 A15 : 0x00060023 SAR : 0x00000000 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffc
Backtrace: 0x40088ffa:0x3ffb8d30 0x400d0c0f:0x3ffb8d60 0x400882e5:0x3ffb8d80
Rebooting...