How to change timer interval in interrupt routine?

Hi

I am running an ESP32 Timer interrupt where I want the timer interval to change between two values every time the interrupt-routine is called. Hence, when toggle0 = true I want one interval and when toggle0 = false I want a different one.

I tried setting the interval in the interrupt routine like below. But this causes a crash everytime the routine is called.

Any suggestions on how to accomplish this in a good way?

I am using the lib ESP32TimerInterrupt by Khoi Hoang.

#define _TIMERINTERRUPT_LOGLEVEL_ 4
#include "ESP32TimerInterrupt.h"

#define TRK_PIN_OUTPUT 19   
#define TRK_OnTime 10
#define TRK_OffTime 1000

// Init ESP32 timer 0
#define TIMER0_INTERVAL_MS 1000
ESP32Timer ITimer0(0);

// Interrupt routine
bool IRAM_ATTR TimerHandler0(void *timerNo)
{
  static bool toggle0 = false;
  digitalWrite(TRK_PIN_OUTPUT, toggle0);

  // Set time to next flip according to current toggle0-state
  ITimer0.setInterval((toggle0 ? TRK_OnTime : TRK_OffTime) * 1000, TimerHandler0);

  toggle0 = !toggle0;

  return true;
}

void setup()
 {
  // Interval in microsecs
  ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0);
}

void loop()
{
   delay(10);
}

Hi @Thomasx

Thanks for using the library.

There are some issues in your sketch

  1. Using Serial.printxx in the ISR, caused by #define _TIMERINTERRUPT_LOGLEVEL_ 4 and setInterval() function
  2. It's safer to wrap the setInterval() function with noInterrupts(); / interrupts();

It's also better to use my ESP32_New_TimerInterrupt library, especially for new ESP32 cores

Try the following modified sketch, from yours, running without crash

#define _TIMERINTERRUPT_LOGLEVEL_ 1

#include "ESP32_New_TimerInterrupt.h"

#ifndef LED_BUILTIN
  #define LED_BUILTIN       2         // Pin D2 mapped to pin GPIO2/ADC12 of ESP32, control on-board LED
#endif

#define TRK_PIN_OUTPUT 19

#define TRK_OnTime 10

#define TRK_OffTime 1000

// Init ESP32 timer 0
#define TIMER0_INTERVAL_MS 1000

ESP32Timer ITimer0(0);

// Interrupt routine
bool IRAM_ATTR TimerHandler0(void *timerNo)
{
  static bool toggle0 = false;
  digitalWrite(TRK_PIN_OUTPUT, toggle0);
  digitalWrite(LED_BUILTIN, toggle0);

  noInterrupts();

  // Set time to next flip according to current toggle0-state
  ITimer0.setInterval((toggle0 ? TRK_OnTime : TRK_OffTime) * 1000, TimerHandler0);

  interrupts();

  toggle0 = !toggle0;

  return true;
}

void setup()
{
  pinMode(TRK_PIN_OUTPUT, OUTPUT);
  pinMode(LED_BUILTIN,    OUTPUT);

  Serial.begin(115200);
  while (!Serial && millis() < 5000);

  delay(100);

  Serial.print(F("\nStarting ChangeInterval_Crash on ")); Serial.println(ARDUINO_BOARD);
  Serial.println(ESP32_NEW_TIMERINTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));

  // Interval in microsecs
  ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0);
}

void loop()
{
  delay(10);
}

Excellent! Now it works. Thank you!

as an addition: interrupts should run through as fast as possible
inside timer interrupt routines you should never do serial printing.
switching an IO-pin HIGH to indicate that the isr is called can be used or setting a boolean-flag-variable that is then checked outside the ISR.

serial printing even on 115200 baud or higher consumes too much time.

best regards Stefan

Ok, so after some testing I notice that it crashes and restarts every now and then, within a few minutes.

Possibly Timer0, Timer1 are used by the core, etc.

Try Timer2 to see OK there. I'm trying here many hours and still OK

If the problem persists, because of the way you're using ISR (the setInterval() function is not designed to be used inside ISR + aggressive timer 10ms), I suggest you rewrite the code to use the correct way

  1. Raise a flag inside ISR
  2. Check the flag frequently, every e.g. 0.5ms, then call setInterval() if flag raised. Certainly, you'll loose a little bit accuracy this way

or

  1. Rewrite the code not using setInterval() inside ISR, but program the registers directly.

Good Luck,

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