Demo 22: How to use Timer interrupt in Arduino ESP32

1. Introduction
- In blinky demo we use delay() function to make the LED blink. In this demo we will replcae delay() function by using Timer (this is hardware timer). Using Timer we can schedule when a task need to be started and repeat or not. Applying to this demo, when the Timer is timeout we will change the current state of LED (ON to OFF to ON) every 1 second.
2. Hardware
Figure: ESP32 connect to LED
Connection:
[ESP32 IO14 and ESP32 GND to LED]
3. Software
In order to use Timer we will use the functions:
"hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp)"
+ num: is order of Timer. We only have 4 timers so the order can be 0,1,2,3.
+ divider: it is a prescaler. To make 1 second scheduler, we will use divider value is 80. ESP32 main clock is 80MHZ so every tick will take T = 1/(80MHZ/80) = 1 microsecond. We need 1000000 ticks for 1 second.
+ countUp: if it is true the timer will count up and vice versa.
"void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge)"
+ fn: is the callback function that will be invoked when timer timeout and timer interrupt will be invoked.
+ edge: if it is true, an alarm will generate an edge type interrupt.
"void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload)"
+ alarm_value: we set it to 1000000 as calculated above
+ autoreload: if it is true, timer will repeat.
"void timerAlarmEnable(hw_timer_t *timer)": enable the Timer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* create a hardware timer */
hw_timer_t * timer = NULL;

/* LED pin */
int led = 14;
/* LED state */
volatile byte state = LOW;

void IRAM_ATTR onTimer(){
  state = !state;
  digitalWrite(led, state);
}

void setup() {
  Serial.begin(115200);

  pinMode(led, OUTPUT);

  /* Use 1st timer of 4 */
  /* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
  timer = timerBegin(0, 80, true);

  /* Attach onTimer function to our timer */
  timerAttachInterrupt(timer, &onTimer, true);

  /* Set alarm to call onTimer function every second 1 tick is 1us
  => 1 second is 1000000us */
  /* Repeat the alarm (third parameter) */
  timerAlarmWrite(timer, 1000000, true);

  /* Start an alarm */
  timerAlarmEnable(timer);
  Serial.println("start timer");
}

void loop() {

}
4. Result

Post a Comment

9 Comments

Anonymous said…
can I make more than one timers?
Aspiring Hobbist said…
is there a command to disable the alarm after enabling it like void timerAlarmDisable?
Tom said…
There are 4 timers in the esp32. To address them use the #'s 0..3; More timers can be created/configured by using the example codemultiple times.

I have written code to use one timer for multiple and different intervals: one timer ticking at 500ms and a list of intervals to compare to like 1000, 2000, 500.

Tom Meyers
emts said…
Hi.
I am using your example code, to turn on and off a led (infrared of 905nm) with "digitalWrtie", but I do not get pulses under 2 microseconds.

I need to generate pulses at a frequency of 6Mhz and 13.3Mhz, please can you help me.
Anonymous said…
@emts don't use digitalwrite as this arduino implementation takes way to long to execute for these high frequency cycles. You need to use the lower level output level command of whatever board you are using.
Your article is very helpful for me.
I totally agree with what you have said!! Thanks for sharing your views.
I found very good information on your blog
Unfortunately, this code will not work with the latest version of the espressif32 platform. Here is the migration guide:
https://github.com/espressif/arduino-esp32/blob/4cbce10cb178b389827cca9f5c16ade99fa347b6/docs/en/migration_guides/2.x_to_3.0.rst#L156

and here is the LONG list of changes to the timer library
Timer
Timer has been refactored to use the new ESP-IDF driver and its API got simplified. For more information about the new API check :doc:`/api/timer`.

Removed APIs
timerGetConfig
timerSetConfig
timerSetDivider
timerSetCountUp
timerSetAutoReload
timerGetDivider
timerGetCountUp
timerGetAutoReload
timerAlarmEnable
timerAlarmDisable
timerAlarmWrite
timerAlarmEnabled
timerAlarmRead
timerAlarmReadMicros
timerAlarmReadSeconds
timerAttachInterruptFlag
New APIs
timerAlarm used to set up Alarm for the timer and enable it automatically (merged timerAlarmWrite and timerAlarmEnable functions).
timerGetFrequency used to get the actual frequency of the timer.
timerAttachInterruptArg used to attach the interrupt to a timer using arguments.
Changes in APIs
timerBegin has now only 1 parameter (frequency). There is an automatic calculation of the divider using different clock sources to achieve the selected frequency.
timerAttachInterrupt has now only 2 parameters. The edge parameter has been removed.