You can also program the timers using the native IDF APIs:
#include "Arduino.h"
#include "driver/gptimer.h"
void BlinkingTask(void *params);
bool timerCallback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data);
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("Starting");
xTaskCreatePinnedToCore(BlinkingTask, "Blinking", 1000, NULL, 5, NULL, ARDUINO_RUNNING_CORE);
}
void loop() {
vTaskDelete(NULL);
}
void BlinkingTask(void *params) {
TaskHandle_t myTaskHandle { xTaskGetCurrentTaskHandle() };
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
gptimer_handle_t gptimer = NULL;
const gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1000000, // 1MHz, 1 tick=1us
};
assert((gptimer_new_timer(&timer_config, &gptimer)==ESP_OK) && "Failed to Create Timer");
gptimer_event_callbacks_t cbs = {
.on_alarm = timerCallback,
};
assert((gptimer_register_event_callbacks(gptimer, &cbs, static_cast<void*>(myTaskHandle))==ESP_OK) && "Failed to Register Callback");
assert((gptimer_enable(gptimer)==ESP_OK) && "Failed to Enable Timer");
gptimer_alarm_config_t alarm_config ={1000000, 0, true};
assert((gptimer_set_alarm_action(gptimer, &alarm_config)==ESP_OK) && "Failed to Set Alarm Action");
assert((gptimer_start(gptimer)==ESP_OK) && "Failed to Start Timer");
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
digitalWrite(4, HIGH);
vTaskDelay(5);
digitalWrite(4, LOW);
}
}
bool IRAM_ATTR timerCallback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) {
TaskHandle_t handle { static_cast<TaskHandle_t>(user_data) };
BaseType_t pxHigherPriorityTaskWoken { pdFALSE };
vTaskNotifyGiveFromISR(handle, &pxHigherPriorityTaskWoken);
return pxHigherPriorityTaskWoken == pdTRUE;
}