Skip to content

Commit 117fedc

Browse files
committed
esp32/machine_pwm.c: Fix lightsleep.
Rename light_sleep_enable to lightsleep. Signed-off-by: Ihor Nehrutsa <[email protected]>
1 parent 59338e1 commit 117fedc

File tree

1 file changed

+94
-47
lines changed

1 file changed

+94
-47
lines changed

ports/esp32/machine_pwm.c

+94-47
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
#include "esp_clk_tree.h"
4141
#include "py/mpprint.h"
4242

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__);
4444

4545
#define FADE 0
4646

@@ -80,7 +80,7 @@ typedef struct _machine_pwm_obj_t {
8080
int8_t mode;
8181
int8_t channel;
8282
int8_t timer;
83-
bool light_sleep_enable;
83+
bool lightsleep;
8484
int32_t freq;
8585
int8_t duty_scale; // DUTY_10 if duty(), DUTY_16 if duty_u16(), DUTY_NS if duty_ns()
8686
int duty_ui; // saved values of UI duty
@@ -90,9 +90,9 @@ typedef struct _machine_pwm_obj_t {
9090
} machine_pwm_obj_t;
9191

9292
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
9696
} chans_t;
9797

9898
// List of PWM channels
@@ -109,33 +109,38 @@ static timers_t timers[LEDC_SPEED_MODE_MAX][LEDC_TIMER_MAX];
109109

110110
// register-unregister channel
111111
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;
116125
}
117-
#define unregister_channel(mode, channel) register_channel(mode, channel, -1, -1)
118126

119127
static void pwm_init(void) {
120128
for (int mode = 0; mode < LEDC_SPEED_MODE_MAX; ++mode) {
121129
// Initial condition: no channels assigned
122130
for (int channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) {
123131
unregister_channel(mode, channel);
124-
chans[mode][channel].light_sleep_enable = false;
125132
}
126133
// Initial condition: no timers assigned
127134
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);
131136
}
132137
}
133138
}
134139

135140
// Returns true if the timer is in use in addition to current channel
136141
static bool is_timer_in_use(int mode, int current_channel, int timer) {
137142
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)) {
139144
return true;
140145
}
141146
}
@@ -156,22 +161,19 @@ static void pwm_deinit(int mode, int channel, int level) {
156161
.speed_mode = mode,
157162
.timer_num = timer,
158163
};
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);
164166
}
165167
}
166168

167169
int pin = chans[mode][channel].pin;
168170
if (pin >= 0) {
169171
// Disable LEDC output, and set idle level
170172
check_esp_err(ledc_stop(mode, channel, level));
171-
if (chans[mode][channel].light_sleep_enable) {
173+
if (chans[mode][channel].lightsleep) {
172174
// Enable SLP_SEL to change GPIO status automantically in lightsleep.
173175
check_esp_err(gpio_sleep_sel_en(pin));
174-
chans[mode][channel].light_sleep_enable = false;
176+
chans[mode][channel].lightsleep = false;
175177
}
176178
}
177179
unregister_channel(mode, channel);
@@ -216,9 +218,10 @@ static int duty_to_ns(machine_pwm_obj_t *self, int duty) {
216218
return ((int64_t)duty * 1000000000LL + (int64_t)self->freq * (int64_t)(MAX_16_DUTY / 2)) / ((int64_t)self->freq * (int64_t)MAX_16_DUTY);
217219
}
218220

219-
// Reconfigure PWM pin output as input/output. This allows to read the pin level.
221+
// Reconfigure PWM pin output as input/output.
220222
static void reconfigure_pin(machine_pwm_obj_t *self) {
221223
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0)
224+
// This allows to read the pin level.
222225
gpio_set_direction(self->pin, GPIO_MODE_INPUT_OUTPUT);
223226
#endif
224227
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) {
259262
check_esp_err(ledc_update_duty(self->mode, self->channel));
260263
#endif
261264
}
262-
if (self->light_sleep_enable) {
265+
if (self->lightsleep) {
263266
// Disable SLP_SEL to change GPIO status automantically in lightsleep.
264267
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;
266269
}
267270
register_channel(self->mode, self->channel, self->pin, self->timer);
268271
}
@@ -360,6 +363,16 @@ static ledc_clk_cfg_t find_clock_in_use() {
360363
}
361364
return LEDC_AUTO_CLK;
362365
}
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+
}
363376
#endif
364377

365378
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)
371384
// Set timer frequency
372385
static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
373386
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)) {
377388
ledc_timer_config_t timer = {};
378389
timer.speed_mode = self->mode;
379390
timer.timer_num = self->timer;
@@ -382,7 +393,7 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
382393

383394
timer.clk_cfg = LEDC_AUTO_CLK;
384395

385-
if (self->light_sleep_enable) {
396+
if (self->lightsleep) {
386397
timer.clk_cfg = LEDC_USE_RC_FAST_CLK; // 8 or 20 MHz
387398
} else {
388399
#if SOC_LEDC_SUPPORT_APB_CLOCK
@@ -402,9 +413,9 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
402413
#endif
403414
}
404415
#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)) {
408419
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."));
409420
}
410421
#endif
@@ -426,6 +437,7 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq) {
426437
if (self->mode == LEDC_LOW_SPEED_MODE) {
427438
check_esp_err(ledc_timer_rst(self->mode, self->timer));
428439
}
440+
timers[self->mode][self->timer].freq = freq;
429441
timers[self->mode][self->timer].duty_resolution = timer.duty_resolution;
430442
timers[self->mode][self->timer].clk_cfg = timer.clk_cfg;
431443
}
@@ -454,7 +466,7 @@ static void find_channel(machine_pwm_obj_t *self, int *ret_mode, int *ret_channe
454466
// Try to find self channel first
455467
for (int mode = 0; mode < LEDC_SPEED_MODE_MAX; ++mode) {
456468
#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)) {
458470
continue;
459471
}
460472
#endif
@@ -469,7 +481,7 @@ static void find_channel(machine_pwm_obj_t *self, int *ret_mode, int *ret_channe
469481
// Find free channel
470482
for (int mode = 0; mode < LEDC_SPEED_MODE_MAX; ++mode) {
471483
#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)) {
473485
continue;
474486
}
475487
#endif
@@ -487,7 +499,7 @@ static void find_channel(machine_pwm_obj_t *self, int *ret_mode, int *ret_channe
487499
static void find_timer(machine_pwm_obj_t *self, int freq, int *ret_mode, int *ret_timer) {
488500
for (int mode = 0; mode < LEDC_SPEED_MODE_MAX; ++mode) {
489501
#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)) {
491503
continue;
492504
}
493505
#endif
@@ -505,7 +517,7 @@ static void find_timer(machine_pwm_obj_t *self, int freq, int *ret_mode, int *re
505517

506518
// Try to find a timer with the same frequency in the current mode, otherwise in the next mode.
507519
// 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.
509521
static void select_timer(machine_pwm_obj_t *self, int freq) {
510522
// mode, channel, timer may be -1(not defined) or actual values
511523
int mode = -1;
@@ -526,16 +538,21 @@ static void select_timer(machine_pwm_obj_t *self, int freq) {
526538
}
527539
}
528540
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);
530542
}
531-
// If the timer is found, then bind
543+
// If the timer is found, then register
532544
if (self->timer != timer) {
533545
unregister_channel(self->mode, self->channel);
534-
// Bind the channel to the timer
546+
// Rregister the channel to the timer
535547
self->mode = mode;
536548
self->timer = timer;
537549
register_channel(self->mode, self->channel, -1, self->timer);
538550
}
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
539556
}
540557

541558
static void set_freq_duty(machine_pwm_obj_t *self, unsigned int freq) {
@@ -560,17 +577,47 @@ static void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
560577
mp_printf(print, ", duty_u16=%d", get_duty_u16(self));
561578
}
562579
if (self->output_invert) {
563-
mp_printf(print, ", invert=%s", self->output_invert ? "True" : "False");
580+
mp_printf(print, ", invert=True");
564581
}
565-
if (self->light_sleep_enable) {
566-
mp_printf(print, ", light_sleep_enable=True");
582+
if (self->lightsleep) {
583+
mp_printf(print, ", lightsleep=True");
567584
}
568585
mp_printf(print, ")");
569586

570587
#if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_NORMAL
571588
mp_printf(print, " # duty=%.2f%%", 100.0 * get_duty_u16(self) / MAX_16_DUTY);
572589
mp_printf(print, ", raw_duty=%d, resolution=%d", ledc_get_duty(self->mode, self->channel), timers[self->mode][self->timer].duty_resolution);
573590
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+
} else {
619+
mp_printf(print, "UNKNOWN");
620+
}
574621
#endif
575622
} else {
576623
mp_printf(print, ")");
@@ -587,20 +634,20 @@ static void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
587634
static void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
588635
size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
589636

590-
enum { ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns, ARG_invert, ARG_light_sleep_enable };
637+
enum { ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns, ARG_invert, ARG_lightsleep };
591638
mp_arg_t allowed_args[] = {
592639
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
593640
{ MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
594641
{ MP_QSTR_duty_u16, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
595642
{ MP_QSTR_duty_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
596643
{ 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} },
644+
{ MP_QSTR_lightsleep, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = self->lightsleep} },
598645
};
599646
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
600647
mp_arg_parse_all(n_args, pos_args, kw_args,
601648
MP_ARRAY_SIZE(allowed_args), allowed_args, args);
602649

603-
self->light_sleep_enable = args[ARG_light_sleep_enable].u_bool;
650+
self->lightsleep = args[ARG_lightsleep].u_bool;
604651

605652
int freq = args[ARG_freq].u_int;
606653
if (freq != -1) {
@@ -628,7 +675,7 @@ static void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
628675
int channel = -1;
629676
find_channel(self, &mode, &channel, freq);
630677
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);
678+
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);
632679
}
633680
self->mode = mode;
634681
self->channel = channel;
@@ -659,7 +706,7 @@ static void self_reset(machine_pwm_obj_t *self) {
659706
self->channel_duty = -1;
660707
self->output_invert = false;
661708
self->output_invert_prev = false;
662-
self->light_sleep_enable = false;
709+
self->lightsleep = false;
663710
}
664711

665712
// This called from PWM() constructor

0 commit comments

Comments
 (0)