// Listing 3.1 — General Purpose Timer LED Blink
#include <stdio.h>
#include "driver/gpio.h"
#include "driver/timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define LED_GPIO 6
#define TIMER_GROUP_USED TIMER_GROUP_0
#define TIMER_IDX_USED TIMER_0
#define APB_CLK_HZ 80000000UL // Typical APB clock on ESP32-S3
#define TIMER_DIVIDER 80 // Prescalar 80. So, APB/80 -> 1 MHz timer tick (1 tick = 1 us)
// Blink period in microseconds
#define BLINK_PERIOD_US 1000000UL // 1,000,000 us = 1 second
// --- ISR callback (called automatically at each alarm) ---
static bool IRAM_ATTR timer_isr_cb(void *args);
void app_main()
{
// Configure LED pin
gpio_reset_pin(LED_GPIO);
gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(LED_GPIO, 0);
// 1) Configure timer
timer_config_t tcfg = {
.divider = TIMER_DIVIDER,
.counter_dir = TIMER_COUNT_UP,
.counter_en = TIMER_PAUSE, // start paused; we'll start after setup
.alarm_en = TIMER_ALARM_EN,
.auto_reload = true // periodic alarm (repeats automatically)
};
timer_init(TIMER_GROUP_USED, TIMER_IDX_USED, &tcfg); // tcfg is the initialized timer instance
// Calculate the alarm tick count with this formula (works for any divider): ticks per us = [APB clock frequency / (Divider * 1000000)]
const uint64_t alarm_ticks =
((uint64_t)BLINK_PERIOD_US * (uint64_t)APB_CLK_HZ) /
((uint64_t)TIMER_DIVIDER * 1000000ULL);
// 2) Reset the Counter to initialize the counter to 0
timer_set_counter_value(TIMER_GROUP_USED, TIMER_IDX_USED, 0);
// 3) Set the alarm value using alarm_ticks
timer_set_alarm_value(TIMER_GROUP_USED, TIMER_IDX_USED, alarm_ticks);
// 4) Enable the Alarm
timer_set_alarm(TIMER_GROUP_USED, TIMER_IDX_USED, TIMER_ALARM_EN);
// 5) Attach ISR callback
timer_isr_callback_add(TIMER_GROUP_USED, TIMER_IDX_USED,
timer_isr_cb, NULL, 0);
// 6) Start timer
timer_start(TIMER_GROUP_USED, TIMER_IDX_USED);
// Main task is free to do other work (the LED blink is fully hardware-timed)
while (1) {
printf("Main task alive. LED blinks via timer ISR.\n");
vTaskDelay(pdMS_TO_TICKS(1000)); // periodic debug printing
}
}
// --- ISR callback (called automatically at each alarm) ---
static bool IRAM_ATTR timer_isr_cb(void *args)
{
static bool level = false;
level = !level;
gpio_set_level(LED_GPIO, level); // Toggle LED
return false;
}