ESPHome  2022.12.8
ledc_output.cpp
Go to the documentation of this file.
1 #include "ledc_output.h"
2 #include "esphome/core/log.h"
3 
4 #ifdef USE_ESP32
5 
6 #ifdef USE_ARDUINO
7 #include <esp32-hal-ledc.h>
8 #endif
9 #ifdef USE_ESP_IDF
10 #include <driver/ledc.h>
11 #endif
12 
13 namespace esphome {
14 namespace ledc {
15 
16 static const char *const TAG = "ledc.output";
17 
18 #ifdef USE_ESP_IDF
19 static const int MAX_RES_BITS = LEDC_TIMER_BIT_MAX - 1;
20 #if SOC_LEDC_SUPPORT_HS_MODE
21 // Only ESP32 has LEDC_HIGH_SPEED_MODE
22 inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; }
23 #else
24 // S2, C3, S3 only support LEDC_LOW_SPEED_MODE
25 // See
26 // https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/ledc.html#functionality-overview
27 inline ledc_mode_t get_speed_mode(uint8_t) { return LEDC_LOW_SPEED_MODE; }
28 #endif
29 #else
30 static const int MAX_RES_BITS = 20;
31 #endif
32 
33 float ledc_max_frequency_for_bit_depth(uint8_t bit_depth) { return 80e6f / float(1 << bit_depth); }
34 
35 float ledc_min_frequency_for_bit_depth(uint8_t bit_depth, bool low_frequency) {
36  const float max_div_num = ((1 << MAX_RES_BITS) - 1) / (low_frequency ? 32.0f : 256.0f);
37  return 80e6f / (max_div_num * float(1 << bit_depth));
38 }
39 
41  ESP_LOGD(TAG, "Calculating resolution bit-depth for frequency %f", frequency);
42  for (int i = MAX_RES_BITS; i >= 1; i--) {
43  const float min_frequency = ledc_min_frequency_for_bit_depth(i, (frequency < 100));
44  const float max_frequency = ledc_max_frequency_for_bit_depth(i);
45  if (min_frequency <= frequency && frequency <= max_frequency) {
46  ESP_LOGD(TAG, "Resolution calculated as %d", i);
47  return i;
48  }
49  }
50  return {};
51 }
52 
54  if (!initialized_) {
55  ESP_LOGW(TAG, "LEDC output hasn't been initialized yet!");
56  return;
57  }
58 
59  if (this->pin_->is_inverted())
60  state = 1.0f - state;
61 
62  this->duty_ = state;
63  const uint32_t max_duty = (uint32_t(1) << this->bit_depth_) - 1;
64  const float duty_rounded = roundf(state * max_duty);
65  auto duty = static_cast<uint32_t>(duty_rounded);
66 
67 #ifdef USE_ARDUINO
68  ledcWrite(this->channel_, duty);
69 #endif
70 #ifdef USE_ESP_IDF
71  auto speed_mode = get_speed_mode(channel_);
72  auto chan_num = static_cast<ledc_channel_t>(channel_ % 8);
73  ledc_set_duty(speed_mode, chan_num, duty);
74  ledc_update_duty(speed_mode, chan_num);
75 #endif
76 }
77 
79 #ifdef USE_ARDUINO
80  this->update_frequency(this->frequency_);
81  this->turn_off();
82  // Attach pin after setting default value
83  ledcAttachPin(this->pin_->get_pin(), this->channel_);
84 #endif
85 #ifdef USE_ESP_IDF
86  auto speed_mode = get_speed_mode(channel_);
87  auto timer_num = static_cast<ledc_timer_t>((channel_ % 8) / 2);
88  auto chan_num = static_cast<ledc_channel_t>(channel_ % 8);
89 
91  if (bit_depth_ < 1) {
92  ESP_LOGW(TAG, "Frequency %f can't be achieved with any bit depth", frequency_);
93  this->status_set_warning();
94  }
95 
96  ledc_timer_config_t timer_conf{};
97  timer_conf.speed_mode = speed_mode;
98  timer_conf.duty_resolution = static_cast<ledc_timer_bit_t>(bit_depth_);
99  timer_conf.timer_num = timer_num;
100  timer_conf.freq_hz = (uint32_t) frequency_;
101  timer_conf.clk_cfg = LEDC_AUTO_CLK;
102  ledc_timer_config(&timer_conf);
103 
104  ledc_channel_config_t chan_conf{};
105  chan_conf.gpio_num = pin_->get_pin();
106  chan_conf.speed_mode = speed_mode;
107  chan_conf.channel = chan_num;
108  chan_conf.intr_type = LEDC_INTR_DISABLE;
109  chan_conf.timer_sel = timer_num;
110  chan_conf.duty = inverted_ == pin_->is_inverted() ? 0 : (1U << bit_depth_);
111  chan_conf.hpoint = 0;
112  ledc_channel_config(&chan_conf);
113  initialized_ = true;
114 #endif
115 }
116 
118  ESP_LOGCONFIG(TAG, "LEDC Output:");
119  LOG_PIN(" Pin ", this->pin_);
120  ESP_LOGCONFIG(TAG, " LEDC Channel: %u", this->channel_);
121  ESP_LOGCONFIG(TAG, " Frequency: %.1f Hz", this->frequency_);
122 }
123 
125  auto bit_depth_opt = ledc_bit_depth_for_frequency(frequency);
126  if (!bit_depth_opt.has_value()) {
127  ESP_LOGW(TAG, "Frequency %f can't be achieved with any bit depth", frequency);
128  this->status_set_warning();
129  }
130  this->bit_depth_ = bit_depth_opt.value_or(8);
131  this->frequency_ = frequency;
132 #ifdef USE_ARDUINO
133  ledcSetup(this->channel_, frequency, this->bit_depth_);
134  initialized_ = true;
135 #endif // USE_ARDUINO
136 #ifdef USE_ESP_IDF
137  if (!initialized_) {
138  ESP_LOGW(TAG, "LEDC output hasn't been initialized yet!");
139  return;
140  }
141  auto speed_mode = get_speed_mode(channel_);
142  auto timer_num = static_cast<ledc_timer_t>((channel_ % 8) / 2);
143 
144  ledc_timer_config_t timer_conf{};
145  timer_conf.speed_mode = speed_mode;
146  timer_conf.duty_resolution = static_cast<ledc_timer_bit_t>(bit_depth_);
147  timer_conf.timer_num = timer_num;
148  timer_conf.freq_hz = (uint32_t) frequency_;
149  timer_conf.clk_cfg = LEDC_AUTO_CLK;
150  ledc_timer_config(&timer_conf);
151 #endif
152  // re-apply duty
153  this->write_state(this->duty_);
154 }
155 
156 uint8_t next_ledc_channel = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
157 
158 } // namespace ledc
159 } // namespace esphome
160 
161 #endif
virtual void turn_off()
Disable this binary output.
Definition: binary_output.h:51
uint8_t next_ledc_channel
void update_frequency(float frequency) override
Dynamically change frequency at runtime.
virtual uint8_t get_pin() const =0
ledc_mode_t get_speed_mode(uint8_t channel)
Definition: ledc_output.cpp:22
void write_state(float state) override
Override FloatOutput&#39;s write_state.
Definition: ledc_output.cpp:53
void status_set_warning()
Definition: component.cpp:141
uint16_le_t frequency
Definition: bl0942.h:21
void setup() override
Setup LEDC.
Definition: ledc_output.cpp:78
void dump_config() override
float ledc_min_frequency_for_bit_depth(uint8_t bit_depth, bool low_frequency)
Definition: ledc_output.cpp:35
optional< uint8_t > ledc_bit_depth_for_frequency(float frequency)
Definition: ledc_output.cpp:40
InternalGPIOPin * pin_
Definition: ledc_output.h:35
Definition: a4988.cpp:4
float ledc_max_frequency_for_bit_depth(uint8_t bit_depth)
Definition: ledc_output.cpp:33
virtual bool is_inverted() const =0
bool state
Definition: fan.h:34