ESP32-RTOS-Timers

Hi.

in my program, I created two tasks, one timer . a flag (sampling_permission) which is set in the ISR of the timer is used in one of my task (ADXL_Handler). after printing the data-set for the second time, the ESP32 crashes. I have no Idea what is the reason.

if the flag is not used inside my task which is ADXL handler, everything is fine and ESP does not crash. the program will run without problem.

Here is the error after crashing :
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1).

Core 1 register dump:
PC : 0x4008a394 PS : 0x00060d35 A0 : 0x800895e6 A1 : 0x3ffbed7c
A2 : 0x3ffb8a00 A3 : 0x3ffb8890 A4 : 0x00000004 A5 : 0x00060d23
A6 : 0x00060d23 A7 : 0x00000001 A8 : 0x3ffb8890 A9 : 0x00000018
A10 : 0x3ffb8890 A11 : 0x00000018 A12 : 0x00000004 A13 : 0x00060d23
A14 : 0x007beed8 A15 : 0x003fffff SAR : 0x0000001f EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x400860d5 LEND : 0x400860e5 LCOUNT : 0xffffffee
Core 1 was running in ISR context:
EPC1 : 0x400db09f EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000

Backtrace:0x4008a391:0x3ffbed7c |<-CORRUPTED

Core 0 register dump:
PC : 0x4008a50b PS : 0x00060035 A0 : 0x8008920f A1 : 0x3ffbe82c
A2 : 0x3ffbeed8 A3 : 0xb33fffff A4 : 0x0000abab A5 : 0x00060023
A6 : 0x00060021 A7 : 0x0000cdcd A8 : 0x0000abab A9 : 0xffffffff
A10 : 0x00000000 A11 : 0x00000000 A12 : 0x3ffc1ef8 A13 : 0x00000007
A14 : 0x007beed8 A15 : 0x003fffff SAR : 0x0000001a EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000

Backtrace:0x4008a508:0x3ffbe82c |<-CORRUPTED

ELF file SHA256: 0000000000000000

Rebooting...

Here is the code:

#include <Arduino.h>
#include <SPI.h>
#if CONFIG_FREERTOS_UNICORE
static const BaseType_t app_cpu = 0;
#else
static const BaseType_t app_cpu = 1;
#endif

#define HSPI_MISO   12
#define HSPI_MOSI   13
#define HSPI_SCLK   14
#define HSPI_SS     15

//function protopypes
 bool SPI_Write_Reg(uint8_t register_addr, uint8_t register_value);
 uint8_t SPI_Read_Reg(uint8_t Reg_Addr);
 float Read_X_Axis(int8_t *xdata);
 float Read_Y_Axis(int8_t *ydata);
 float Read_Z_Axis(int8_t* zdata);


//Global vairiables
 static const int led_pin = LED_BUILTIN;
 static const int spiClk = 4000000; // 4 MHz

 //Address for the Range Register
 const uint8_t RANGE = 0x2C;    //Considered Reset value for this Register is 0x81.
 const uint8_t RANGE_2G = 0x01;  //value to set the 2G_range of the sensor
 const uint8_t POWER_CTL = 0x2D; //Power control Register's Address.
 const uint8_t MEASURE_MODE = 0x06; // Only accelerometer
 const uint8_t ADXL_Reset_Reg_Address= 0x2F;  //this Reg is only Writable. put 0x00 to this Reg in order to reset it.
//Senors's reset register address
 static uint8_t  READ_BYTE = 0x01;
 static uint8_t WRITE_BYTE = 0x00;
 static uint8_t reg_adress = 0x00;

 //address of the X axis
 const uint8_t XDATA3 = 0x08;
 const uint8_t XDATA2 = 0x09;
 const uint8_t XDATA1 = 0x0A;

 //address of the Y axis
 const uint8_t YDATA3 = 0x0B;
 const uint8_t YDATA2 = 0x0C;
 const uint8_t YDATA1 = 0x0D;

 //address of the Z axis
 const uint8_t ZDATA3 = 0x0E;
 const uint8_t ZDATA2 = 0x0F;
 const uint8_t ZDATA1 = 0x10;

 //X axis variables
 int8_t xdata[3]={0,0,0};
 int32_t Xdata_i=0;
 float Xdata_d[200] = {0.0};
 //static float Xdata_d = 0;

 //Y axis variables
 int8_t ydata[3]={0,0,0};
 int32_t Ydata_i=0;
 float Ydata_d[200] = {0.0};
 //static float Ydata_d = 0;

 //Z axis variables
 int8_t zdata[3]={0,0,0};
 int32_t Zdata_i=0;
 float Zdata_d[200] = {0.0};
 //static float Zdata_d = 0;

 char uart_buff[200]={0};
 uint8_t sample_counter = 0;

 bool sampling_permission = true;

 uint64_t dataset_counter = 0;
 uint8_t led_status = 0;

 hw_timer_t * timer3 = NULL;
portMUX_TYPE timerMux3 = portMUX_INITIALIZER_UNLOCKED;

static TaskHandle_t LED_HANDLER_Handle = NULL;
static TaskHandle_t ADXL_task_Handle = NULL;
bool uart_show_dataset = false;

void IRAM_ATTR onTimer3(){
 //portENTER_CRITICAL_ISR(&timerMux3);
  sampling_permission = true;
  Serial.println(" 2 minute has passed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
 //portEXIT_CRITICAL_ISR(&timerMux3);
}


//LED Handler task
void LED_HANDLER(void *parameter){

  while(1){

    led_status = !led_status;
    digitalWrite(LED_BUILTIN, led_status);
    vTaskDelay(500 / portTICK_PERIOD_MS); // time interval dring which the task is executed,// vtask delay expects the number of tiks or time intervals,//which is set to 1ms by default
   // Serial.println(" 500ms has passed " + String(millis()) + "   Task LED-Blinker running on core " + String(xPortGetCoreID()));
      
  }  

}

//Accelerometer Handler task
void ADXL_Handler(void *parameter){

  while(1){

   if(sampling_permission){
      Xdata_d[sample_counter] = Read_X_Axis(xdata);
      Ydata_d[sample_counter] = Read_Y_Axis(ydata);
      Zdata_d[sample_counter] = Read_Z_Axis(zdata);
      sample_counter++;
    
      if(sample_counter == 200){
        sampling_permission = false;
        sample_counter = 0;
        dataset_counter++;
        uart_show_dataset = true;
        
        for ( int i = 0; i<200 ; i++) {
            sprintf(uart_buff, "Sensor data: Ax = %.3f  Ay = %.3f  Az = %.3f", Xdata_d[i], Ydata_d[i], Zdata_d[i]);
            Serial.println(uart_buff);
        }
      sprintf(uart_buff, "end of data set %d", dataset_counter);
      Serial.println(uart_buff);
      Serial.print("ADXL_Handler is running on core ");
      Serial.println(xPortGetCoreID());
      //memset(Xdata_d, 0, 200);
      //memset(Ydata_d, 0, 200);
      //memset(Zdata_d, 0, 200);
    }
  }
      vTaskDelay(50 / portTICK_PERIOD_MS); //suspend this task every 4ms during which RTOS run other tasks. 
 }
  
}

void setup() {

  //vTaskSuspend();
  pinMode(led_pin, OUTPUT);
  Serial.begin(921600);

  //SPI Initializations 
  SPI.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SPI-BUS initializing 
  pinMode(HSPI_SS, OUTPUT); //HSPI Slave select pin defined as output

  //ADXL355 initialiyation
  SPI_Write_Reg (ADXL_Reset_Reg_Address , 0x52);           //resetting the ADXL
  SPI_Write_Reg (RANGE, RANGE_2G);            //Setting the ADXL Range to 2G
  SPI_Write_Reg (POWER_CTL, MEASURE_MODE);    //Setting the ADXL to the measurment mode.
  
  //create the LED Handler Task
  xTaskCreatePinnedToCore(
      LED_HANDLER,   // function to be called as the task
      "LED_HANDLER", // name of the task
      1024,       // stack size of the task in KB, min value 756 Byte
      NULL,       // parameter to pass to function
      1,          // task priority which is 0 to 24, higher number higher peiority 
      &LED_HANDLER_Handle,       // a pointer used for handling the current task from other tasks or main loop
      app_cpu);   // choosing our core
   // remember that loop() and setup() are considered as task with priority one. 


//create the Acceleremetor Handler Task
xTaskCreatePinnedToCore(
      ADXL_Handler,   // function to be called as the task
      "ADXL_Handler", // name of the task
      8192,       // stack size of the task in KB, min value 756 Byte
      NULL,       // parameter to pass to function
      2,           // task priority which is 0 to 24, higher number higher peiority 
      &ADXL_task_Handle,       // a pointer used for handling the current task from other tasks or main loop
      app_cpu);   // choosing our core
   // remember that loop() and setup() are considered as task with priority one. 

//Timer1 Initialization
  timer3 = timerBegin(3, 80, true); //uint8_t num, uint16_t prescalar 80, bool countUp . our clock is 80MHz 
  timerAttachInterrupt(timer3, &onTimer3, true); //true: trigger on edge
  timerAlarmWrite(timer3, 120000000, true); // timer tick = 1u sec
  timerAlarmEnable(timer3);

  //vTaskResume(ADXL_task_Handle);
}



void loop() {
  // put your main code here, to run repeatedly:
  
 
}



//our function definitions
bool SPI_Write_Reg (uint8_t register_addr , uint8_t register_value){
  uint8_t Modif_addr = 0;
  Modif_addr = (register_addr << 1) | WRITE_BYTE;
  digitalWrite(HSPI_SS, LOW);
  SPI.transfer(Modif_addr);
  SPI.transfer(register_value);
  digitalWrite(HSPI_SS, HIGH);
  return true;
}

 uint8_t  SPI_Read_Reg(uint8_t Reg_Addr){
  uint8_t Mod_Reg_Addr = (Reg_Addr << 1) | READ_BYTE;
  uint8_t Reg_Value = 0;
  digitalWrite(HSPI_SS, LOW);
  SPI.transfer(Mod_Reg_Addr);
  Reg_Value = SPI.transfer(0x00);
  digitalWrite(HSPI_SS, HIGH);
  return Reg_Value;
}


 float Read_X_Axis(int8_t* xdata){
  int32_t Xdata_i;
  float Xdata_d;
  xdata[0] = SPI_Read_Reg(XDATA1);
  xdata[1] = SPI_Read_Reg(XDATA2);
  xdata[2] = SPI_Read_Reg(XDATA3);
  Xdata_i = ((int32_t)xdata[0] >> 4) + ((int32_t)xdata[1] << 4) + ((int32_t)xdata[2] << 12);
  Xdata_d = (float)Xdata_i/256000;
  return Xdata_d;
};

 float Read_Y_Axis(int8_t* ydata){

  int32_t Ydata_i;
  float Ydata_d;
  ydata[0] = SPI_Read_Reg(YDATA1);
  ydata[1] = SPI_Read_Reg(YDATA2);
  ydata[2] = SPI_Read_Reg(YDATA3);
  Ydata_i = ((int32_t)ydata[0] >> 4) + ((int32_t)ydata[1] << 4) + ((int32_t)ydata[2] << 12);
  Ydata_d = (float)Ydata_i/256000;
  return Ydata_d;
};

 float Read_Z_Axis(int8_t* zdata){

  int32_t Zdata_i;
  float Zdata_d;
  zdata[0] = SPI_Read_Reg(ZDATA1);
  zdata[1] = SPI_Read_Reg(ZDATA2);
  zdata[2] = SPI_Read_Reg(ZDATA3);
  Zdata_i = ((int32_t)zdata[0] >> 4) + ((int32_t)zdata[1] << 4) + ((int32_t)zdata[2] << 12);
  Zdata_d = (float)Zdata_i/256000;
  return Zdata_d;
};

Use a semaphore for the flag.

I implemented another code using only two tasks one of which works like timer and the second one is responsible for sending and receiving using SPI. I used semaphore and it works.
The semaphore I know to use is to impose mutual exclusion only for tasks. like

if(xSemaphoreTake(mutex,0) == pdTRUE){
     //critical section
      xSemaphoreGive(mutex);
      }

can I use this even in timer ISR? I think the ISR is an atomic function which can not be interrupted. right? and we need a semaphore inside the ISR to have mutual exclusion?

Use a notification. Call vTaskNotifyGiveFromISR() from the timer ISR.

Have your ADXL_Handler task pend on that notification using ulTaskNotifyTake().

Could you please provide an example?
I red about it but I is still vague for me.

Here is the page I could not understand how to use it.

Simple example of sending a notification from an ISR. It uses a pin interrupt, but the concept would be the same from a timer interrupt.

#include "Arduino.h"

void handleInterrupt(void *pvParameters);
void pinIsr();
TaskHandle_t handlerTask;
const uint8_t interruptPin = 21;

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting");

  BaseType_t returnCode = xTaskCreatePinnedToCore(handleInterrupt, "Handle Interrupt", 2000, NULL, 4, &handlerTask, CONFIG_ARDUINO_RUNNING_CORE);
  if (returnCode != pdPASS) {
    log_e("Failed to create WiFi Event Processing Task");
    vTaskDelete(NULL);
  }

  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), pinIsr, FALLING);
}

void loop() {
}

void handleInterrupt(void *pvParameters) {
  for (;;) {
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    Serial.println("Interrupt Detected");
  }
}

void IRAM_ATTR pinIsr() {
  BaseType_t pxHigherPriorityTaskWoken = pdFALSE;

  vTaskNotifyGiveFromISR(handlerTask, &pxHigherPriorityTaskWoken);
  if (pxHigherPriorityTaskWoken == pdTRUE) {
    portYIELD_FROM_ISR();
  }
}

To start with your device connected to the HSPI buss must NOT do any signal line changes during boot or programing.

Next when the debug stuff is put into the exception decoder what is the decoded error?

Next, printing from a ISR, really?

void IRAM_ATTR onTimer()
{
  BaseType_t xHigherPriorityTaskWoken;
  xEventGroupSetBitsFromISR(eg, OneMinuteGroup, &xHigherPriorityTaskWoken);
} // void IRAM_ATTR onTimer()

Should start the timer before the task are created, as a note.

this task will cause an error.

without any traffic management code. That task is running as fast as the CPU can run the task ignoring all other tasks.

Thank you. that helped me a lot.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.