6#include <driver/ledc.h>
9#define CLOCK_FREQUENCY 80e6f
11#ifdef SOC_LEDC_SUPPORT_APB_CLOCK
12#define DEFAULT_CLK LEDC_USE_APB_CLK
14#define DEFAULT_CLK LEDC_AUTO_CLK
17static const uint8_t SETUP_ATTEMPT_COUNT_MAX = 5;
22static const char *
const TAG =
"ledc.output";
24static const int MAX_RES_BITS = LEDC_TIMER_BIT_MAX - 1;
25#if SOC_LEDC_SUPPORT_HS_MODE
27inline ledc_mode_t
get_speed_mode(uint8_t channel) {
return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; }
32inline ledc_mode_t
get_speed_mode(uint8_t) {
return LEDC_LOW_SPEED_MODE; }
36 return static_cast<float>(CLOCK_FREQUENCY) /
static_cast<float>(1 << bit_depth);
40 const float max_div_num = ((1 << MAX_RES_BITS) - 1) / (low_frequency ? 32.0f : 256.0f);
41 return static_cast<float>(CLOCK_FREQUENCY) / (max_div_num *
static_cast<float>(1 << bit_depth));
45 ESP_LOGV(TAG,
"Calculating resolution bit-depth for frequency %f",
frequency);
46 for (
int i = MAX_RES_BITS; i >= 1; i--) {
50 ESP_LOGV(TAG,
"Resolution calculated as %d", i);
58 uint8_t channel, uint8_t &bit_depth,
float frequency) {
61 ESP_LOGE(TAG,
"Frequency %f can't be achieved with any bit depth",
frequency);
64 ledc_timer_config_t timer_conf{};
65 timer_conf.speed_mode = speed_mode;
66 timer_conf.duty_resolution =
static_cast<ledc_timer_bit_t
>(bit_depth);
67 timer_conf.timer_num = timer_num;
68 timer_conf.freq_hz = (uint32_t)
frequency;
69 timer_conf.clk_cfg = DEFAULT_CLK;
72 int attempt_count_max = SETUP_ATTEMPT_COUNT_MAX;
73 esp_err_t init_result = ESP_FAIL;
74 while (attempt_count_max > 0 && init_result != ESP_OK) {
75 init_result = ledc_timer_config(&timer_conf);
76 if (init_result != ESP_OK) {
77 ESP_LOGW(TAG,
"Unable to initialize timer with frequency %.1f and bit depth of %u",
frequency, bit_depth);
79 timer_conf.duty_resolution =
static_cast<ledc_timer_bit_t
>(--bit_depth);
88 return static_cast<int>(angle * ((1U << bit_depth) - 1) / 360.0f);
93 ESP_LOGW(TAG,
"Not yet initialized");
101 const uint32_t max_duty = (uint32_t(1) << this->
bit_depth_) - 1;
102 const float duty_rounded = roundf(
state * max_duty);
103 auto duty =
static_cast<uint32_t
>(duty_rounded);
104 ESP_LOGV(TAG,
"Setting duty: %" PRIu32
" on channel %u", duty, this->
channel_);
106 auto chan_num =
static_cast<ledc_channel_t
>(this->
channel_ % 8);
108 if (duty == max_duty) {
109 ledc_stop(speed_mode, chan_num, 1);
110 }
else if (duty == 0) {
111 ledc_stop(speed_mode, chan_num, 0);
113 ledc_set_duty_with_hpoint(speed_mode, chan_num, duty, hpoint);
114 ledc_update_duty(speed_mode, chan_num);
120 auto timer_num =
static_cast<ledc_timer_t
>((this->
channel_ % 8) / 2);
121 auto chan_num =
static_cast<ledc_channel_t
>(this->
channel_ % 8);
123 esp_err_t timer_init_result =
126 if (timer_init_result != ESP_OK) {
127 ESP_LOGE(TAG,
"Frequency %f can't be achieved with computed bit depth %u", this->
frequency_, this->
bit_depth_);
133 ESP_LOGV(TAG,
"Configured frequency %f with a bit depth of %u bits", this->
frequency_, this->
bit_depth_);
134 ESP_LOGV(TAG,
"Angle of %.1f° results in hpoint %u", this->
phase_angle_, hpoint);
136 ledc_channel_config_t chan_conf{};
138 chan_conf.speed_mode = speed_mode;
139 chan_conf.channel = chan_num;
140 chan_conf.intr_type = LEDC_INTR_DISABLE;
141 chan_conf.timer_sel = timer_num;
143 chan_conf.hpoint = hpoint;
144 ledc_channel_config(&chan_conf);
150 ESP_LOGCONFIG(TAG,
"Output:");
151 LOG_PIN(
" Pin ", this->
pin_);
154 " PWM Frequency: %.1f Hz\n"
155 " Phase angle: %.1f°\n"
159 ESP_LOGV(TAG,
" Min frequency for bit depth: %f",
162 ESP_LOGV(TAG,
" Min frequency for bit depth-1: %f",
165 ESP_LOGV(TAG,
" Min frequency for bit depth+1: %f",
167 ESP_LOGV(TAG,
" Max res bits: %d", MAX_RES_BITS);
168 ESP_LOGV(TAG,
" Clock frequency: %f", CLOCK_FREQUENCY);
173 if (!bit_depth_opt.has_value()) {
174 ESP_LOGE(TAG,
"Frequency %f can't be achieved with any bit depth", this->
frequency_);
181 ESP_LOGW(TAG,
"Not yet initialized");
186 auto timer_num =
static_cast<ledc_timer_t
>((this->
channel_ % 8) / 2);
187 auto chan_num =
static_cast<ledc_channel_t
>(this->
channel_ % 8);
189 esp_err_t timer_init_result =
192 if (timer_init_result != ESP_OK) {
193 ESP_LOGE(TAG,
"Frequency %f can't be achieved with computed bit depth %u", this->
frequency_, this->
bit_depth_);
void status_clear_error()
void status_set_error(const char *message=nullptr)
virtual uint8_t get_pin() const =0
virtual bool is_inverted() const =0
void update_frequency(float frequency) override
Dynamically change frequency at runtime.
void setup() override
Setup LEDC.
void write_state(float state) override
Override FloatOutput's write_state.
void dump_config() override
esp_err_t configure_timer_frequency(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_channel_t chan_num, uint8_t channel, uint8_t &bit_depth, float frequency)
uint8_t next_ledc_channel
optional< uint8_t > ledc_bit_depth_for_frequency(float frequency)
constexpr int ledc_angle_to_htop(float angle, uint8_t bit_depth)
float ledc_min_frequency_for_bit_depth(uint8_t bit_depth, bool low_frequency)
ledc_mode_t get_speed_mode(uint8_t channel)
float ledc_max_frequency_for_bit_depth(uint8_t bit_depth)
Providing packet encoding functions for exchanging data with a remote host.