From 290da8df2ded1cc82268d2a22e24a163e2a27881 Mon Sep 17 00:00:00 2001 From: rsumner Date: Wed, 24 Nov 2021 16:22:51 -0600 Subject: [PATCH] Fix LEDC resolution calculation on ESP32-C3/S2/S3 (#2794) Co-authored-by: Oxan van Leeuwen Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/ledc/ledc_output.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/esphome/components/ledc/ledc_output.cpp b/esphome/components/ledc/ledc_output.cpp index 13ad32ab70..a56dccfd72 100644 --- a/esphome/components/ledc/ledc_output.cpp +++ b/esphome/components/ledc/ledc_output.cpp @@ -16,6 +16,7 @@ namespace ledc { static const char *const TAG = "ledc.output"; #ifdef USE_ESP_IDF +static const int MAX_RES_BITS = LEDC_TIMER_BIT_MAX - 1; #if SOC_LEDC_SUPPORT_HS_MODE // Only ESP32 has LEDC_HIGH_SPEED_MODE inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE; } @@ -25,19 +26,26 @@ inline ledc_mode_t get_speed_mode(uint8_t channel) { return channel < 8 ? LEDC_H // https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/ledc.html#functionality-overview inline ledc_mode_t get_speed_mode(uint8_t) { return LEDC_LOW_SPEED_MODE; } #endif +#else +static const int MAX_RES_BITS = 20; #endif float ledc_max_frequency_for_bit_depth(uint8_t bit_depth) { return 80e6f / float(1 << bit_depth); } -float ledc_min_frequency_for_bit_depth(uint8_t bit_depth) { - const float max_div_num = ((1 << 20) - 1) / 256.0f; + +float ledc_min_frequency_for_bit_depth(uint8_t bit_depth, bool low_frequency) { + const float max_div_num = ((1 << MAX_RES_BITS) - 1) / (low_frequency ? 32.0f : 256.0f); return 80e6f / (max_div_num * float(1 << bit_depth)); } + optional ledc_bit_depth_for_frequency(float frequency) { - for (int i = 20; i >= 1; i--) { - const float min_frequency = ledc_min_frequency_for_bit_depth(i); + ESP_LOGD(TAG, "Calculating resolution bit-depth for frequency %f", frequency); + for (int i = MAX_RES_BITS; i >= 1; i--) { + const float min_frequency = ledc_min_frequency_for_bit_depth(i, (frequency < 100)); const float max_frequency = ledc_max_frequency_for_bit_depth(i); - if (min_frequency <= frequency && frequency <= max_frequency) + if (min_frequency <= frequency && frequency <= max_frequency) { + ESP_LOGD(TAG, "Resolution calculated as %d", i); return i; + } } return {}; } @@ -80,6 +88,10 @@ void LEDCOutput::setup() { auto chan_num = static_cast(channel_ % 8); bit_depth_ = *ledc_bit_depth_for_frequency(frequency_); + if (bit_depth_ < 1) { + ESP_LOGW(TAG, "Frequency %f can't be achieved with any bit depth", frequency_); + this->status_set_warning(); + } ledc_timer_config_t timer_conf{}; timer_conf.speed_mode = speed_mode;