|
34 | 34 | #include "py/mphal.h" |
35 | 35 | #include "driver/ledc.h" |
36 | 36 | #include "esp_err.h" |
| 37 | +#include "esp_clk_tree.h" |
37 | 38 | #include "soc/gpio_sig_map.h" |
38 | 39 |
|
39 | 40 | #define PWM_DBG(...) |
@@ -209,51 +210,32 @@ static void configure_channel(machine_pwm_obj_t *self) { |
209 | 210 |
|
210 | 211 | static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) { |
211 | 212 | 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 |
243 | 214 | 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 |
245 | 221 | timer->clk_cfg = LEDC_USE_XTAL_CLK; |
246 | 222 | #else |
247 | | - timer->clk_cfg = LEDC_USE_APB_CLK; |
| 223 | + #error No supported PWM / LEDC clocks. |
248 | 224 | #endif |
249 | 225 | #if SOC_LEDC_SUPPORT_REF_TICK |
250 | 226 | if (freq < EMPIRIC_FREQ) { |
251 | 227 | timer->clk_cfg = LEDC_USE_REF_TICK; |
252 | 228 | } |
253 | 229 | #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); |
254 | 236 |
|
255 | 237 | // Set frequency |
256 | | - esp_err_t err = ledc_timer_config(timer); |
| 238 | + err = ledc_timer_config(timer); |
257 | 239 | if (err != ESP_OK) { |
258 | 240 | if (err == ESP_FAIL) { |
259 | 241 | mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq); |
|
0 commit comments