mirror of
https://github.com/esphome/esphome.git
synced 2026-09-15 09:08:41 +00:00
[opentherm] Migrate from legacy timer API to GPTimer API (#14859)
This commit is contained in:
@@ -81,10 +81,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
|
||||
async def to_code(config: dict[str, Any]) -> None:
|
||||
if CORE.is_esp32:
|
||||
# Re-enable ESP-IDF's legacy driver component (excluded by default to save compile time)
|
||||
# Provides driver/timer.h header for hardware timer API
|
||||
# TODO: Remove this once opentherm migrates to GPTimer API (driver/gptimer.h)
|
||||
include_builtin_idf_component("driver")
|
||||
include_builtin_idf_component("esp_driver_gptimer")
|
||||
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
#include "opentherm.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <cinttypes>
|
||||
// TODO: Migrate from legacy timer API (driver/timer.h) to GPTimer API (driver/gptimer.h)
|
||||
// The legacy timer API is deprecated in ESP-IDF 5.x. See opentherm.h for details.
|
||||
#ifdef USE_ESP32
|
||||
#include "driver/timer.h"
|
||||
#include "esp_err.h"
|
||||
#endif
|
||||
#ifdef ESP8266
|
||||
@@ -33,10 +30,6 @@ OpenTherm *OpenTherm::instance = nullptr;
|
||||
OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout)
|
||||
: in_pin_(in_pin),
|
||||
out_pin_(out_pin),
|
||||
#ifdef USE_ESP32
|
||||
timer_group_(TIMER_GROUP_0),
|
||||
timer_idx_(TIMER_0),
|
||||
#endif
|
||||
mode_(OperationMode::IDLE),
|
||||
error_type_(ProtocolErrorType::NO_ERROR),
|
||||
capture_(0),
|
||||
@@ -134,7 +127,12 @@ void IRAM_ATTR OpenTherm::read_() {
|
||||
// period in OpenTherm.
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32
|
||||
bool IRAM_ATTR OpenTherm::timer_isr(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx) {
|
||||
auto *arg = static_cast<OpenTherm *>(user_ctx);
|
||||
#else
|
||||
bool IRAM_ATTR OpenTherm::timer_isr(OpenTherm *arg) {
|
||||
#endif
|
||||
if (arg->mode_ == OperationMode::LISTEN) {
|
||||
if (arg->timeout_counter_ == 0) {
|
||||
arg->mode_ = OperationMode::ERROR_TIMEOUT;
|
||||
@@ -243,67 +241,35 @@ void IRAM_ATTR OpenTherm::write_bit_(uint8_t high, uint8_t clock) {
|
||||
#ifdef USE_ESP32
|
||||
|
||||
bool OpenTherm::init_esp32_timer_() {
|
||||
// Search for a free timer. Maybe unstable, we'll see.
|
||||
int cur_timer = 0;
|
||||
timer_group_t timer_group = TIMER_GROUP_0;
|
||||
timer_idx_t timer_idx = TIMER_0;
|
||||
bool timer_found = false;
|
||||
|
||||
for (; cur_timer < SOC_TIMER_GROUP_TOTAL_TIMERS; cur_timer++) {
|
||||
timer_config_t temp_config;
|
||||
timer_group = cur_timer < 2 ? TIMER_GROUP_0 : TIMER_GROUP_1;
|
||||
timer_idx = cur_timer < 2 ? (timer_idx_t) cur_timer : (timer_idx_t) (cur_timer - 2);
|
||||
|
||||
auto err = timer_get_config(timer_group, timer_idx, &temp_config);
|
||||
if (err == ESP_ERR_INVALID_ARG) {
|
||||
// Error means timer was not initialized (or other things, but we are careful with our args)
|
||||
timer_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Timer %d:%d seems to be occupied, will try another", timer_group, timer_idx);
|
||||
}
|
||||
|
||||
if (!timer_found) {
|
||||
ESP_LOGE(TAG, "No free timer was found! OpenTherm cannot function without a timer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Found free timer %d:%d", timer_group, timer_idx);
|
||||
this->timer_group_ = timer_group;
|
||||
this->timer_idx_ = timer_idx;
|
||||
|
||||
timer_config_t const config = {
|
||||
.alarm_en = TIMER_ALARM_EN,
|
||||
.counter_en = TIMER_PAUSE,
|
||||
.intr_type = TIMER_INTR_LEVEL,
|
||||
.counter_dir = TIMER_COUNT_UP,
|
||||
.auto_reload = TIMER_AUTORELOAD_EN,
|
||||
.clk_src = TIMER_SRC_CLK_DEFAULT,
|
||||
.divider = 80,
|
||||
// 80MHz / 80 = 1MHz resolution (1µs per tick)
|
||||
gptimer_config_t config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = 1000000,
|
||||
};
|
||||
|
||||
esp_err_t result;
|
||||
|
||||
result = timer_init(this->timer_group_, this->timer_idx_, &config);
|
||||
esp_err_t result = gptimer_new_timer(&config, &this->timer_handle_);
|
||||
if (result != ESP_OK) {
|
||||
const auto *error = esp_err_to_name(result);
|
||||
ESP_LOGE(TAG, "Failed to init timer. Error: %s", error);
|
||||
ESP_LOGE(TAG, "Failed to create timer: %s", esp_err_to_name(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0);
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = OpenTherm::timer_isr,
|
||||
};
|
||||
result = gptimer_register_event_callbacks(this->timer_handle_, &cbs, this);
|
||||
if (result != ESP_OK) {
|
||||
const auto *error = esp_err_to_name(result);
|
||||
ESP_LOGE(TAG, "Failed to set counter value. Error: %s", error);
|
||||
ESP_LOGE(TAG, "Failed to register timer callback: %s", esp_err_to_name(result));
|
||||
gptimer_del_timer(this->timer_handle_);
|
||||
this->timer_handle_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = timer_isr_callback_add(this->timer_group_, this->timer_idx_, reinterpret_cast<bool (*)(void *)>(timer_isr),
|
||||
this, 0);
|
||||
result = gptimer_enable(this->timer_handle_);
|
||||
if (result != ESP_OK) {
|
||||
const auto *error = esp_err_to_name(result);
|
||||
ESP_LOGE(TAG, "Failed to register timer interrupt. Error: %s", error);
|
||||
ESP_LOGE(TAG, "Failed to enable timer: %s", esp_err_to_name(result));
|
||||
gptimer_del_timer(this->timer_handle_);
|
||||
this->timer_handle_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -315,12 +281,13 @@ void IRAM_ATTR OpenTherm::start_esp32_timer_(uint64_t alarm_value) {
|
||||
this->timer_error_ = ESP_OK;
|
||||
this->timer_error_type_ = TimerErrorType::NO_TIMER_ERROR;
|
||||
|
||||
this->timer_error_ = timer_set_alarm_value(this->timer_group_, this->timer_idx_, alarm_value);
|
||||
this->alarm_config_.alarm_count = alarm_value;
|
||||
this->timer_error_ = gptimer_set_alarm_action(this->timer_handle_, &this->alarm_config_);
|
||||
if (this->timer_error_ != ESP_OK) {
|
||||
this->timer_error_type_ = TimerErrorType::SET_ALARM_VALUE_ERROR;
|
||||
return;
|
||||
}
|
||||
this->timer_error_ = timer_start(this->timer_group_, this->timer_idx_);
|
||||
this->timer_error_ = gptimer_start(this->timer_handle_);
|
||||
if (this->timer_error_ != ESP_OK) {
|
||||
this->timer_error_type_ = TimerErrorType::TIMER_START_ERROR;
|
||||
}
|
||||
@@ -356,12 +323,12 @@ void IRAM_ATTR OpenTherm::stop_timer_() {
|
||||
this->timer_error_ = ESP_OK;
|
||||
this->timer_error_type_ = TimerErrorType::NO_TIMER_ERROR;
|
||||
|
||||
this->timer_error_ = timer_pause(this->timer_group_, this->timer_idx_);
|
||||
this->timer_error_ = gptimer_stop(this->timer_handle_);
|
||||
if (this->timer_error_ != ESP_OK) {
|
||||
this->timer_error_type_ = TimerErrorType::TIMER_PAUSE_ERROR;
|
||||
return;
|
||||
}
|
||||
this->timer_error_ = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0);
|
||||
this->timer_error_ = gptimer_set_raw_count(this->timer_handle_, 0);
|
||||
if (this->timer_error_ != ESP_OK) {
|
||||
this->timer_error_type_ = TimerErrorType::SET_COUNTER_VALUE_ERROR;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,8 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
// TODO: Migrate from legacy timer API (driver/timer.h) to GPTimer API (driver/gptimer.h)
|
||||
// The legacy timer API is deprecated in ESP-IDF 5.x. Migration would allow removing the
|
||||
// "driver" IDF component dependency. See:
|
||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/peripherals.html#id4
|
||||
#ifdef USE_ESP32
|
||||
#include "driver/timer.h"
|
||||
#include "driver/gptimer.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
@@ -348,7 +344,11 @@ class OpenTherm {
|
||||
const char *operation_mode_to_str(OperationMode mode);
|
||||
const char *message_id_to_str(MessageId id);
|
||||
|
||||
#ifdef USE_ESP32
|
||||
static bool timer_isr(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);
|
||||
#else
|
||||
static bool timer_isr(OpenTherm *arg);
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
static void esp8266_timer_isr();
|
||||
@@ -361,8 +361,12 @@ class OpenTherm {
|
||||
ISRInternalGPIOPin isr_out_pin_;
|
||||
|
||||
#ifdef USE_ESP32
|
||||
timer_group_t timer_group_;
|
||||
timer_idx_t timer_idx_;
|
||||
gptimer_handle_t timer_handle_{nullptr};
|
||||
gptimer_alarm_config_t alarm_config_{
|
||||
.alarm_count = 0,
|
||||
.reload_count = 0,
|
||||
.flags = {.auto_reload_on_alarm = true},
|
||||
};
|
||||
#endif
|
||||
|
||||
OperationMode mode_;
|
||||
|
||||
Reference in New Issue
Block a user