Changing timer alarm in ISR

Thomas1
Posts: 11
Joined: Wed Jan 23, 2019 7:40 pm

Changing timer alarm in ISR

Postby Thomas1 » Mon Feb 25, 2019 5:28 pm

Hi,
I'm trying to use hardware timer interrupts to change a pin's output between high and low for varying durations. To do this, I change the timer alarm value in the ISR. However, calling the timerAlarmWrite function in the ISR causes A Guru Meditation Error:

Code: Select all

Guru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
Memory dump at 0x401abe54: bad00bad bad00bad bad00bad
The relevant code is as follows:

Code: Select all

#define PIN_A 32

hw_timer_t * timerA = NULL;

volatile bool dcA = false;

int durationON = 80000;
int durationOFF = 120000;


void IRAM_ATTR onTimerA() {
  if (dcA) // ON cycle
  {
    digitalWrite(PIN_A, LOW);
    dcA = false;
    timerAlarmWrite(timerA, durationON, true);
  }
  else // OFF cycle
  {
    digitalWrite(PIN_A, HIGH);
    dcA = true;
    timerAlarmWrite(timerA, durationOFF, true);
  }
}

void setup() {

  pinMode(PIN_A, OUTPUT);
  
  timerA = timerBegin(2, 80, true);
  timerAttachInterrupt(timerA, &onTimerA, true);
  timerAlarmWrite(timerA, durationON, true);
  timerAlarmEnable(timerA);

}

void loop() {

}
I understand this is happening because timerAlarmWrite is not an IRAM_ATTR function. So my question is, is there an IRAM safe way of changing the alarm value that can be called from within an ISR?

Thanks.

idahowalker
Posts: 166
Joined: Wed Aug 01, 2018 12:06 pm

Re: Changing timer alarm in ISR

Postby idahowalker » Mon Feb 25, 2019 6:04 pm

Yes.

Whiles I am not doing what you are trying to do, I hope this serves as an example:

Code: Select all

#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"

#define evtAnalogVoltReadTask_LIDAR  ( 1 << 6 ) //1000000
#define evtfLIDAR_Power_On           ( 1 << 7 ) //10000000
#define evtfLIDAR_Power_Off          ( 1 << 8 ) //100000000

#define TimerDivider 80
#define TaskCore1 1
#define OneK 1000
#define TaskStack10K 10000
#define LIDAR_PowerControl 14

TickType_t xTicksToWait0 = 0;
TickType_t QueueReceiveDelayTime = 20;
TickType_t xTicksToWait20 = 20;
TickType_t xSemaphoreTicksToWait = 30;
TickType_t xSemaphoreTicksToWait10 = 10;

SemaphoreHandle_t sema_iLIDAR_Power_Reset;

/* create event group */
EventGroupHandle_t eg;

volatile int iTicCount = 0; //counts milliseconds
volatile int iLIDAR_Power_Reset = 0;
void IRAM_ATTR onTimer()
{
  BaseType_t xHigherPriorityTaskWoken;
  iTicCount++;
  xEventGroupSetBitsFromISR(eg, OneMilliSecondGroupBits, &xHigherPriorityTaskWoken);
  if ( (iTicCount % 2) == 0 )
  {
    if ( (xSemaphoreTakeFromISR(sema_ReceiveSerial_LIDAR, &xHigherPriorityTaskWoken)) == pdTRUE ) // grab semaphore, no wait
    {
      xEventGroupSetBitsFromISR(eg, evtReceiveSerial_LIDAR, &xHigherPriorityTaskWoken); // trigger every 2mS, if not already processing
    }
  }
  if ( iTicCount == OneK )
  {
    xEventGroupSetBitsFromISR(eg, OneSecondGroupBits, &xHigherPriorityTaskWoken); // trigger every 1X a second
    // reset counter to start again
    iTicCount = 0;
  }
  if ( !bLIDAR_OK )
  {
    xSemaphoreTakeFromISR ( sema_iLIDAR_Power_Reset, &xHigherPriorityTaskWoken );
    ++iLIDAR_Power_Reset;
    xSemaphoreGiveFromISR ( sema_iLIDAR_Power_Reset,  &xHigherPriorityTaskWoken);
    if ( iLIDAR_Power_Reset >= 4000 )
    {
      xEventGroupSetBitsFromISR(eg, evtfLIDAR_Power_On, &xHigherPriorityTaskWoken);
    }
  }
} // void IRAM_ATTR onTimer()

void fLIDAR_Power_On ( void *pvParameters )
{
  for ( ;; )
  {
    xEventGroupWaitBits (eg, evtfLIDAR_Power_On, pdTRUE, pdTRUE, portMAX_DELAY );
    fClearSpiffFile();
    vTaskDelay( pdMS_TO_TICKS( 1 ) );
    xSemaphoreTake ( sema_SPIFF_Buffer, xSemaphoreTicksToWait );
    SPIFF_Buffer.concat ("Power up LIDAR" );
    xEventGroupSetBits( eg, evtOpenAppendSPIFF_FILE );
    digitalWrite ( LIDAR_PowerControl, LOW );
    xSemaphoreTake ( sema_iLIDAR_Power_Reset, xSemaphoreTicksToWait );
    iLIDAR_Power_Reset = 0;
    xSemaphoreGive ( sema_iLIDAR_Power_Reset );
  }
  vTaskDelete( NULL );
} //void fLIDAR_Power_On ) void *pvParameters )

void setup()
{
 eg = xEventGroupCreate();
pinMode( LIDAR_PowerControl, OUTPUT );
 digitalWrite ( LIDAR_PowerControl, HIGH );
 /* Use 4th timer of 4.
    1 tick 1/(80MHZ/80) = 1us set divider 80 and count up.
    Attach onTimer function to timer
    Set alarm to call timer ISR, every 10000uS and repeat / reset ISR (true) after each alarm
    Start an timer alarm
  */
  timer = timerBegin( TIMER_FOUR, TimerDivider, true );
  timerAttachInterrupt( timer, &onTimer, true );
  timerAlarmWrite(timer, OneK, true);
  timerAlarmEnable(timer);
  
  sema_iLIDAR_Power_Reset = xSemaphoreCreateMutex();
  xSemaphoreGive ( sema_iLIDAR_Power_Reset );
  
 xTaskCreatePinnedToCore ( fLIDAR_Power_On, "fLIDAR_Power_On", TaskStack10K, NULL, Priority5, NULL, TaskCore0 ); // assigned to core 0
 } //void setup() // runs on core 1
///////////////////////////
void loop() {} // runs on core 1
I posted other code but I wanted to show how I do a LIDAR power on, so I tried to include all the code for a LIDAR power on.
As you can see the void IRAM_ATTR onTimer() function uses ISR based routines to run various taskings. Instead of functions calls, where the timer has to go to those functions and follow those functions through, the functions are just triggered to run as CPU cycles allow
https://www.freertos.org/a00106.html

Code: Select all

 if (dcA) // ON cycle
  {
    digitalWrite(PIN_A, LOW);
    dcA = false;
    timerAlarmWrite(timerA, durationON, true);
  }
  else // OFF cycle
  {
    digitalWrite(PIN_A, HIGH);
    dcA = true;
    timerAlarmWrite(timerA, durationOFF, true);
  }
You'd replace the above code with a task triggered by an event in the ISR, the task would be wrapped in a semaphore to stop the task from being re-triggered in case the task is already in process when the next interrupt arrives.

Thomas1
Posts: 11
Joined: Wed Jan 23, 2019 7:40 pm

Re: Changing timer alarm in ISR

Postby Thomas1 » Tue Feb 26, 2019 9:18 pm

Thanks. I'll look into that.

PeterRd
Posts: 1
Joined: Sat Jan 30, 2021 8:52 pm

Re: Changing timer alarm in ISR

Postby PeterRd » Sat Jan 30, 2021 9:04 pm

I've been struggling around with a similar problem and then found that the initial code posted by Thomas1will work soon (esp32 v1.05):

ESP32 Library file "cores/esp32/esp32-hal-timer.c" has been fixes by applying IRAM_ATTR to all functions.
(see https://github.com/espressif/arduino-es ... d2172f4a37)

I found the file on my PC and patched it the same way - now my problem has gone!

Who is online

Users browsing this forum: No registered users and 73 guests