Skip to content

uPesy now ships to the entire European Union

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Using ESP32 timers in Arduino code

In this article, we will explore the operation of a timer on the ESP32 using Arduino code. We’ll look at how to set up and use a timer effectively, using practical examples to help you understand the basic concepts. We will discover the steps to configure a timer on the ESP32, with the important parameters for optimal operation. Here we go 😊.

How ESP32 timers work ?

The theoretical functioning of the timer is not presented in this article to avoid overloading it. If you are a beginner and you don’t know the internal working of a timer, I strongly encourage you to read the theoretical article on how it works . It will allow you to better understand how to choose the values of the parameters to use it in your Arduino code.

Configure and use an ESP32 timer with Arduino code

Here is the minimal skeleton code to use a timer on the ESP32 with Arduino code. It allows to trigger an interrupt when the timer reaches the threshold value threashold threshold value, which is commonly called the autoreload .

hw_timer_t * timer = NULL;

void IRAM_ATTR timer_isr() {
    // This code will be executed every 1000 ticks, 1ms

void setup() {
  uint8_t timer_id = 0;
  uint16_t prescaler = 80; // Between 0 and 65 535
  int threshold = 1000000; // 64 bits value (limited to int size of 32bits)

  timer = timerBegin(timer_id, prescaler, true);
  timerAttachInterrupt(timer, &timer_isr, true);
  timerAlarmWrite(timer, threshold, true);

void loop() {

Selection and basic configuration of the timer

We define an object hw_timer_t object outside the setup() function to be able to access it from different functions. The function timerBegin(uint8_t id, uint16_t prescaler, bool countUp) allows to configure the timer :

On the ESP32 there are 4 completely independent timers, they are chosen via an id between 0 and 3. Then, we choose the prescaler that we want to apply to the timer clock signal. On the ESP32, it is the clock APB_CLK clock clocked at 80 MHz is used.


If you use external libraries in your code, they may use timers. In this case you have to be careful not to choose one that is already used by them, otherwise your program will certainly have bugs!

In most of the available examples, a prescaler of 80 is applied to have a counting period of 1 µs. From a period of the timer in microseconds, we can directly know the value of the corresponding autoreload without doing complicated calculations:

\[autoreload = T_{timer}\times10^{6}\space ou \space T_{timer} = autoreload\times10^{-6}\]

The argument countUp argument specifies in which direction we want to count: true in ascending order, false in decreasing order.

Configure the alarm and the triggering of an interrupt routine

We attach to the timer an interrupt which will be triggered each time the threshold value is exceeded with timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge) .

In the middle argument you have to put the name of the interrupt routine that will be executed (here timer_isr() ). You can also choose if the interrupt will be triggered on the rising or falling edge: we generally opt for a rising edge for timers.

The threshold value of the counter is defined by timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload) . We activate the mode autoreload mode by setting autoreload à true : once the timer has exceeded the value alarm_value value, it starts counting again from zero and the interrupt function is triggered.


With a prescaler of 80, the value of alarm_value corresponds directly to the global period of the timer in microseconds.

Once the timer has been completely configured, you can activate it with its alarm with timerAlarmEnable(timer) .

If we execute this code, the function timer_isr() function will be executed every second. Since the function is empty in this “skeleton” code, nothing will actually happen. I propose you a version which makes the blue LED of the ESP32 blink on the pin GPIO2 .

Increment a variable and generate flags

The interrupt routine must be executed as quickly as possible to avoid disturbing the main program. So we commonly use flags which will change state (usually a boolean : true or false ) in the``isr`` . These changes will then be processed in the main loop:

hw_timer_t * timer = NULL;
volatile boolean tick_flags = false;

void IRAM_ATTR timer_isr() {
  tick_flags = true;

void setup() {

  uint8_t timer_id = 0;

This section is available to premium members only. You still have 77% to discover.

Subscribe for only 5$/month

Already subscribed? Sign in

Advanced uses of timers on the ESP32 in Arduino code

Use semaphores to manage read/write access to a shared variable

It is a good practice to frame the interrupt code of a timer in a semaphore to manage access to global variables. This helps predict how the program will work when the interrupt routine and the main program want to write the same variable at the same time. Since the Arduino code for ESP32 uses freeRTOS as a real-time OS, the semaphores are already integrated: we just have to use them directly in our program:

This section is available to premium members only. You still have 93% to discover.

Subscribe for only 5$/month

Already subscribed? Sign in

We use cookies to make your visit to the site as pleasant as possible. Privacy Policy