40
40
#include "esp_clk_tree.h"
41
41
#include "py/mpprint.h"
42
42
43
- #define debug_printf (...) // mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, " | %d at %s\n", __LINE__, __FILE__);
43
+ #define debug_printf (...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, " | %d at %s\n", __LINE__, __FILE__);
44
44
45
45
#define FADE 0
46
46
@@ -80,7 +80,7 @@ typedef struct _machine_pwm_obj_t {
80
80
int8_t mode ;
81
81
int8_t channel ;
82
82
int8_t timer ;
83
- bool light_sleep_enable ;
83
+ bool lightsleep ;
84
84
int32_t freq ;
85
85
int8_t duty_scale ; // DUTY_10 if duty(), DUTY_16 if duty_u16(), DUTY_NS if duty_ns()
86
86
int duty_ui ; // saved values of UI duty
@@ -90,9 +90,9 @@ typedef struct _machine_pwm_obj_t {
90
90
} machine_pwm_obj_t ;
91
91
92
92
typedef struct _chans_t {
93
- int8_t pin ; // Which channel has which GPIO pin assigned? (-1 if not assigned)
94
- int8_t timer ; // Which channel has which timer assigned? (-1 if not assigned)
95
- bool light_sleep_enable ; // Is light sleep enable has been set for this pin
93
+ int8_t pin ; // Which channel has which GPIO pin assigned? (-1 if not assigned)
94
+ int8_t timer ; // Which channel has which timer assigned? (-1 if not assigned)
95
+ bool lightsleep ; // Is light sleep enable has been set for this pin
96
96
} chans_t ;
97
97
98
98
// List of PWM channels
@@ -109,33 +109,38 @@ static timers_t timers[LEDC_SPEED_MODE_MAX][LEDC_TIMER_MAX];
109
109
110
110
// register-unregister channel
111
111
static void register_channel (int mode , int channel , int pin , int timer ) {
112
- if ((mode >= 0 ) && (mode < LEDC_SPEED_MODE_MAX ) && (channel >= 0 ) && (channel < LEDC_CHANNEL_MAX )) {
113
- chans [mode ][channel ].pin = pin ;
114
- chans [mode ][channel ].timer = timer ;
115
- }
112
+ chans [mode ][channel ].pin = pin ;
113
+ chans [mode ][channel ].timer = timer ;
114
+ }
115
+
116
+ static void unregister_channel (int mode , int channel ) {
117
+ register_channel (mode , channel , -1 , -1 );
118
+ chans [mode ][channel ].lightsleep = false;
119
+ }
120
+
121
+ static void unregister_timer (int mode , int timer ) {
122
+ timers [mode ][timer ].freq = -1 ; // unused timer freq is -1
123
+ timers [mode ][timer ].duty_resolution = 0 ;
124
+ timers [mode ][timer ].clk_cfg = LEDC_AUTO_CLK ;
116
125
}
117
- #define unregister_channel (mode , channel ) register_channel(mode, channel, -1, -1)
118
126
119
127
static void pwm_init (void ) {
120
128
for (int mode = 0 ; mode < LEDC_SPEED_MODE_MAX ; ++ mode ) {
121
129
// Initial condition: no channels assigned
122
130
for (int channel = 0 ; channel < LEDC_CHANNEL_MAX ; ++ channel ) {
123
131
unregister_channel (mode , channel );
124
- chans [mode ][channel ].light_sleep_enable = false;
125
132
}
126
133
// Initial condition: no timers assigned
127
134
for (int timer = 0 ; timer < LEDC_TIMER_MAX ; ++ timer ) {
128
- timers [mode ][timer ].freq = -1 ; // unset timer is -1
129
- timers [mode ][timer ].duty_resolution = 0 ;
130
- timers [mode ][timer ].clk_cfg = LEDC_AUTO_CLK ;
135
+ unregister_timer (mode , timer );
131
136
}
132
137
}
133
138
}
134
139
135
140
// Returns true if the timer is in use in addition to current channel
136
141
static bool is_timer_in_use (int mode , int current_channel , int timer ) {
137
142
for (int channel = 0 ; channel < LEDC_CHANNEL_MAX ; ++ channel ) {
138
- if ((channel != current_channel ) && (chans [mode ][channel ].timer == timer )) {
143
+ if ((channel != current_channel ) && (chans [mode ][channel ].timer == timer ) && ( chans [ mode ][ channel ]. pin >= 0 ) ) {
139
144
return true;
140
145
}
141
146
}
@@ -156,22 +161,19 @@ static void pwm_deinit(int mode, int channel, int level) {
156
161
.speed_mode = mode ,
157
162
.timer_num = timer ,
158
163
};
159
- check_esp_err (ledc_timer_config (& ledc_timer ));
160
- // Flag it unused
161
- timers [mode ][timer ].freq = -1 ;
162
- timers [mode ][timer ].duty_resolution = 0 ;
163
- timers [mode ][timer ].clk_cfg = LEDC_AUTO_CLK ;
164
+ ledc_timer_config (& ledc_timer );
165
+ unregister_timer (mode , timer );
164
166
}
165
167
}
166
168
167
169
int pin = chans [mode ][channel ].pin ;
168
170
if (pin >= 0 ) {
169
171
// Disable LEDC output, and set idle level
170
172
check_esp_err (ledc_stop (mode , channel , level ));
171
- if (chans [mode ][channel ].light_sleep_enable ) {
173
+ if (chans [mode ][channel ].lightsleep ) {
172
174
// Enable SLP_SEL to change GPIO status automantically in lightsleep.
173
175
check_esp_err (gpio_sleep_sel_en (pin ));
174
- chans [mode ][channel ].light_sleep_enable = false;
176
+ chans [mode ][channel ].lightsleep = false;
175
177
}
176
178
}
177
179
unregister_channel (mode , channel );
@@ -216,9 +218,10 @@ static int duty_to_ns(machine_pwm_obj_t *self, int duty) {
216
218
return ((int64_t )duty * 1000000000LL + (int64_t )self -> freq * (int64_t )(MAX_16_DUTY / 2 )) / ((int64_t )self -> freq * (int64_t )MAX_16_DUTY );
217
219
}
218
220
219
- // Reconfigure PWM pin output as input/output. This allows to read the pin level.
221
+ // Reconfigure PWM pin output as input/output.
220
222
static void reconfigure_pin (machine_pwm_obj_t * self ) {
221
223
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL (5 , 4 , 0 )
224
+ // This allows to read the pin level.
222
225
gpio_set_direction (self -> pin , GPIO_MODE_INPUT_OUTPUT );
223
226
#endif
224
227
esp_rom_gpio_connect_out_signal (self -> pin , ledc_periph_signal [self -> mode ].sig_out0_idx + self -> channel , self -> output_invert , 0 );
@@ -259,10 +262,10 @@ static void apply_duty(machine_pwm_obj_t *self) {
259
262
check_esp_err (ledc_update_duty (self -> mode , self -> channel ));
260
263
#endif
261
264
}
262
- if (self -> light_sleep_enable ) {
265
+ if (self -> lightsleep ) {
263
266
// Disable SLP_SEL to change GPIO status automantically in lightsleep.
264
267
check_esp_err (gpio_sleep_sel_dis (self -> pin ));
265
- chans [self -> mode ][self -> channel ].light_sleep_enable = true;
268
+ chans [self -> mode ][self -> channel ].lightsleep = true;
266
269
}
267
270
register_channel (self -> mode , self -> channel , self -> pin , self -> timer );
268
271
}
@@ -360,6 +363,16 @@ static ledc_clk_cfg_t find_clock_in_use() {
360
363
}
361
364
return LEDC_AUTO_CLK ;
362
365
}
366
+
367
+ // Check if a timer is already set with a different clock source
368
+ static bool is_timer_with_different_clock (int mode , int current_timer , ledc_clk_cfg_t clk_cfg ) {
369
+ for (int timer = 0 ; timer < LEDC_TIMER_MAX ; ++ timer ) {
370
+ if ((timer != current_timer ) && (clk_cfg != LEDC_AUTO_CLK ) && (timers [mode ][timer ].clk_cfg != LEDC_AUTO_CLK ) && (timers [mode ][timer ].clk_cfg != clk_cfg )) {
371
+ return true;
372
+ }
373
+ }
374
+ return false;
375
+ }
363
376
#endif
364
377
365
378
static void check_freq_ranges (machine_pwm_obj_t * self , int freq , int upper_freq ) {
@@ -371,9 +384,7 @@ static void check_freq_ranges(machine_pwm_obj_t *self, int freq, int upper_freq)
371
384
// Set timer frequency
372
385
static void set_freq (machine_pwm_obj_t * self , unsigned int freq ) {
373
386
self -> freq = freq ;
374
- if (timers [self -> mode ][self -> timer ].freq != freq ) {
375
- timers [self -> mode ][self -> timer ].freq = freq ;
376
-
387
+ if ((timers [self -> mode ][self -> timer ].freq != freq ) || (self -> lightsleep )) {
377
388
ledc_timer_config_t timer = {};
378
389
timer .speed_mode = self -> mode ;
379
390
timer .timer_num = self -> timer ;
@@ -382,7 +393,7 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
382
393
383
394
timer .clk_cfg = LEDC_AUTO_CLK ;
384
395
385
- if (self -> light_sleep_enable ) {
396
+ if (self -> lightsleep ) {
386
397
timer .clk_cfg = LEDC_USE_RC_FAST_CLK ; // 8 or 20 MHz
387
398
} else {
388
399
#if SOC_LEDC_SUPPORT_APB_CLOCK
@@ -402,9 +413,9 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
402
413
#endif
403
414
}
404
415
#if !(CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 )
405
- // Check for clock source conflic
406
- ledc_clk_cfg_t pwm_clk = find_clock_in_use ();
407
- if ((pwm_clk != LEDC_AUTO_CLK ) && (pwm_clk != timer .clk_cfg )) {
416
+ // Check for clock source conflict
417
+ ledc_clk_cfg_t clk_cfg = find_clock_in_use ();
418
+ if ((clk_cfg != LEDC_AUTO_CLK ) && (clk_cfg != timer .clk_cfg )) {
408
419
mp_raise_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("one or more active timers use a different clock source, not supported by the current SoC." ));
409
420
}
410
421
#endif
@@ -426,6 +437,7 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
426
437
if (self -> mode == LEDC_LOW_SPEED_MODE ) {
427
438
check_esp_err (ledc_timer_rst (self -> mode , self -> timer ));
428
439
}
440
+ timers [self -> mode ][self -> timer ].freq = freq ;
429
441
timers [self -> mode ][self -> timer ].duty_resolution = timer .duty_resolution ;
430
442
timers [self -> mode ][self -> timer ].clk_cfg = timer .clk_cfg ;
431
443
}
@@ -454,7 +466,7 @@ static void find_channel(machine_pwm_obj_t *self, int *ret_mode, int *ret_channe
454
466
// Try to find self channel first
455
467
for (int mode = 0 ; mode < LEDC_SPEED_MODE_MAX ; ++ mode ) {
456
468
#if SOC_LEDC_SUPPORT_HS_MODE
457
- if (self -> light_sleep_enable && (mode == LEDC_HIGH_SPEED_MODE )) {
469
+ if (self -> lightsleep && (mode == LEDC_HIGH_SPEED_MODE )) {
458
470
continue ;
459
471
}
460
472
#endif
@@ -469,7 +481,7 @@ static void find_channel(machine_pwm_obj_t *self, int *ret_mode, int *ret_channe
469
481
// Find free channel
470
482
for (int mode = 0 ; mode < LEDC_SPEED_MODE_MAX ; ++ mode ) {
471
483
#if SOC_LEDC_SUPPORT_HS_MODE
472
- if (self -> light_sleep_enable && (mode == LEDC_HIGH_SPEED_MODE )) {
484
+ if (self -> lightsleep && (mode == LEDC_HIGH_SPEED_MODE )) {
473
485
continue ;
474
486
}
475
487
#endif
@@ -487,7 +499,7 @@ static void find_channel(machine_pwm_obj_t *self, int *ret_mode, int *ret_channe
487
499
static void find_timer (machine_pwm_obj_t * self , int freq , int * ret_mode , int * ret_timer ) {
488
500
for (int mode = 0 ; mode < LEDC_SPEED_MODE_MAX ; ++ mode ) {
489
501
#if SOC_LEDC_SUPPORT_HS_MODE
490
- if (self -> light_sleep_enable && (mode == LEDC_HIGH_SPEED_MODE )) {
502
+ if (self -> lightsleep && (mode == LEDC_HIGH_SPEED_MODE )) {
491
503
continue ;
492
504
}
493
505
#endif
@@ -505,7 +517,7 @@ static void find_timer(machine_pwm_obj_t *self, int freq, int *ret_mode, int *re
505
517
506
518
// Try to find a timer with the same frequency in the current mode, otherwise in the next mode.
507
519
// If no existing timer and channel was found, then try to find free timer in any mode.
508
- // If the mode or channel is changed, release the channel and select(bind) a new channel in the next mode.
520
+ // If the mode or channel is changed, release the channel and register a new channel in the next mode.
509
521
static void select_timer (machine_pwm_obj_t * self , int freq ) {
510
522
// mode, channel, timer may be -1(not defined) or actual values
511
523
int mode = -1 ;
@@ -526,16 +538,21 @@ static void select_timer(machine_pwm_obj_t *self, int freq) {
526
538
}
527
539
}
528
540
if (timer < 0 ) {
529
- mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("out of %sPWM timers:%d" ), self -> light_sleep_enable ? "light sleep capable " : "" , self -> light_sleep_enable ? LEDC_TIMER_MAX : LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX );
541
+ mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("out of %sPWM timers:%d" ), self -> lightsleep ? "light sleep capable " : "" , self -> lightsleep ? LEDC_TIMER_MAX : LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX );
530
542
}
531
- // If the timer is found, then bind
543
+ // If the timer is found, then register
532
544
if (self -> timer != timer ) {
533
545
unregister_channel (self -> mode , self -> channel );
534
- // Bind the channel to the timer
546
+ // Rregister the channel to the timer
535
547
self -> mode = mode ;
536
548
self -> timer = timer ;
537
549
register_channel (self -> mode , self -> channel , -1 , self -> timer );
538
550
}
551
+ #if !(CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 )
552
+ if (is_timer_with_different_clock (self -> mode , self -> timer , timers [self -> mode ][self -> timer ].clk_cfg )) {
553
+ mp_raise_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("one or more active timers use a different clock source, not supported by the current SoC." ));
554
+ }
555
+ #endif
539
556
}
540
557
541
558
static void set_freq_duty (machine_pwm_obj_t * self , unsigned int freq ) {
@@ -560,17 +577,48 @@ static void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
560
577
mp_printf (print , ", duty_u16=%d" , get_duty_u16 (self ));
561
578
}
562
579
if (self -> output_invert ) {
563
- mp_printf (print , ", invert=%s" , self -> output_invert ? " True" : "False " );
580
+ mp_printf (print , ", invert=True" );
564
581
}
565
- if (self -> light_sleep_enable ) {
566
- mp_printf (print , ", light_sleep_enable =True" );
582
+ if (self -> lightsleep ) {
583
+ mp_printf (print , ", lightsleep =True" );
567
584
}
568
585
mp_printf (print , ")" );
569
586
570
587
#if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_NORMAL
571
588
mp_printf (print , " # duty=%.2f%%" , 100.0 * get_duty_u16 (self ) / MAX_16_DUTY );
572
589
mp_printf (print , ", raw_duty=%d, resolution=%d" , ledc_get_duty (self -> mode , self -> channel ), timers [self -> mode ][self -> timer ].duty_resolution );
573
590
mp_printf (print , ", mode=%d, timer=%d, channel=%d" , self -> mode , self -> timer , self -> channel );
591
+ int clk_cfg = timers [self -> mode ][self -> timer ].clk_cfg ;
592
+ mp_printf (print , ", clk_cfg=%d=" , clk_cfg );
593
+ if (clk_cfg == LEDC_USE_RC_FAST_CLK ) {
594
+ mp_printf (print , "RC_FAST_CLK" );
595
+ }
596
+ #if SOC_LEDC_SUPPORT_APB_CLOCK
597
+ else if (clk_cfg == LEDC_USE_APB_CLK ) {
598
+ mp_printf (print , "APB_CLK" );
599
+ }
600
+ #endif
601
+ #if SOC_LEDC_SUPPORT_XTAL_CLOCK
602
+ else if (clk_cfg == LEDC_USE_XTAL_CLK ) {
603
+ mp_printf (print , "XTAL_CLK" );
604
+ }
605
+ #endif
606
+ #if SOC_LEDC_SUPPORT_REF_TICK
607
+ else if (clk_cfg == LEDC_USE_REF_TICK ) {
608
+ mp_printf (print , "REF_TICK" );
609
+ }
610
+ #endif
611
+ #if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
612
+ else if (clk_cfg == LEDC_USE_PLL_DIV_CLK ) {
613
+ mp_printf (print , "PLL_CLK" );
614
+ }
615
+ #endif
616
+ else if (clk_cfg == LEDC_AUTO_CLK ) {
617
+ mp_printf (print , "AUTO_CLK" );
618
+ }
619
+ else {
620
+ mp_printf (print , "UNKNOWN" );
621
+ }
574
622
#endif
575
623
} else {
576
624
mp_printf (print , ")" );
@@ -587,20 +635,20 @@ static void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
587
635
static void mp_machine_pwm_init_helper (machine_pwm_obj_t * self ,
588
636
size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
589
637
590
- enum { ARG_freq , ARG_duty , ARG_duty_u16 , ARG_duty_ns , ARG_invert , ARG_light_sleep_enable };
638
+ enum { ARG_freq , ARG_duty , ARG_duty_u16 , ARG_duty_ns , ARG_invert , ARG_lightsleep };
591
639
mp_arg_t allowed_args [] = {
592
640
{ MP_QSTR_freq , MP_ARG_INT , {.u_int = -1 } },
593
641
{ MP_QSTR_duty , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = -1 } },
594
642
{ MP_QSTR_duty_u16 , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = -1 } },
595
643
{ MP_QSTR_duty_ns , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = -1 } },
596
644
{ MP_QSTR_invert , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = self -> output_invert } },
597
- { MP_QSTR_light_sleep_enable , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = self -> light_sleep_enable } },
645
+ { MP_QSTR_lightsleep , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = self -> lightsleep } },
598
646
};
599
647
mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
600
648
mp_arg_parse_all (n_args , pos_args , kw_args ,
601
649
MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
602
650
603
- self -> light_sleep_enable = args [ARG_light_sleep_enable ].u_bool ;
651
+ self -> lightsleep = args [ARG_lightsleep ].u_bool ;
604
652
605
653
int freq = args [ARG_freq ].u_int ;
606
654
if (freq != -1 ) {
@@ -628,7 +676,7 @@ static void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
628
676
int channel = -1 ;
629
677
find_channel (self , & mode , & channel , freq );
630
678
if (channel < 0 ) {
631
- mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("out of %sPWM channels:%d" ), self -> light_sleep_enable ? "light sleep capable " : "" , self -> light_sleep_enable ? LEDC_CHANNEL_MAX : LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX );
679
+ mp_raise_msg_varg (& mp_type_RuntimeError , MP_ERROR_TEXT ("out of %sPWM channels:%d" ), self -> lightsleep ? "light sleep capable " : "" , self -> lightsleep ? LEDC_CHANNEL_MAX : LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX );
632
680
}
633
681
self -> mode = mode ;
634
682
self -> channel = channel ;
@@ -659,7 +707,7 @@ static void self_reset(machine_pwm_obj_t *self) {
659
707
self -> channel_duty = -1 ;
660
708
self -> output_invert = false;
661
709
self -> output_invert_prev = false;
662
- self -> light_sleep_enable = false;
710
+ self -> lightsleep = false;
663
711
}
664
712
665
713
// This called from PWM() constructor
0 commit comments