Timer Interrupt not firing Firebeetle ESP32-E

I'm working on a project that uses Bluetooth to interface with my software so I chose a ESP32-E Firebeetle Board.

I recently changed my code to use timer interrupts rather than the crude delay that was fine for scoping out the project initially.

My problem is that the "onTimer" event doesn't fire...

to rule out something in my code causing the issue, I fired up the first Example from here:

https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/timer.html

this example failed to fire the "onTimer" either.

So I took another simple interrupt example and queried the timervalue in the main loop (code below).

I found a few interesting things by doing this, but don't understand what the fundamental issue is.

When I looked at the serial output I noticed that:

  • The first time the timer get to 1,000,000 the timer value resets, after this first occurrence it just keeps increasing.

  • The Timer is incrementing at around 78000 ticks. Since I have 500mS delay and the timer prescaler is 80, then I would expect this to be roughly 500000 ticks....So the timer is running slower than expected???
    If I change the prescaler in the timer begin method from 80 to 8, then the Timer still increments at the same 78000 ticks per main loop.

This has been driving me mad all day.
I only have the 1 Firebeetle board to try, & no other ESP32 devices kicking around to try.
My module does not have any thing else connected to it.
I've also tried timers 0 thru to 3 and get the same result.
I've tried using Arduino IDE 1.8.19 and IDE 2.1.1, and am running the df robot EPS32 board package 0.2.1

If anyone can point me in the right direction I'd appreciate it. right now I'm just thinking that somehow my board is borked, or there is an issue with the DF robot library?

volatile int interruptCounter;
int totalInterruptCounter;

hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);
  //interruptCounter++;
  //Serial.print("interrupt");

  portEXIT_CRITICAL_ISR(&timerMux);

}

void setup() {

  Serial.begin(115200);

  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true);
  timerAlarmEnable(timer);

}

void loop() {
  delay(500);
  Serial.print("timer Value: ");
  Serial.println(timerRead(timer));

  Serial.print("interuppt counter: ");
  Serial.println(interruptCounter);

  if (interruptCounter > 0) {

    portENTER_CRITICAL(&timerMux);
    interruptCounter--;
    portEXIT_CRITICAL(&timerMux);

    totalInterruptCounter++;

    Serial.print("An interrupt as occurred. Total number: ");
    Serial.println(totalInterruptCounter);

  }
}

That example works for me on an Adafruit ESP32 Feather Huzzah.

Also, IMO, using a Critical Section for this applicaton is way overkill:

  portENTER_CRITICAL_ISR(&timerMux);
  isrCounter++;
  lastIsrAt = millis();
  portEXIT_CRITICAL_ISR(&timerMux);
    // Read the interrupt count and time
    portENTER_CRITICAL(&timerMux);
    isrCount = isrCounter;
    isrTime = lastIsrAt;
    portEXIT_CRITICAL(&timerMux);

Do you intend to access the 'isrCounter' value from both ESP32 cores in either regular or ISR code? If not, just use noInterrupts() / interrupts() in the main code and nothing in the ISR. That's much lighter weight than a Critical Section.

Ok, Thanks for checking on your Huzzah. I guess that means there is something wrong with my board or the board package...?

If so, this is annoying as I have PCBs being delivered soon that are designed for this module. I'll have a bit a extra soldering and retracking to do if I have to try fit a Huzzah.

TBH I wasn't 100% sure what the CRITICALs were doing for me - I'm new to the ESP devices, so perhaps I need to read up a bit more. For testing I just copied the example as I wanted to deviate as little as possible from something that should just work.

I've always disable/reenabled interrupts when working with PICs or Atmel, I just presumed this was a more exotic version of the same principal.

I'm only using 1 core for my application, so if I can still use the nointerrupts() then I will probably do that. Thanks for pointing this out.

You didn't test the software with a breadboard version first before cutting copper?

I had everything tested and working and for several weeks before I ordered the board, and then shortly after, I thought of some more features I wanted that were best/more easily implemented with an interrupt.

I may still implement them on this DF robot board...Thinking about it since I have another core to go at I presume I can farm any time critical bits off to that.

The solution is to change true in false: timerAttachInterrupt(timer, &onTimer, false);
It will fire again and again