ESP32 Tutorial – Using xTimer
Contents
Introduction
ESP32 is a low-power Wi-Fi and Bluetooth dual-mode SoC developed by Espressif Systems, while FreeRTOS is an open source real-time operating system kernel for microcontrollers. When the two are used together, ESP32 can leverage FreeRTOS to achieve multi-task scheduling and improve the real-time performance of applications.
xTimer is a powerful timer tool in FreeRTOS for implementing precise delays and timing operations on ESP32.
xTimer Function
xTimer is a flexible and efficient way to handle software timers. Software timers allow you to set a timer that executes a callback function after a specified amount of time. This is useful for applications that require periodic tasks or delayed operations.
How To Use xTimer
1. Create and initialize timers.
2. Set timer parameters.
3. Start the timer.
4. Stop the timer.
xTimer Functions
1. xTimerCreate: Create a software timer.
2. xTimerStart: Start the timer.
3. xTimerStop: Stop the timer.
4. xTimerChangePeriod: Change the period of the timer.
5. xTimerReset: Reset the timer and restart the timer.
6. xTimerDelete: Delete the timer.
7. xTimerGetPeriod: Get the period of the timer.
8. xTimerGetExpiryTime: Get the next expiration time of the timer.
9. xTimerGetTimerDaemonTaskHandle: Get the handle of the timer daemon task.
10. pvTimerGetTimerID: Get the ID of the timer.
11. vTimerSetTimerID: Set the ID of the timer.
12. xTimerPendFunctionCall: Execute a function that will run in the context of the timer daemon task.
Install VSCode & ESP-IDF VSCode Extension
Make sure you have installed and configured the ESP-IDF development environment. You can also refer to the article the ESP32 Tutorial – ESP-IDF With VSCode.
Create A New ESP32 Project
We can use VSCode's IDF plug-in to create a new ESP32 project. Please refer to ESP32 Tutorial – How To Create An ESP32 Project With VSCode.
xTimer Functions Example
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "esp_log.h"
#define TAG "xtimer_example"
// Counter to track the number of timer callbacks
static int callback_count = 0;
static const int stop_after_count = 4;
// Callback function
void timer_callback(TimerHandle_t xTimer) {
callback_count++;
ESP_LOGI(TAG, "Timer expired! Callback count: %d", callback_count);
// Stop the timer after 4 callbacks
if (callback_count >= stop_after_count) {
if (xTimerStop(xTimer, 0) != pdPASS) {
ESP_LOGE(TAG, "Timer stop failed!");
} else {
ESP_LOGI(TAG, "Timer stopped after %d callbacks", stop_after_count);
}
}
}
// Function to be executed in the timer daemon task context
void pendingFunction(void *pvParameter1, uint32_t ulParameter2) {
ESP_LOGI(TAG, "Pending function called with param1: %p, param2: %d", pvParameter1, ulParameter2);
}
void app_main() {
// Create a software timer
TimerHandle_t xTimer = xTimerCreate(
"Timer", // Timer name
pdMS_TO_TICKS(1000), // Timer period in ticks (milliseconds to ticks)
pdTRUE, // Auto-reload flag
(void *) 0, // Timer ID
timer_callback // Callback function
);
if (xTimer == NULL) {
ESP_LOGE(TAG, "Timer creation failed!");
return;
}
// Start the timer
if (xTimerStart(xTimer, 0) != pdPASS) {
ESP_LOGE(TAG, "Timer start failed!");
}
// Change the timer period to 2000 ticks (assuming 1 tick = 1 millisecond)
if (xTimerChangePeriod(xTimer, pdMS_TO_TICKS(2000), 0) != pdPASS) {
ESP_LOGE(TAG, "Timer change period failed!");
}
// Get the timer period
TickType_t period = xTimerGetPeriod(xTimer);
ESP_LOGI(TAG, "Timer period: %d ticks", period);
// Get the timer expiry time
TickType_t expiryTime = xTimerGetExpiryTime(xTimer);
ESP_LOGI(TAG, "Timer expiry time: %d ticks", expiryTime);
// Set and get the timer ID
void *newTimerID = (void *)111;
vTimerSetTimerID(xTimer, newTimerID);
void *timerID = pvTimerGetTimerID(xTimer);
ESP_LOGI(TAG, "Timer ID: %p", timerID);
// Call a function in the timer daemon task context
if (xTimerPendFunctionCall(pendingFunction, (void *)0xFFF, 111, 0) != pdPASS) {
ESP_LOGE(TAG, "Pending function call failed!");
}
// Get the timer daemon task handle
TaskHandle_t timerDaemonTaskHandle = xTimerGetTimerDaemonTaskHandle();
ESP_LOGI(TAG, "Timer daemon task handle: %p", timerDaemonTaskHandle);
}
Compile, Flash & Monitor
Find the "ESP32-IDF: Build, Flash and Monitor" ICON in VSCode to execute and burn.
Results
We can view the printing results on the terminal, as follows...
I (306) xtimer_example: Timer period: 100 ticks
I (316) xtimer_example: Timer expiry time: 1073407732 ticks
I (316) xtimer_example: Timer ID: 0x6f
I (326) xtimer_example: Timer daemon task handle: 0x3ffb6b48
I (326) xtimer_example: Pending function called with param1: 0xfff, param2: 111
I (2326) xtimer_example: Timer expired! Callback count: 1
I (4326) xtimer_example: Timer expired! Callback count: 2
I (6326) xtimer_example: Timer expired! Callback count: 3
I (8326) xtimer_example: Timer expired! Callback count: 4
I (8326) xtimer_example: Timer stopped after 4 callbacks
Conclusion
The accuracy of the ESP32's FreeRTOS timer depends on the system's tick frequency, which is typically 1ms. Make sure you manage memory properly when creating and deleting timers to avoid memory leaks. The callback function should perform fast and non-blocking operations and avoid running for a long time, so as not to affect the scheduling of other tasks in the system.