34
34
#include "py/mphal.h"
35
35
#include "driver/ledc.h"
36
36
#include "esp_err.h"
37
- #include "esp_clk_tree.h"
38
37
#include "soc/gpio_sig_map.h"
39
38
39
+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (5 , 1 , 0 )
40
+ #include "esp_clk_tree.h"
41
+ #endif
42
+
40
43
#define PWM_DBG (...)
41
44
// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n");
42
45
@@ -208,7 +211,41 @@ static void configure_channel(machine_pwm_obj_t *self) {
208
211
}
209
212
}
210
213
214
+ // Temporary workaround for ledc_find_suitable_duty_resolution function only being added in IDF V5.2
215
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL (5 , 2 , 0 )
216
+ static uint32_t ledc_find_suitable_duty_resolution (uint32_t src_clk_freq , uint32_t timer_freq ) {
217
+ // This implementation is based on the one used in Micropython v1.23
218
+
219
+ // Find the highest bit resolution for the requested frequency
220
+ unsigned int freq = src_clk_freq ;
221
+
222
+ int divider = (freq + timer_freq / 2 ) / timer_freq ; // rounded
223
+ if (divider == 0 ) {
224
+ divider = 1 ;
225
+ }
226
+ float f = (float )freq / divider ; // actual frequency
227
+ if (f <= 1.0 ) {
228
+ f = 1.0 ;
229
+ }
230
+ freq = (unsigned int )roundf ((float )freq / f );
231
+
232
+ unsigned int res = 0 ;
233
+ for (; freq > 1 ; freq >>= 1 ) {
234
+ ++ res ;
235
+ }
236
+ if (res == 0 ) {
237
+ res = 1 ;
238
+ } else if (res > HIGHEST_PWM_RES ) {
239
+ // Limit resolution to HIGHEST_PWM_RES to match units of our duty
240
+ res = HIGHEST_PWM_RES ;
241
+ }
242
+
243
+ return res ;
244
+ }
245
+ #endif
246
+
211
247
static void set_freq (machine_pwm_obj_t * self , unsigned int freq , ledc_timer_config_t * timer ) {
248
+ esp_err_t err ;
212
249
if (freq != timer -> freq_hz ) {
213
250
// Configure the new frequency and resolution
214
251
timer -> freq_hz = freq ;
@@ -228,10 +265,21 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
228
265
}
229
266
#endif
230
267
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 );
268
+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (5 , 1 , 0 )
269
+ err = esp_clk_tree_src_get_freq_hz (timer -> clk_cfg , ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED , & src_clk_freq );
232
270
if (err != ESP_OK ) {
233
271
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("unable to query source clock frequency %d" ), (int )timer -> clk_cfg );
234
272
}
273
+ #else
274
+ // Simplified fallback logic for IDF V5.0.x, for targets with APB only.
275
+ src_clk_freq = APB_CLK_FREQ ; // 80 MHz
276
+ #if SOC_LEDC_SUPPORT_REF_TICK
277
+ if (timer -> clk_cfg == LEDC_USE_REF_TICK ) {
278
+ src_clk_freq = REF_CLK_FREQ ; // 1 MHz
279
+ }
280
+ #endif // SOC_LEDC_SUPPORT_REF_TICK
281
+ #endif // ESP_IDF_VERSION
282
+
235
283
timer -> duty_resolution = ledc_find_suitable_duty_resolution (src_clk_freq , timer -> freq_hz );
236
284
237
285
// Set frequency
0 commit comments