8000 esp32/machine_pwm: Use IDF functions to calculate resolution correctly. · micropython/micropython@548babf · GitHub
[go: up one dir, main page]

Skip to content

Commit 548babf

Browse files
pi-anldpgeorge
authored andcommitted
esp32/machine_pwm: Use IDF functions to calculate resolution correctly.
This commit fixes PWM configuration across C3, C6, S2 and S3 chips, which was broken by 6d79937. Without this fix the PWM frequency is limited to a maximum of 2446Hz (on S2 at least). Signed-off-by: Andrew Leech <andrew@alelec.net>
1 parent 86c71a0 commit 548babf

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"
8000
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) {
< 10000 div aria-hidden="true" style="left:-2px" class="position-absolute top-0 d-flex user-select-none DiffLineTableCellParts-module__in-progress-comment-indicator--hx3m3">
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)
0