Issue with spinlocks and interrupt watchdog timer reset

sgmustadio
Posts: 4
Joined: Thu Mar 04, 2021 4:33 am

Issue with spinlocks and interrupt watchdog timer reset

Postby sgmustadio » Thu Mar 04, 2021 5:04 am

Hi all,

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
}
Here is the Serial output:

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...


Who is online

Users browsing this forum: No registered users and 84 guests