ESP32 Using the HW timers

When I started programming on the ESP32 there was no Ticker library available as I was used to from the ESP8266 and Arduino. So I decided to write some code that makes it easy for me to use the ESP32’s hardware timers.

But before I explain the code, some essentials about the HW timers. There are only 4 HW timers available, so the code snippet I made is supporting only 4 timers.

The code snippet for the HW timer wrapper and the example code is available on my Bitbucket repo.

How to setup the HW timers of the ESP32

To use the HW timers we need to include the header file with all the definitions

To setup the timers we first need to define which timer we want to use and the divider for the prescaler (see ESP32 Technical Reference Manual for more info). This is done by calling

To use the HW timer 0 with standard settings the call will look like

Then we need to tell the HW timer which function to call when the time has expired with the call

To attach the ISR (interrupt service routine) void IRAM_ATTR isrTimer1() to the timer the call looks like

Now we tell the HW timer the time it should run and if it should run only once or repeatedly

To prepare a repeating timer with a 2 seconds interval the call is

for a single shot timer with a 500 milli seconds duration the call is

Note the difference of true and false in the call for a repeating or single shot timer.

All is done now, we can start the timer

In this example the call looks like

Of course the ISR needs to be written as well. Keep in mind that ISR must be short and should not do too much work, because while the code of the ISR is executed other interrupts and tasks are disabled. Here is a example for an ISR that just sets a flag that can be processed from the main loop of the application

Now with these calls you can setup a repeating or single-shot HW timer. But I wanted to have a wrapper around this so that I do not need to keep track which of the 4 HW timers I already use.

HW Timer wrapper

As there are 4 HW timers available I first made some definitions to handle the 4 timers with the same group of functions

It sets the number of available timers (availTimers), an array that shows which timers are in use (timerInUse), an array to hold the pointers to the timer structures (attachedTimer), an array for user defined callbacks (usrCallback) and an array for the timer ISR routines (isrPtr). The last array defines for each timer if it is used as repeating or single-shot timer (doRepeat).

initTimer() initTimerSec() initTimerMsec()

To start a timer the function initTimer() is used. It’s parameters are

the time in micro seconds as an uint64_t variable, a pointer to the callback function and a flag to define a repeating or single shot timer. Inside initTimer() the first thing is to check if there is any timer available. If all timers are used up, a NULL pointer is returned. This should be checked by the calling code to see if a timer was started successfully. If one of the 4 timers is available the above explained functions are used to setup the timer.

There are two alternative calls to initialize a timer with the time in seconds or milli seconds, they simple convert the given time into micro seconds and then call initTimer()

startTimer()

To start a specific timer, the function startTimer() is called with a pointer to the timer structure as argument

restartTimer()

To restart a single-shot timer or to restart a repeating timer from 0 the routine restartTimer() can be used. It takes as an argument to pointer to the timer structure, stops that timer and starts it again with the settings given by startTimer()

stopTimer()

The stopTimer() function stops a single timer defined by the parameter timerToStop

stopAllTimers()

To stop all running timers I added a function to check which timers are active and stop all active timers

Interrupt Service Routines

For the ISR (interrupt service routine) for each of the timers I had two possible ways to do it.

  1. Take the user callback function and attach it to the timer
  2. Create a “standard” ISR that is then calling the user callback function

I decided to go for the second solution. This way I made sure that in my callbacks I do not forget to inform the operating system that an ISR is executed and should not be interrupted.

There are four ISR defined, one for each timer. The ISR locks the OS, then calls the user callback function, unlocks the OS and returns. As all of the 4 ISR are basically the same, here is only the code for the ISR for timer 0

How to use the HW timer wrapper

Everybody likes to see some example code, so here is a short program that uses 4 HW timers to display some messages on the Serial port. The example code is available on my Bitbucket repo. To run the code, copy the files hw_timer.cpp and hw_timer.h into your project or sketch folder and create an test_timer.ino (ArduinoIDE) or test_timer.cpp (PlatformIO) file with this code:

 

 

Loading...
Facebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published. Required fields are marked *

Free Link Directory