| 
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