ESP32 Timer Tutorial

Embedded Software requires Timer functionality for solving many use cases. ESP-IDF is based on FreeRTOS and we use freertos api to design our application. FreeRTOS do provide software timers, but these timers have limitations such as it's smallest possible interval/period can be at best be qual to the RTOS tick period such as 1ms / 10ms . In addition, the software timer callbacks are dispatched from a low priority task. In order to address these issues we can get help from the ESP32 microcontroller itself. The microcontroller has dedicated hardware Timer peripheral as part of the SoC which does not consume any CPU processing and can execute as a higher priority interrupt

Timer Features

ESP-IDF has esp_timer API using which we can get hold of the internal 32bit hardware timer. Let’s see what it provides.

  • It is a high resolution timer
  • Provides one-shot timer
  • Provides periodic timer
  • Timer callbacks are dispatched from a high priority esp_timer task

it is recommended to make the code in the callback as small as possible, the callback can dispatch another low priority task using a queue

  • Time since boot can be read using esp_timer_get_time()
  • Enabling esp_timer profiling feature in menuconfig cause esp_timer_dump() function to print more information

Code-Walkthrough

Now we will go through this example to understand the usage of esp_timer https://github.com/espressif/esp-idf/tree/master/examples/system/esp_timer

The example code creates a periodic timer & a one-shot timer

To create a esp_timer type timer the following configuration type structure is needed to be instantiated

typedef struct {
   
esp_timer_cb_t callback;                //!< Function to call when timer expires
   
void* arg;                                        //!< Argument to pass to the callback
   
esp_timer_dispatch_t dispatch_method;   //!< Call the callback from task or from ISR
   
const char* name;                       //!< Timer name, used in esp_timer_dump function
}
esp_timer_create_args_t;

So we create one of the type above

    const esp_timer_create_args_t periodic_timer_args = {
           .callback = &periodic_timer_callback,
           .name =
"periodic" /* name is optional, but may help identify the timer when debugging */
   };

Before creating the timer we also need a esp_timer_handle_t type handle with the following structure

struct esp_timer {
   
uint64_t alarm;
   
uint64_t period;
   
union {
       
esp_timer_cb_t callback;
       
uint32_t event_id;
   };

typedef struct esp_timer* esp_timer_handle_t;

So we create a handle out of the structure type above

esp_timer_handle_t periodic_timer;

Now we will use the esp_timer_create() function to create the timer

esp_err_t esp_timer_create(
 
const esp_timer_create_args_t* create_args,            
                         
esp_timer_handle_t* out_handle
                          );

Now as we have the arguments and handler variable instantiated, we will call The create function which is wrapped by ESP_ERROR_CHECK macro function

 ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));

Now the timer is created but the timer has not started yet . we need to decide in which mode we want to run it either periodic or one-shot . Let’s run the timer in a periodic way so we use the  esp_timer_start_periodic() function.

ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 500000));

The called function definition is

 /*Timer should not be running when this function is called.
* @param timer timer handle created using esp_timer_create
* @param period timer period, in microseconds
*/

esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);

At the esp_timer_create_args_t type periodic_timer_args variable we assigned the callback member to a function named periodic_timer_callback . this is the function which will be called back periodically . we need to implement the callback in our C file but the function signature should be like

typedef void (*esp_timer_cb_t)(void* arg);

Here is our implementation . we have put a debug msg to better visualize the timer in operation.

static void periodic_timer_callback(void* arg)
{
   
int64_t time_since_boot = esp_timer_get_time();
   ESP_LOGI(TAG,
"Periodic timer called, time since boot: %lld us", time_since_boot);
}

This callback function prints the time since boot , periodically

In a similar way the example code creates one-shot type timer and runs it . you can run and see it’s operation.

Additional Note

If your application is a low power device and relies upon esp32 hardware timer then do take note of the following cases.

  • Light sleep does not impact timer period. So after light sleep  esp_timer_get_time() function returns accurate time.
  • But Note during the light sleep the periodic timer & one shot timer callbacks do not execute since the CPU is not running during the light sleep. After waking up the callbacks get immediately fired up .


Reference

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

0 comments:

Post a Comment

Categories

Pages

Firmware Engineer

My photo
Works on Firmware, Embedded Linux, Smart Metering, RTOS, IoT backend

Contact Form

Name

Email *

Message *

Copyrighted by Hassin. Powered by Blogger.