support esp-idf 5.x

This commit is contained in:
Anton Viktorov 2024-07-15 15:06:02 +02:00
parent 8a077fbe40
commit 65f61f29e0
3 changed files with 180 additions and 3 deletions

View file

@ -13,6 +13,7 @@
#endif
#ifdef USE_ESP32_FRAMEWORK_ESP_IDF
#include "esp_idf_version.h"
#include "hw_timer_esp_idf.h"
#endif
@ -195,7 +196,8 @@ void AcDimmer::setup() {
// PWM and AcDimmer can even run at the same time this way
setTimer1Callback(&timer_interrupt);
#endif
#ifdef USE_ESP32
#if USE_ESP32 && (ESP_IDF_VERSION_MAJOR == 4)
// 80 Divider -> 1 count=1µs
dimmer_timer = timerBegin(0, 80, true);
timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr, true);
@ -205,6 +207,16 @@ void AcDimmer::setup() {
timerAlarmWrite(dimmer_timer, 50, true);
timerAlarmEnable(dimmer_timer);
#endif
#if USE_ESP32 && (ESP_IDF_VERSION_MAJOR == 5)
// 1 MHz -> 1 count=1µs
dimmer_timer = timerBegin(1000000);
timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr);
// For ESP32, we can't use dynamic interval calculation because the timerX functions
// are not callable from ISR (placed in flash storage).
// Here we just use an interrupt firing every 50 µs.
timerAlarm(dimmer_timer, 50, true, 0);
timerStart(dimmer_timer);
#endif
}
void AcDimmer::write_state(float state) {

View file

@ -4,7 +4,18 @@
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#if (ESP_IDF_VERSION_MAJOR == 4)
#include "esp32/clk.h"
#endif
#if (ESP_IDF_VERSION_MAJOR == 5)
#include "driver/gptimer.h"
#if defined __has_include && __has_include("clk_tree.h")
#include "clk_tree.h"
#else
#include "esp_clk_tree.h"
#endif
#endif
#include "esphome/core/log.h"
@ -13,6 +24,8 @@ static const char *const TAG = "hw_timer_esp_idf";
namespace esphome {
namespace ac_dimmer {
#if (ESP_IDF_VERSION_MAJOR == 4)
#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS
typedef union {
@ -195,8 +208,125 @@ uint32_t timerGetConfig(hw_timer_t *timer) {
return cfg.val;
}
#endif // (ESP_IDF_VERSION_MAJOR == 4)
#if (ESP_IDF_VERSION_MAJOR == 5)
interrupt_config_t *timer_intr_config = NULL;
hw_timer_t *timerBegin(uint32_t frequency) {
esp_err_t err = ESP_OK;
uint32_t counter_src_hz = 0;
uint32_t divider = 0;
// soc_periph_gptimer_clk_src_t clk;
int clk;
// soc_periph_gptimer_clk_src_t gptimer_clks[] = SOC_GPTIMER_CLKS;
int gptimer_clks[] = SOC_GPTIMER_CLKS;
for (size_t i = 0; i < sizeof(gptimer_clks) / sizeof(gptimer_clks[0]); i++) {
clk = gptimer_clks[i];
#if defined __has_include && __has_include("clk_tree.h")
clk_tree_src_get_freq_hz((soc_module_clk_t) clk, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz);
#else
esp_clk_tree_src_get_freq_hz((soc_module_clk_t) clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz);
#endif
divider = counter_src_hz / frequency;
if ((divider >= 2) && (divider <= 65536)) {
break;
} else {
divider = 0;
}
}
if (divider == 0) {
ESP_LOGE(TAG, "Resolution cannot be reached with any clock source, aborting!");
return NULL;
}
gptimer_config_t config = {
.clk_src = (gptimer_clock_source_t) clk,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = frequency,
.intr_priority = 0,
.flags = {.intr_shared = true},
};
hw_timer_t *timer = (hw_timer_t *) malloc(sizeof(hw_timer_t));
err = gptimer_new_timer(&config, &timer->timer_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to create a new GPTimer, error num=%d", err);
free(timer);
return NULL;
}
gptimer_enable(timer->timer_handle);
gptimer_start(timer->timer_handle);
timer->timer_started = true;
return timer;
}
bool IRAM_ATTR timerFnWrapper(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *args) {
interrupt_config_t *isr = (interrupt_config_t *) args;
if (isr->fn) {
if (isr->arg) {
((voidFuncPtrArg) isr->fn)(isr->arg);
} else {
isr->fn();
}
}
// some additional logic or handling may be required here to appropriately yield or not
return false;
}
void timerAttachInterruptFunctionalArg(hw_timer_t *timer, void (*userFunc)(void *), void *arg) {
esp_err_t err = ESP_OK;
gptimer_event_callbacks_t cbs = {
.on_alarm = timerFnWrapper,
};
timer->interrupt_handle.fn = (voidFuncPtr) userFunc;
timer->interrupt_handle.arg = arg;
if (timer->timer_started == true) {
gptimer_stop(timer->timer_handle);
}
gptimer_disable(timer->timer_handle);
err = gptimer_register_event_callbacks(timer->timer_handle, &cbs, &timer->interrupt_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Timer Attach Interrupt failed, error num=%d", err);
}
gptimer_enable(timer->timer_handle);
if (timer->timer_started == true) {
gptimer_start(timer->timer_handle);
}
}
void timerAttachInterrupt(hw_timer_t *timer, voidFuncPtr userFunc) {
timerAttachInterruptFunctionalArg(timer, (voidFuncPtrArg) userFunc, NULL);
}
void timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
esp_err_t err = ESP_OK;
gptimer_alarm_config_t alarm_cfg = {
.alarm_count = alarm_value,
.reload_count = reload_count,
.flags = {.auto_reload_on_alarm = autoreload},
};
err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Timer Alarm Write failed, error num=%d", err);
}
}
void timerStart(hw_timer_t *timer) {
gptimer_start(timer->timer_handle);
timer->timer_started = true;
}
#endif // (ESP_IDF_VERSION_MAJOR == 5)
} // namespace ac_dimmer
} // namespace esphome
#endif
#endif

View file

@ -1,9 +1,20 @@
#pragma once
#ifdef USE_ESP32_FRAMEWORK_ESP_IDF
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION_MAJOR == 4)
#include "driver/timer.h"
#endif
#if (ESP_IDF_VERSION_MAJOR == 5)
#include "driver/gptimer_types.h"
#endif
namespace esphome {
namespace ac_dimmer {
#if (ESP_IDF_VERSION_MAJOR == 4)
typedef struct hw_timer_s {
timer_group_t group;
timer_idx_t num;
@ -21,8 +32,32 @@ void timerStop(hw_timer_t *timer);
uint32_t timerGetConfig(hw_timer_t *timer);
uint16_t timerGetDivider(hw_timer_t *timer);
void timerSetDivider(hw_timer_t *timer, uint16_t divider);
#endif
#if (ESP_IDF_VERSION_MAJOR == 5)
typedef void (*voidFuncPtr)(void);
typedef void (*voidFuncPtrArg)(void *);
struct interrupt_config_t {
voidFuncPtr fn;
void *arg;
};
struct hw_timer_t {
gptimer_handle_t timer_handle;
interrupt_config_t interrupt_handle;
bool timer_started;
};
hw_timer_t *timerBegin(uint32_t frequency);
void timerAttachInterrupt(hw_timer_t *timer, void (*userFunc)(void));
void timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count);
void timerStart(hw_timer_t *timer);
#endif
} // namespace ac_dimmer
} // namespace esphome
#endif
#endif