35
35
#include "py/mphal.h"
36
36
#include "esp_err.h"
37
37
#include "driver/ledc.h"
38
- #include "soc/gpio_sig_map.h"
39
38
#include "soc/ledc_periph.h"
39
+ #include "soc/gpio_sig_map.h"
40
40
#include "esp_clk_tree.h"
41
41
#include "py/mpprint.h"
42
42
43
43
#define debug_printf (...) // mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, " | %d at %s\n", __LINE__, __FILE__);
44
- #define FADE 1
44
+
45
+ #define FADE
45
46
46
47
// 10-bit user interface resolution compatible with esp8266 PWM.duty()
47
48
#define UI_RES_10_BIT (10)
48
49
#define DUTY_10 UI_RES_10_BIT
49
- // Maximum duty value on 10-bit resolution
50
- #define MAX_10_DUTY (( 1U << UI_RES_10_BIT) - 1 )
50
+ // Maximum duty value on 10-bit resolution is 1024 but reduced to 1023 in UI
51
+ #define MAX_10_DUTY (1U << UI_RES_10_BIT)
51
52
52
53
// 16-bit user interface resolution used in PWM.duty_u16()
53
54
#define UI_RES_16_BIT (16)
54
55
#define DUTY_16 UI_RES_16_BIT
55
- // Maximum duty value on 16-bit resolution
56
- #define MAX_16_DUTY (( 1U << UI_RES_16_BIT) - 1 )
56
+ // Maximum duty value on 16-bit resolution is 65536 but reduced to 65535 in UI
57
+ #define MAX_16_DUTY (1U << UI_RES_16_BIT)
57
58
58
59
// ns user interface used in PWM.duty_ns()
59
60
#define DUTY_NS (1)
63
64
// default duty 50%
64
65
#define PWM_DUTY ((1U << UI_RES_16_BIT) / 2)
65
66
66
- // MAX_timer_duty is the MAX value of a channel_duty
67
- #define MAX_timer_duty ((1U << timers[self->mode][self->timer].duty_resolution) - 1)
68
-
69
67
// All chips except esp32 and esp32s2 do not have timer-specific clock sources, which means clock source for all timers must be the same one.
70
68
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
71
69
// 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
@@ -89,7 +87,6 @@ typedef struct _machine_pwm_obj_t {
89
87
int channel_duty ; // saved values of UI duty, calculated to raw channel->duty
90
88
bool output_invert ;
91
89
bool output_invert_prev ;
92
- bool output_is_inverted ;
93
90
} machine_pwm_obj_t ;
94
91
95
92
typedef struct _chans_t {
@@ -218,14 +215,10 @@ static int duty_to_ns(machine_pwm_obj_t *self, int duty) {
218
215
219
216
// Reconfigure PWM pin output as input/output. This allows to read the pin level.
220
217
static void reconfigure_pin (machine_pwm_obj_t * self ) {
221
- bool invert = self -> output_invert ;
222
- if (self -> channel_duty == MAX_timer_duty ) {
223
- invert = !invert ;
224
- }
225
218
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL (5 , 4 , 0 )
226
219
gpio_set_direction (self -> pin , GPIO_MODE_INPUT_OUTPUT );
227
220
#endif
228
- esp_rom_gpio_connect_out_signal (self -> pin , ledc_periph_signal [self -> mode ].sig_out0_idx + self -> channel , invert , 0 );
221
+ esp_rom_gpio_connect_out_signal (self -> pin , ledc_periph_signal [self -> mode ].sig_out0_idx + self -> channel , self -> output_invert , 0 );
229
222
}
230
223
231
224
static void apply_duty (machine_pwm_obj_t * self ) {
@@ -235,13 +228,12 @@ static void apply_duty(machine_pwm_obj_t *self) {
235
228
if (self -> duty_scale == DUTY_16 ) {
236
229
duty = self -> duty_ui ;
237
230
} else if (self -> duty_scale == DUTY_10 ) {
238
- duty = self -> duty_ui == MAX_10_DUTY ? MAX_16_DUTY : self -> duty_ui << (UI_RES_16_BIT - UI_RES_10_BIT );
231
+ duty = self -> duty_ui << (UI_RES_16_BIT - UI_RES_10_BIT );
239
232
} else if (self -> duty_scale == DUTY_NS ) {
240
233
duty = ns_to_duty (self , self -> duty_ui );
241
234
}
242
235
self -> channel_duty = duty >> (UI_RES_16_BIT - timers [self -> mode ][self -> timer ].duty_resolution );
243
- int max_timer_duty = MAX_timer_duty ;
244
- if ((chans [self -> mode ][self -> channel ].pin == -1 ) || (self -> channel_duty == 0 ) || (self -> channel_duty == max_timer_duty ) || (self -> output_invert_prev != self -> output_invert ) || (self -> output_is_inverted != self -> output_invert )) {
236
+ if ((chans [self -> mode ][self -> channel ].pin == -1 ) || (self -> output_invert_prev != self -> output_invert )) {
245
237
self -> output_invert_prev = self -> output_invert ;
246
238
// New PWM assignment
247
239
ledc_channel_config_t cfg = {
@@ -254,27 +246,21 @@ static void apply_duty(machine_pwm_obj_t *self) {
254
246
.hpoint = 0 ,
255
247
.flags .output_invert = self -> output_invert ,
256
248
};
257
- self -> output_is_inverted = false;
258
- if (self -> channel_duty == max_timer_duty ) {
259
- cfg .duty = 0 ;
260
- cfg .flags .output_invert = !self -> output_invert ;
261
- self -> output_is_inverted = true;
262
- }
263
249
check_esp_err (ledc_channel_config (& cfg ));
264
250
if (self -> light_sleep_enable ) {
265
251
// Disable SLP_SEL to change GPIO status automantically in lightsleep.
266
252
check_esp_err (gpio_sleep_sel_dis (self -> pin ));
267
253
chans [self -> mode ][self -> channel ].light_sleep_enable = true;
268
254
}
255
+ reconfigure_pin (self );
269
256
} else {
270
- #if FADE
257
+ #ifdef FADE
271
258
check_esp_err (ledc_set_duty_and_update (self -> mode , self -> channel , self -> channel_duty , 0 ));
272
259
#else
273
260
check_esp_err (ledc_set_duty (self -> mode , self -> channel , self -> channel_duty ));
274
261
check_esp_err (ledc_update_duty (self -> mode , self -> channel ));
275
262
#endif
276
263
}
277
- reconfigure_pin (self );
278
264
register_channel (self -> mode , self -> channel , self -> pin , self -> timer );
279
265
}
280
266
@@ -284,25 +270,24 @@ static uint32_t find_suitable_duty_resolution(uint32_t src_clk_freq, uint32_t ti
284
270
// limit resolution to user interface
285
271
resolution = UI_RES_16_BIT ;
286
272
}
287
- /*
288
- // Uncomment if duty is 65536!
289
273
// Note: On ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2, ESP32P4, due to a hardware bug,
290
274
// 100% duty cycle (i.e. 2**duty_res) is not reachable when the binded timer selects the maximum duty
291
275
// resolution. For example, the max duty resolution on ESP32C3 is 14-bit width, then set duty to (2**14)
292
276
// will mess up the duty calculation in hardware.
293
- if (resolution >= SOC_LEDC_TIMER_BIT_WIDTH)
277
+ // Reduce the resolution from 14 to 13 bits to resolve the hardware bug.
278
+ if (resolution >= SOC_LEDC_TIMER_BIT_WIDTH ) {
294
279
resolution -= 1 ;
295
280
}
296
- */
297
281
return resolution ;
298
282
}
299
283
300
284
static uint32_t get_duty_u16 (machine_pwm_obj_t * self ) {
301
285
pwm_is_active (self );
302
- if (self -> channel_duty == MAX_timer_duty ) {
303
- return MAX_16_DUTY ;
286
+ int duty = ledc_get_duty (self -> mode , self -> channel ) << (UI_RES_16_BIT - timers [self -> mode ][self -> timer ].duty_resolution );
287
+ if (duty != MAX_16_DUTY ) {
288
+ return duty ;
304
289
} else {
305
- return ledc_get_duty ( self -> mode , self -> channel ) << ( UI_RES_16_BIT - timers [ self -> mode ][ self -> timer ]. duty_resolution ) ;
290
+ return MAX_16_DUTY - 1 ;
306
291
}
307
292
}
308
293
@@ -316,9 +301,12 @@ static uint32_t get_duty_ns(machine_pwm_obj_t *self) {
316
301
}
317
302
318
303
static void check_duty_u16 (machine_pwm_obj_t * self , int duty ) {
319
- if ((duty < 0 ) || (duty > MAX_16_DUTY )) {
304
+ if ((duty < 0 ) || (duty > MAX_16_DUTY - 1 )) {
320
305
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty_u16 must be from 0 to %d" ), MAX_16_DUTY );
321
306
}
307
+ if (duty == MAX_16_DUTY - 1 ) {
308
+ duty = MAX_16_DUTY ;
309
+ }
322
310
self -> duty_scale = DUTY_16 ;
323
311
self -> duty_ui = duty ;
324
312
}
@@ -329,8 +317,11 @@ static void set_duty_u16(machine_pwm_obj_t *self, int duty) {
329
317
}
330
318
331
319
static void check_duty_u10 (machine_pwm_obj_t * self , int duty ) {
332
- if ((duty < 0 ) || (duty > MAX_10_DUTY )) {
333
- mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty must be from 0 to %u" ), MAX_10_DUTY );
320
+ if ((duty < 0 ) || (duty > MAX_10_DUTY - 1 )) {
321
+ mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("duty must be from 0 to %u" ), MAX_10_DUTY - 1 );
322
+ }
323
+ if (duty == MAX_10_DUTY - 1 ) {
324
+ duty = MAX_10_DUTY ;
334
325
}
335
326
self -> duty_scale = DUTY_10 ;
336
327
self -> duty_ui = duty ;
@@ -656,7 +647,6 @@ static void self_reset(machine_pwm_obj_t *self) {
656
647
self -> channel_duty = -1 ;
657
648
self -> output_invert = false;
658
649
self -> output_invert_prev = false;
659
- self -> output_is_inverted = false;
660
650
self -> light_sleep_enable = false;
661
651
}
662
652
@@ -668,7 +658,7 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
668
658
// start the PWM subsystem if it's not already running
669
659
if (!pwm_inited ) {
670
660
pwm_init ();
671
- #if FADE
661
+ #ifdef FADE
672
662
ledc_fade_func_install (0 );
673
663
#endif
674
664
pwm_inited = true;
@@ -684,7 +674,6 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
684
674
mp_map_t kw_args ;
685
675
mp_map_init_fixed_table (& kw_args , n_kw , args + n_args );
686
676
mp_machine_pwm_init_helper (self , n_args - 1 , args + 1 , & kw_args );
687
-
688
677
return MP_OBJ_FROM_PTR (self );
689
678
}
690
679
0 commit comments