ac_dimmer esp-idf

This commit is contained in:
Anton Viktorov 2024-07-10 05:17:52 +02:00
parent 894d81c577
commit d934ebbd0e
5 changed files with 150 additions and 9 deletions

View file

@ -1,4 +1,3 @@
#ifdef USE_ARDUINO
#include "ac_dimmer.h"
#include "esphome/core/helpers.h"
@ -8,10 +7,15 @@
#ifdef USE_ESP8266
#include <core_esp8266_waveform.h>
#endif
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include <esp32-hal-timer.h>
#endif
#ifdef USE_ESP32_FRAMEWORK_ESP_IDF
#include "esp32-hw-timer.h"
#endif
namespace esphome {
namespace ac_dimmer {
@ -191,7 +195,7 @@ void AcDimmer::setup() {
// PWM and AcDimmer can even run at the same time this way
setTimer1Callback(&timer_interrupt);
#endif
#ifdef USE_ESP32
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
// 80 Divider -> 1 count=1µs
dimmer_timer = timerBegin(0, 80, true);
timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr, true);
@ -201,6 +205,16 @@ void AcDimmer::setup() {
timerAlarmWrite(dimmer_timer, 50, true);
timerAlarmEnable(dimmer_timer);
#endif
#ifdef USE_ESP32_FRAMEWORK_ESP_IDF
// 80 Divider -> 1 count=1µs
dimmer_timer = EspIdfTimer::timerBegin(0, 80, true);
EspIdfTimer::timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr, true);
// 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.
EspIdfTimer::timerAlarmWrite(dimmer_timer, 50, true);
EspIdfTimer::timerAlarmEnable(dimmer_timer);
#endif
}
void AcDimmer::write_state(float state) {
state = std::acos(1 - (2 * state)) / 3.14159; // RMS power compensation
@ -229,5 +243,3 @@ void AcDimmer::dump_config() {
} // namespace ac_dimmer
} // namespace esphome
#endif // USE_ARDUINO

View file

@ -1,7 +1,5 @@
#pragma once
#ifdef USE_ARDUINO
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/components/output/float_output.h"
@ -66,5 +64,3 @@ class AcDimmer : public output::FloatOutput, public Component {
} // namespace ac_dimmer
} // namespace esphome
#endif // USE_ARDUINO

View file

@ -0,0 +1,110 @@
#include "esp32-hw-timer.h"
// #include "soc/soc_caps.h"
// #include "esp_clk.h"
// #include "esp32/clk.h"
#include "esphome/core/log.h"
static const char *const TAG = "esp32-hal-timer";
namespace esphome {
namespace ac_dimmer {
typedef union {
struct {
uint32_t reserved0 : 10;
uint32_t alarm_en : 1; /*When set alarm is enabled*/
uint32_t level_int_en : 1; /*When set level type interrupt will be generated during alarm*/
uint32_t edge_int_en : 1; /*When set edge type interrupt will be generated during alarm*/
uint32_t divider : 16; /*Timer clock (T0/1_clk) pre-scale value.*/
uint32_t autoreload : 1; /*When set timer 0/1 auto-reload at alarming is enabled*/
uint32_t increase : 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter
decrement.*/
uint32_t enable : 1; /*When set timer 0/1 time-base counter is enabled*/
};
uint32_t val;
} timer_cfg_t;
#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS
// Works for all chips
static hw_timer_t timer_dev[4] = {
{TIMER_GROUP_0, TIMER_0}, {TIMER_GROUP_1, TIMER_0}, {TIMER_GROUP_0, TIMER_1}, {TIMER_GROUP_1, TIMER_1}};
// NOTE: (in IDF 5.0 there wont be need to know groups/numbers
// timer_init() will list thru all timers and return free timer handle)
// uint32_t getApbFrequency() {
// // rtc_clk_apb_freq_get();
// return esp_clk_apb_freq();
// }
// static void _on_apb_change(void *arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb) {
// hw_timer_t *timer = (hw_timer_t *) arg;
// if (ev_type == APB_BEFORE_CHANGE) {
// timerStop(timer);
// } else {
// old_apb /= 1000000;
// new_apb /= 1000000;
// uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb;
// timerSetDivider(timer, divider);
// timerStart(timer);
// }
// }
hw_timer_t *EspIdfTimer::timerBegin(uint8_t num, uint16_t divider, bool countUp) {
if (num >= NUM_OF_TIMERS) {
ESP_LOGE(TAG, "Timer number %u exceeds available number of Timers.", num);
return NULL;
}
hw_timer_t *timer = &timer_dev[num]; // Get Timer group/num from 0-3 number
timer_config_t config = {
.alarm_en = TIMER_ALARM_DIS,
.counter_en = TIMER_PAUSE,
.intr_type = TIMER_INTR_LEVEL,
.counter_dir = static_cast<timer_count_dir_t>(countUp),
.auto_reload = timer_autoreload_t::TIMER_AUTORELOAD_DIS,
.divider = divider,
};
timer_init(timer->group, timer->num, &config);
timer_set_counter_value(timer->group, timer->num, 0);
EspIdfTimer::timerStart(timer);
// addApbChangeCallback(timer, _on_apb_change);
return timer;
}
bool IRAM_ATTR timerFnWrapper(void *arg) {
void (*fn)(void) = (void (*)()) arg;
fn();
// some additional logic or handling may be required here to approriately yield or not
return false;
}
void EspIdfTimer::timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge) {
if (edge) {
ESP_LOGW(TAG, "EDGE timer interrupt is not supported! Setting to LEVEL...");
}
timer_isr_callback_add(timer->group, timer->num, (bool (*)(void *)) timerFnWrapper, (void *) fn, 0);
}
void EspIdfTimer::timerStart(hw_timer_t *timer) { timer_start(timer->group, timer->num); }
void EspIdfTimer::timerAlarmEnable(hw_timer_t *timer) { timer_set_alarm(timer->group, timer->num, TIMER_ALARM_EN); }
void EspIdfTimer::timerAlarmDisable(hw_timer_t *timer) { timer_set_alarm(timer->group, timer->num, TIMER_ALARM_DIS); }
void EspIdfTimer::timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload) {
timer_set_alarm_value(timer->group, timer->num, alarm_value);
timerSetAutoReload(timer, autoreload);
}
void EspIdfTimer::timerSetAutoReload(hw_timer_t *timer, bool autoreload) {
timer_set_auto_reload(timer->group, timer->num, (timer_autoreload_t) autoreload);
}
} // namespace ac_dimmer
} // namespace esphome

View file

@ -0,0 +1,24 @@
#pragma once
#include "driver/timer.h"
namespace esphome {
namespace ac_dimmer {
typedef struct hw_timer_s {
timer_group_t group;
timer_idx_t num;
} hw_timer_t;
class EspIdfTimer {
public:
static hw_timer_t *timerBegin(uint8_t timer, uint16_t divider, bool countUp);
static void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
static void timerAlarmEnable(hw_timer_t *timer);
static void timerAlarmDisable(hw_timer_t *timer);
static void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload);
static void timerSetAutoReload(hw_timer_t *timer, bool autoreload);
static void timerStart(hw_timer_t *timer);
};
} // namespace ac_dimmer
} // namespace esphome

View file

@ -31,7 +31,6 @@ CONFIG_SCHEMA = cv.All(
),
}
).extend(cv.COMPONENT_SCHEMA),
cv.only_with_arduino,
)