@@ -74,7 +74,8 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
74
74
// Params for PWM operation
75
75
// 5khz is default frequency
76
76
#define PWM_FREQ (5000)
77
- // default 10-bit resolution (compatible with esp8266 PWM)
77
+
78
+ // 10-bit resolution (compatible with esp8266 PWM)
78
79
#define PWM_RES_10_BIT (LEDC_TIMER_10_BIT)
79
80
80
81
// Maximum duty value on 10-bit resolution
@@ -84,15 +85,17 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
84
85
// duty_u16() and duty_ns() use 16-bit resolution or less
85
86
86
87
// Possible highest resolution in device
87
- #if CONFIG_IDF_TARGET_ESP32
88
- #define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit for ESP32, but 16 bit is used
88
+ #if ( LEDC_TIMER_BIT_MAX - 1 ) < LEDC_TIMER_16_BIT
89
+ #define HIGHEST_PWM_RES (LEDC_TIMER_BIT_MAX - 1)
89
90
#else
90
- #define HIGHEST_PWM_RES (LEDC_TIMER_BIT_MAX - 1 ) // 14 bit is used
91
+ #define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT ) // 20 bit for ESP32, but 16 bit is used
91
92
#endif
92
93
// Duty resolution of user interface in `duty_u16()` and `duty_u16` parameter in constructor/initializer
93
94
#define UI_RES_16_BIT (16)
94
95
// Maximum duty value on highest user interface resolution
95
96
#define UI_MAX_DUTY ((1 << UI_RES_16_BIT) - 1)
97
+ // How much to shift from the HIGHEST_PWM_RES duty resolution to the user interface duty resolution UI_RES_16_BIT
98
+ #define UI_RES_SHIFT (UI_RES_16_BIT - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3
96
99
97
100
// If the PWM frequency is less than EMPIRIC_FREQ, then LEDC_REF_CLK_HZ(1 MHz) source is used, else LEDC_APB_CLK_HZ(80 MHz) source is used
98
101
#define EMPIRIC_FREQ (10) // Hz
@@ -108,7 +111,7 @@ typedef struct _machine_pwm_obj_t {
108
111
int mode ;
109
112
int channel ;
110
113
int timer ;
111
- int duty_x ; // PWM_RES_10_BIT if duty(), UI_RES_16_BIT if duty_u16(), -UI_RES_16_BIT if duty_ns()
114
+ int duty_x ; // PWM_RES_10_BIT if duty(), HIGHEST_PWM_RES if duty_u16(), -HIGHEST_PWM_RES if duty_ns()
112
115
int duty_u10 ; // stored values from previous duty setters
113
116
int duty_u16 ; // - / -
114
117
int duty_ns ; // - / -
@@ -237,7 +240,6 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
237
240
}
238
241
239
242
// Configure the new resolution and frequency
240
- unsigned int save_duty_resolution = timer -> duty_resolution ;
241
243
timer -> duty_resolution = res ;
242
244
timer -> freq_hz = freq ;
243
245
timer -> clk_cfg = LEDC_USE_APB_CLK ;
@@ -258,17 +260,15 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
258
260
if (self -> mode == LEDC_LOW_SPEED_MODE ) {
259
261
check_esp_err (ledc_timer_rst (self -> mode , self -> timer ));
260
262
}
263
+ }
261
264
262
- // Save the same duty cycle when frequency is changed
263
- if (save_duty_resolution != timer -> duty_resolution ) {
264
- if (self -> duty_x == UI_RES_16_BIT ) {
265
- set_duty_u16 (self , self -> duty_u16 );
266
- } else if (self -> duty_x == PWM_RES_10_BIT ) {
267
- set_duty_u10 (self , self -> duty_u10 );
268
- } else if (self -> duty_x == - UI_RES_16_BIT ) {
269
- set_duty_ns (self , self -> duty_ns );
270
- }
271
- }
265
+ // Save the same duty cycle when frequency is changed
266
+ if (self -> duty_x == HIGHEST_PWM_RES ) {
267
+ set_duty_u16 (self , self -> duty_u16 );
268
+ } else if (self -> duty_x == PWM_RES_10_BIT ) {
269
+ set_duty_u10 (self , self -> duty_u10 );
270
+ } else if (self -> duty_x == - HIGHEST_PWM_RES ) {
271
+ set_duty_ns (self , self -> duty_ns );
272
272
}
273
273
}
274
274
@@ -293,11 +293,18 @@ STATIC int duty_to_ns(machine_pwm_obj_t *self, int duty) {
293
293
#define get_duty_raw (self ) ledc_get_duty(self->mode, self->channel)
294
294
295
295
STATIC uint32_t get_duty_u16 (machine_pwm_obj_t * self ) {
296
- return ledc_get_duty (self -> mode , self -> channel ) << (UI_RES_16_BIT - timers [TIMER_IDX (self -> mode , self -> timer )].duty_resolution );
296
+ int resolution = timers [TIMER_IDX (self -> mode , self -> timer )].duty_resolution ;
297
+ int duty = ledc_get_duty (self -> mode , self -> channel );
298
+ if (resolution <= UI_RES_16_BIT ) {
299
+ duty <<= (UI_RES_16_BIT - resolution );
300
+ } else {
301
+ duty >>= (resolution - UI_RES_16_BIT );
302
+ }
303
+ return duty ;
297
304
}
298
305
299
306
STATIC uint32_t get_duty_u10 (machine_pwm_obj_t * self ) {
300
- return get_duty_u16 (self ) >> ( UI_RES_16_BIT - LEDC_TIMER_10_BIT );
307
+ return get_duty_u16 (self ) >> 6 ; // Scale down from 16 bit to 10 bit resolution
301
308
}
302
309
303
310
STATIC uint32_t get_duty_ns (machine_pwm_obj_t * self ) {
@@ -309,7 +316,12 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
309
316
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty_u16 must be from 0 to %d" ), UI_MAX_DUTY );
310
317
}
311
318
ledc_timer_config_t timer = timers [TIMER_IDX (self -> mode , self -> timer )];
312
- int channel_duty = duty >> (UI_RES_16_BIT - timer .duty_resolution );
319
+ int channel_duty ;
320
+ if (timer .duty_resolution <= UI_RES_16_BIT ) {
321
+ channel_duty = duty >> (UI_RES_16_BIT - timer .duty_resolution );
322
+ } else {
323
+ channel_duty = duty << (timer .duty_resolution - UI_RES_16_BIT );
324
+ }
313
325
int max_duty = (1 << timer .duty_resolution ) - 1 ;
314
326
if (channel_duty < 0 ) {
315
327
channel_duty = 0 ;
@@ -333,15 +345,15 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
333
345
}
334
346
*/
335
347
336
- self -> duty_x = UI_RES_16_BIT ;
348
+ self -> duty_x = HIGHEST_PWM_RES ;
337
349
self -> duty_u16 = duty ;
338
350
}
339
351
340
352
STATIC void set_duty_u10 (machine_pwm_obj_t * self , int duty ) {
341
353
if ((duty < 0 ) || (duty > MAX_DUTY_U10 )) {
342
354
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty must be from 0 to %u" ), MAX_DUTY_U10 );
343
355
}
344
- set_duty_u16 (self , duty << (UI_RES_16_BIT - LEDC_TIMER_10_BIT ));
356
+ set_duty_u16 (self , duty << (UI_RES_16_BIT - PWM_RES_10_BIT ));
345
357
self -> duty_x = PWM_RES_10_BIT ;
346
358
self -> duty_u10 = duty ;
347
359
}
@@ -351,7 +363,7 @@ STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns) {
351
363
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty_ns must be from 0 to %d ns" ), duty_to_ns (self , UI_MAX_DUTY ));
352
364
}
353
365
set_duty_u16 (self , ns_to_duty (self , ns ));
354
- self -> duty_x = - UI_RES_16_BIT ;
366
+ self -> duty_x = - HIGHEST_PWM_RES ;
355
367
self -> duty_ns = ns ;
356
368
}
357
369
@@ -424,7 +436,7 @@ STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
424
436
425
437
if (self -> duty_x == PWM_RES_10_BIT ) {
426
438
mp_printf (print , ", duty=%d" , get_duty_u10 (self ));
427
- } else if (self -> duty_x == - UI_RES_16_BIT ) {
439
+ } else if (self -> duty_x == - HIGHEST_PWM_RES ) {
428
440
mp_printf (print , ", duty_ns=%d" , get_duty_ns (self ));
429
441
} else {
430
442
mp_printf (print , ", duty_u16=%d" , get_duty_u16 (self ));
0 commit comments