@@ -85,17 +85,17 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX];
85
85
// duty_u16() and duty_ns() use 16-bit resolution or less
86
86
87
87
// Possible highest resolution in device
88
- #if CONFIG_IDF_TARGET_ESP32
89
- #define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit in fact, 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)
90
90
#else
91
- #define HIGHEST_PWM_RES (LEDC_TIMER_14_BIT)
91
+ #define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit for ESP32, but 16 bit is used
92
92
#endif
93
93
// Duty resolution of user interface in `duty_u16()` and `duty_u16` parameter in constructor/initializer
94
94
#define UI_RES_16_BIT (16)
95
95
// Maximum duty value on highest user interface resolution
96
96
#define UI_MAX_DUTY ((1 << UI_RES_16_BIT) - 1)
97
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 (16 - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3
98
+ #define UI_RES_SHIFT (UI_RES_16_BIT - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3
99
99
100
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
101
101
#define EMPIRIC_FREQ (10) // Hz
@@ -205,24 +205,19 @@ STATIC void configure_channel(machine_pwm_obj_t *self) {
205
205
}
206
206
207
207
STATIC void set_freq (machine_pwm_obj_t * self , unsigned int freq , ledc_timer_config_t * timer ) {
208
- // Even if the timer frequency is already set,
209
- // the set_duty_x() is required to reconfigure the channel duty anyway
210
208
if (freq != timer -> freq_hz ) {
211
- PWM_DBG ("set_freq(%d)" , freq )
212
-
213
209
// Find the highest bit resolution for the requested frequency
214
210
unsigned int i = LEDC_APB_CLK_HZ ; // 80 MHz
215
211
if (freq < EMPIRIC_FREQ ) {
216
212
i = LEDC_REF_CLK_HZ ; // 1 MHz
217
213
}
218
214
219
- #if 1
215
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL ( 5 , 0 , 0 )
220
216
// original code
221
217
i /= freq ;
222
218
#else
223
219
// See https://github.com/espressif/esp-idf/issues/7722
224
- unsigned int divider = i / freq ; // truncated
225
- // int divider = (i + freq / 2) / freq; // rounded
220
+ int divider = (i + freq / 2 ) / freq ; // rounded
226
221
if (divider == 0 ) {
227
222
divider = 1 ;
228
223
}
@@ -245,6 +240,7 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
245
240
}
246
241
247
242
// Configure the new resolution and frequency
243
+ unsigned int save_duty_resolution = timer -> duty_resolution ;
248
244
timer -> duty_resolution = res ;
249
245
timer -> freq_hz = freq ;
250
246
timer -> clk_cfg = LEDC_USE_APB_CLK ;
@@ -256,7 +252,6 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
256
252
esp_err_t err = ledc_timer_config (timer );
257
253
if (err != ESP_OK ) {
258
254
if (err == ESP_FAIL ) {
259
- PWM_DBG (" (timer timer->speed_mode %d, timer->timer_num %d, timer->clk_cfg %d, timer->freq_hz %d, timer->duty_resolution %d) " , timer -> speed_mode , timer -> timer_num , timer -> clk_cfg , timer -> freq_hz , timer -> duty_resolution );
260
255
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("unreachable frequency %d" ), freq );
261
256
} else {
262
257
check_esp_err (err );
@@ -266,15 +261,17 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
266
261
if (self -> mode == LEDC_LOW_SPEED_MODE ) {
267
262
check_esp_err (ledc_timer_rst (self -> mode , self -> timer ));
268
263
}
269
- }
270
264
271
- // Save the same duty cycle when frequency or channel are changed
272
- if (self -> duty_x == HIGHEST_PWM_RES ) {
273
- set_duty_u16 (self , self -> duty_u16 );
274
- } else if (self -> duty_x == PWRES ) {
275
- set_duty_u10 (self , self -> duty_u10 );
276
- } else if (self -> duty_x == - HIGHEST_PWM_RES ) {
277
- set_duty_ns (self , self -> duty_ns );
265
+ // Save the same duty cycle when frequency is changed
266
+ if (save_duty_resolution != timer -> duty_resolution ) {
267
+ if (self -> duty_x == HIGHEST_PWM_RES ) {
268
+ set_duty_u16 (self , self -> duty_u16 );
269
+ } else if (self -> duty_x == PWRES ) {
270
+ set_duty_u10 (self , self -> duty_u10 );
271
+ } else if (self -> duty_x == - HIGHEST_PWM_RES ) {
272
+ set_duty_ns (self , self -> duty_ns );
273
+ }
274
+ }
278
275
}
279
276
}
280
277
@@ -287,14 +284,12 @@ STATIC int ns_to_duty(machine_pwm_obj_t *self, int ns) {
287
284
} else if (duty > UI_MAX_DUTY ) {
288
285
duty = UI_MAX_DUTY ;
289
286
}
290
- // PWM_DBG(" ns_to_duty(UI_MAX_DUTY=%d freq_hz=%d duty=%d=%f <- ns=%d) ", UI_MAX_DUTY, timer.freq_hz, duty, (float)ns * UI_MAX_DUTY * timer.freq_hz / 1000000000.0, ns);
291
287
return duty ;
292
288
}
293
289
294
290
STATIC int duty_to_ns (machine_pwm_obj_t * self , int duty ) {
295
291
ledc_timer_config_t timer = timers [TIMER_IDX (self -> mode , self -> timer )];
296
292
int64_t ns = ((int64_t )duty * 1000000000LL + (int64_t )timer .freq_hz * UI_MAX_DUTY / 2 ) / ((int64_t )timer .freq_hz * UI_MAX_DUTY );
297
- // PWM_DBG(" duty_to_ns(UI_MAX_DUTY=%d freq_hz=%d duty=%d -> ns=%f=%d) ", UI_MAX_DUTY, timer.freq_hz, duty, (float)duty * 1000000000.0 / ((float)timer.freq_hz * UI_MAX_DUTY), ns);
298
293
return ns ;
299
294
}
300
295
@@ -316,23 +311,27 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
316
311
if ((duty < 0 ) || (duty > UI_MAX_DUTY )) {
317
312
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty_u16 must be from 0 to %d" ), UI_MAX_DUTY );
318
313
}
319
- duty >>= HIGHEST_PWM_RES + UI_RES_SHIFT - timers [TIMER_IDX (self -> mode , self -> timer )].duty_resolution ;
320
- int max_duty = (1 << timers [TIMER_IDX (self -> mode , self -> timer )].duty_resolution ) - 1 ;
321
- if (duty < 0 ) {
322
- duty = 0 ;
323
- } else if (duty > max_duty ) {
324
- duty = max_duty ;
325
- }
326
- check_esp_err (ledc_set_duty (self -> mode , self -> channel , duty ));
314
+ ledc_timer_config_t timer = timers [TIMER_IDX (self -> mode , self -> timer )];
315
+ int channel_duty = duty >> (HIGHEST_PWM_RES + UI_RES_SHIFT - timer .duty_resolution );
316
+ int max_duty = (1 << timer .duty_resolution ) - 1 ;
317
+ if (channel_duty < 0 ) {
318
+ channel_duty = 0 ;
319
+ } else if (channel_duty > max_duty ) {
320
+ channel_duty = max_duty ;
321
+ }
322
+ check_esp_err (ledc_set_duty (self -> mode , self -> channel , channel_duty ));
327
323
check_esp_err (ledc_update_duty (self -> mode , self -> channel ));
328
324
329
325
/*
330
326
// Bug: Sometimes duty is not set right now.
327
+ // Not a bug. It's a feature. The duty is applied at the beginning of the next signal period.
328
+ // Bug: It has been experimentally established that the duty is setted during 2 signal periods, but 1 period is expected.
331
329
// See https://github.com/espressif/esp-idf/issues/7288
332
330
if (duty != get_duty_u16(self)) {
333
- ets_delay_us(100);
331
+ PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz);
332
+ ets_delay_us(2 * 1000000 / timer.freq_hz);
334
333
if (duty != get_duty_u16(self)) {
335
- PWM_DBG(" ( set_duty_u16(%u) get_duty_u16()=%u duty_resolution=%d) ", duty, get_duty_u16(self), timers[TIMER_IDX(self->mode, self-> timer)] .duty_resolution);
334
+ PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d ", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz );
336
335
}
337
336
}
338
337
*/
0 commit comments