Skip to content

Commit 8751d05

Browse files
committed
esp32/pwm: Use IDF functions to calculate resolution correctly.
Signed-off-by: Andrew Leech <[email protected]>
1 parent f212bbe commit 8751d05

File tree

1 file changed

+16
-34
lines changed

1 file changed

+16
-34
lines changed

ports/esp32/machine_pwm.c

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "py/mphal.h"
3535
#include "driver/ledc.h"
3636
#include "esp_err.h"
37+
#include "esp_clk_tree.h"
3738
#include "soc/gpio_sig_map.h"
3839

3940
#define PWM_DBG(...)
@@ -209,51 +210,32 @@ static void configure_channel(machine_pwm_obj_t *self) {
209210

210211
static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) {
211212
if (freq != timer->freq_hz) {
212-
// Find the highest bit resolution for the requested frequency
213-
unsigned int i = APB_CLK_FREQ; // 80 MHz
214-
#if SOC_LEDC_SUPPORT_REF_TICK
215-
if (freq < EMPIRIC_FREQ) {
216-
i = REF_CLK_FREQ; // 1 MHz
217-
}
218-
#endif
219-
220-
int divider = (i + freq / 2) / freq; // rounded
221-
if (divider == 0) {
222-
divider = 1;
223-
}
224-
float f = (float)i / divider; // actual frequency
225-
if (f <= 1.0) {
226-
f = 1.0;
227-
}
228-
i = (unsigned int)roundf((float)i / f);
229-
230-
unsigned int res = 0;
231-
for (; i > 1; i >>= 1) {
232-
++res;
233-
}
234-
if (res == 0) {
235-
res = 1;
236-
} else if (res > HIGHEST_PWM_RES) {
237-
// Limit resolution to HIGHEST_PWM_RES to match units of our duty
238-
res = HIGHEST_PWM_RES;
239-
}
240-
241-
// Configure the new resolution and frequency
242-
timer->duty_resolution = res;
213+
// Configure the new frequency and resolution
243214
timer->freq_hz = freq;
244-
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
215+
216+
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
217+
timer->clk_cfg = LEDC_USE_PLL_DIV_CLK;
218+
#elif SOC_LEDC_SUPPORT_APB_CLOCK
219+
timer->clk_cfg = LEDC_USE_APB_CLK;
220+
#elif SOC_LEDC_SUPPORT_XTAL_CLOCK
245221
timer->clk_cfg = LEDC_USE_XTAL_CLK;
246222
#else
247-
timer->clk_cfg = LEDC_USE_APB_CLK;
223+
#error No supported PWM / LEDC clocks.
248224
#endif
249225
#if SOC_LEDC_SUPPORT_REF_TICK
250226
if (freq < EMPIRIC_FREQ) {
251227
timer->clk_cfg = LEDC_USE_REF_TICK;
252228
}
253229
#endif
230+
uint32_t src_clk_freq = 0;
231+
esp_err_t err = esp_clk_tree_src_get_freq_hz(timer->clk_cfg, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_freq);
232+
if (err != ESP_OK) {
233+
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unable to query source clock frequency %d"), (int)timer->clk_cfg);
234+
}
235+
timer->duty_resolution = ledc_find_suitable_duty_resolution(src_clk_freq, timer->freq_hz);
254236

255237
// Set frequency
256-
esp_err_t err = ledc_timer_config(timer);
238+
err = ledc_timer_config(timer);
257239
if (err != ESP_OK) {
258240
if (err == ESP_FAIL) {
259241
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq);

0 commit comments

Comments
 (0)