Notifications
Clear all

[Solved] ESP 32 Timer Interrupts – ‘Unlimited’ Programmatic User Definable Timers

54 Posts
7 Users
37 Likes
2,452 Views
Inq
 Inq
(@inq)
Noble Member
Joined: 10 months ago
Posts: 980
 

@ronbentley1 - I might have...  exposed a similar kind of capability in my library, but only for ESP8266 devices.  I prefer event style programming to the massively convoluted loop() methods.  Even when they call subroutines, it's still a mess to debug down the road.  Nothing worse than looking at my Arduino programs from five years ago!  😝 😫 

Here's how a user needs to implement a repeating callback of 1 millisecond.  

#include <InqPortal.h>

InqPortal svr;

void setup() 
{
    svr.onInterval(callback, 1);
}

void callback(void*)
{
    Serial.println(micros());
}

void loop(){}

 

... and the output.  It's not microsecond accurate... but good enough for most anything I can think of.

389573
390573
391567
392570
393565
394567
395562
396564
397559
398554
399556
400551
401553
402546
403549
404544
405547
406541
407544
408539
409541
410536
411538
412533
413535
414530
415533
416528
417530
418525
419520
420522
421517
422520
423515
424517
425512
426514
427508

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
ron bentley reacted
ReplyQuote
Ron
 Ron
(@zander)
Famed Member
Joined: 2 years ago
Posts: 3875
 

@inq So is that using one of the hardware timers, or just a millis() loop.

Arduino says and I agree, in general, the const keyword is preferred for defining constants and should be used instead of #define
"Never wrestle with a pig....the pig loves it and you end up covered in mud..." anon
My experience hours are >75,000 and I stopped counting in 2004.
Major Languages - 360 Macro Assembler, Intel Assembler, PLI/1, Pascal, C plus numerous job control and scripting


   
ReplyQuote
Inq
 Inq
(@inq)
Noble Member
Joined: 10 months ago
Posts: 980
 
Posted by: @zander

@inq So is that using one of the hardware timers, or just a millis() loop.

No, these are software timers.  I wrote the library directly on top of Espressif's code base.  I did not write it on top of the Arduino Core ESP libraries that ride on top of Espressif code. 

I use os_timer_setfn() and os_timer_arm() methods under the covers.  I did not design this interface to be used for things like bit-banging that requires more accuracy.  As you can see from the results... it is millisecond accurate.  I've even written sketches that send out data to browsers at 1 ms intervals.  I've also seen peak rates of 200 kB/sec total going out to multiple browsers... while reading sensors and setting PWM on multiple servos.  Remembering... that PWM is bit-banging software on the ESP8266!  It's why I like them so much.  

And yes... I'm sure I'd love the ESP32 even more, if I could dive into it as deeply as I'm invested in the ESP8266.

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
ron bentley reacted
ReplyQuote
Ron
 Ron
(@zander)
Famed Member
Joined: 2 years ago
Posts: 3875
 

@inq Ok, I have been recently working one level down at the hw_timer level and having a problem, maybe I will use this api and see if the problem goes away. I don't see an esp32 equivalent document, but I imagine the esp32 and esp8266 are similar enough that the api is the same, I guess I will find out. 

Arduino says and I agree, in general, the const keyword is preferred for defining constants and should be used instead of #define
"Never wrestle with a pig....the pig loves it and you end up covered in mud..." anon
My experience hours are >75,000 and I stopped counting in 2004.
Major Languages - 360 Macro Assembler, Intel Assembler, PLI/1, Pascal, C plus numerous job control and scripting


   
ron bentley reacted
ReplyQuote
Ron
 Ron
(@zander)
Famed Member
Joined: 2 years ago
Posts: 3875
 

@inq I just found another esp32 doc. I think this is one level above the hardware, but I have seen so many different esp32 timer/interrupt api's I am disoriented. I haven't tried this one yet so I will give it a try.

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_timer.html#api-reference

Arduino says and I agree, in general, the const keyword is preferred for defining constants and should be used instead of #define
"Never wrestle with a pig....the pig loves it and you end up covered in mud..." anon
My experience hours are >75,000 and I stopped counting in 2004.
Major Languages - 360 Macro Assembler, Intel Assembler, PLI/1, Pascal, C plus numerous job control and scripting


   
ron bentley reacted
ReplyQuote
Inq
 Inq
(@inq)
Noble Member
Joined: 10 months ago
Posts: 980
 

@zander - I think my cursory look over Espressif documents convinced me it might as well be two different companies of engineers creating the ESP8266 versus the ESP32.  Almost everything is different.  It's like they didn't even use the same core concepts.  Almost like Intel versus Motorola chips.  Which gave me serious pause to porting my library to ESP32's.  

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
ron bentley reacted
ReplyQuote
ron bentley
(@ronbentley1)
Honorable Member
Joined: 11 months ago
Posts: 383
Topic starter  

@zander 

Hi Ron,

no millis(), instead it uses one of the 4 readily available hardware timers - timer 0 by default, but this can be 1,2 or 3 by changing the default timer number value (a macro).

I could have used a millis() approach but I am on the ESP 32 learning curve so wanted to explore its timer interrupt capabilities a little.

Ron B

Ron Bentley
Creativity is an input to innovation and change is the output from innovation. Braden Kelley
A computer is a machine for constructing mappings from input to output. Michael Kirby
Through great input you get great output. RZA
Gauss is great but Euler rocks!!


   
ReplyQuote
ron bentley
(@ronbentley1)
Honorable Member
Joined: 11 months ago
Posts: 383
Topic starter  

@inq 

Hi Inq - The ETA framework design ensures that it does not matter if a timer interrupt is triggered during main code execution - it separates interrupt handling from the processing of any other part of the framework, so no clashes should be possible - it operates asynchronously to the timer interrupt ISR. The 'interface' between the ISR process and the framework is simply an interrupt counter - incremented by each interrupt and decremented as part of the framework's main loop processing.  The rules for reading and updating this counter are followed always which ensure no clash or conflict.

As for switch debounce, then yes, this is a pitfall for anyone starting out and trips up so, so many.  There is much on the net about this and I have suggested that this be a subject for one of Bill's videos - both hardware and software debouncing solutions. There are effective methods and libraries for handling this.

Cheers 

Ron

Ron Bentley
Creativity is an input to innovation and change is the output from innovation. Braden Kelley
A computer is a machine for constructing mappings from input to output. Michael Kirby
Through great input you get great output. RZA
Gauss is great but Euler rocks!!


   
Inq reacted
ReplyQuote
ron bentley
(@ronbentley1)
Honorable Member
Joined: 11 months ago
Posts: 383
Topic starter  

@inq 

Hi again,

Yours observations are sound and noted.

I would not, however, recommend use of the ETA framework for use requiring sub-millisecond processing, eg communications time out monitoring, etc.  Everything has its limitations and constraints!

Ron B

Ron Bentley
Creativity is an input to innovation and change is the output from innovation. Braden Kelley
A computer is a machine for constructing mappings from input to output. Michael Kirby
Through great input you get great output. RZA
Gauss is great but Euler rocks!!


   
ReplyQuote
ron bentley
(@ronbentley1)
Honorable Member
Joined: 11 months ago
Posts: 383
Topic starter  

@inq 

Hi again,

Yes, its all down to preference isn't it.  I have never been a big fan of the call back approach but if the 'shoe fits' and all of that.

The important thing is that we have at our disposal a broad range of techniques.

You 'pays your money and you makes you choice'.

Ron B

Ron Bentley
Creativity is an input to innovation and change is the output from innovation. Braden Kelley
A computer is a machine for constructing mappings from input to output. Michael Kirby
Through great input you get great output. RZA
Gauss is great but Euler rocks!!


   
ReplyQuote
THRandell
(@thrandell)
Estimable Member
Joined: 2 years ago
Posts: 135
 
Posted by: @ronbentley1

I was recently finalising some work after my hols relating to ESP 32 timer interrupts and thought some members may find an interest in it.

Hey Ron,

    Thanks for sharing...

Tom

See, the human mind is kind of like... a pinata. When it breaks open, there's a lot of surprises inside. Once you get the pinata perspective, you see that losing your mind can be a peak experience.
Jane Wagner - The Search for Signs of Intelligent Life in the Universe


   
ron bentley reacted
ReplyQuote
ron bentley
(@ronbentley1)
Honorable Member
Joined: 11 months ago
Posts: 383
Topic starter  

@thrandell 

Thanks Tom, most grateful for your note.

Ron B

Ron Bentley
Creativity is an input to innovation and change is the output from innovation. Braden Kelley
A computer is a machine for constructing mappings from input to output. Michael Kirby
Through great input you get great output. RZA
Gauss is great but Euler rocks!!


   
ReplyQuote
Ron
 Ron
(@zander)
Famed Member
Joined: 2 years ago
Posts: 3875
 

@ronbentley1 I spent a few weeks trying to get the hardware timers to work. My problem is I would set an alarm on timer 1 and get the interrupt on timer 2. NOT all the time, sometimes it took days. Found several esp examples that were slightly different in RAM macros, semaphore code, critical section code etc. 

I finally gave up which is not my usual way, I normally am like a dog with a bone.

If you have experienced anything like the above and found the solution I would be happy to hear about it.

FYI the entire logic is on button press set a 30 min alarm. When alarm fires set a boolean variable. The main code does all the rest. 

Arduino says and I agree, in general, the const keyword is preferred for defining constants and should be used instead of #define
"Never wrestle with a pig....the pig loves it and you end up covered in mud..." anon
My experience hours are >75,000 and I stopped counting in 2004.
Major Languages - 360 Macro Assembler, Intel Assembler, PLI/1, Pascal, C plus numerous job control and scripting


   
ReplyQuote
ron bentley
(@ronbentley1)
Honorable Member
Joined: 11 months ago
Posts: 383
Topic starter  

@zander 

Hi Ron,

No, I've not experienced anything like you describe, all very odd! Sounds like  something is getting its wires crossed? Perhaps some corruption somewhere during run time? Impossible to say at a distance.

Just for interest, can you post your code or is it the code you've previously posted on this thread?

Finally, you mention a button switch and I realise I have an outstanding update for you. When we last were discussing switches you had some difficulty installing my switch library. Well now it is available under the Arduino IDE library manager along with it documentation. Do a search for 'ez_switch_lib' if you still have an interest.

In the mean time, how is your button switch wired? I assume you have a pull down 10k resistor connected to the pin and the other side to +3.3v? Ie pinMode(pin, INPUT)?

How are you handling debounce?

Regard

Ron B

 

Ron Bentley
Creativity is an input to innovation and change is the output from innovation. Braden Kelley
A computer is a machine for constructing mappings from input to output. Michael Kirby
Through great input you get great output. RZA
Gauss is great but Euler rocks!!


   
ReplyQuote
Ron
 Ron
(@zander)
Famed Member
Joined: 2 years ago
Posts: 3875
 

@ronbentley1 No doubt it's run time corruption, the question is where? I actually have it failing ALL the time now using arduino api sample code. I am including part of the code for brevity, the missing parts are other buttons identical in nature, some emergency on/off toggle switches and the wifi/mqtt/logging code.

I used another Button library, it's just a simple and very old library. There is no concern there, the problem is that the wrong ISR is executing (I have 3 that are the same other than names) 

Not that it matters, but the button switches are using INPUT_PULLUP, it's built into the esp32, no need for external resistors etc.

The problem is manifested 30 minutes after pressing the button, I get a log msg of Button K pressed, then 30 minutes later Button B's ISR fires and turns off the already off Bathroom variable.

I have checked that I don't have a typo about 20 or more times. I checked for all occurrences of Kitchen and K and they were all where they should be, I then did the same for Bathroom and B and again no more or less were found.

If I am not mistaken, this version fails every time, I have other ISR routines using different memory macros and critical section macros vs semaphores that fail after a few days. All the various 'styles' of ISR I have tried came from what I would call reputable sources.

 Any ideas?

volatile SemaphoreHandle_t timerSemaphoreK;

hw_timer_t * TimerWasher   = NULL;

portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void ARDUINO_ISR_ATTR TimerKitchen_ISR()  { xSemaphoreGiveFromISR(timerSemaphoreK, NULL); }

void setup() {

  LOG("Set up timer for Kitchen ");
  timerSemaphoreK = xSemaphoreCreateBinary();      // Create semaphore to inform us when the timer has fired
  TimerKitchen = timerBegin(0, 40000, true);    // timer is now 1/2000 or every 2ms tick
  if (NULL == TimerKitchen) LOG(" TimerKitchen is NULL ");
  timerAttachInterrupt(TimerKitchen, &TimerKitchen_ISR, Edge);
  timerAlarmWrite(TimerKitchen, DurationK, AutoReload);
  timerAlarmDisable(TimerKitchen);

}

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

  if (ButtonK.pressed()){
    LOG(" Kitchen calling ");
    if (TimerKitchenOn) KitchenOFF();   // If ON, turn OFF
    else KitchenON();                   // else turn ON
  }

  if (TimerWasherOn | TimerBathroomOn | TimerKitchenOn) digitalWrite(SSR_Pin, HIGH);  
  else digitalWrite(SSR_Pin, LOW);
  
  if (xSemaphoreTake(timerSemaphoreK, 0) == pdTRUE) KitchenOFF();      // If Timer has fired turn off water

}

void KitchenON(){
  TimerKitchenOn = true;
  LOG(" Kitchen ON ");
  ledcWrite(LedChanYellow[Kitchen], DutyCycleYellow[Kitchen]);
  timerAlarmEnable(TimerKitchen);
}

void KitchenOFF(){
  TimerKitchenOn = false;
  LOG(" Kitchen OFF ");
  ledcWrite(LedChanYellow[Kitchen], DutyCycleOff);    
  timerAlarmDisable(TimerKitchen);  
}

Arduino says and I agree, in general, the const keyword is preferred for defining constants and should be used instead of #define
"Never wrestle with a pig....the pig loves it and you end up covered in mud..." anon
My experience hours are >75,000 and I stopped counting in 2004.
Major Languages - 360 Macro Assembler, Intel Assembler, PLI/1, Pascal, C plus numerous job control and scripting


   
ReplyQuote
Page 2 / 4