Skip to content

Commit 8239774

Browse files
author
Antoine Aubert
committed
esp32/machine_pwm: re-use existing timer if possible.
In order to smooth the pwm transition. If the timer is only use by one channel just set the frequency.
1 parent d4b614a commit 8239774

File tree

1 file changed

+50
-29
lines changed

1 file changed

+50
-29
lines changed

ports/esp32/machine_pwm.c

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ STATIC int set_freq(int newval, ledc_timer_config_t *timer) {
116116
return 1;
117117
}
118118

119-
STATIC int found_timer(int freq) {
119+
STATIC int found_timer(int freq, bool same_freq_only) {
120120
int free_timer_found = -1;
121121
int timer;
122122
// Find a free PWM Timer using the same freq
@@ -125,34 +125,25 @@ STATIC int found_timer(int freq) {
125125
// A timer already use the same freq. Use it now.
126126
return timer;
127127
}
128-
if ((free_timer_found == -1) && (timers[timer].freq_hz == -1)) {
128+
if (!same_freq_only && (free_timer_found == -1) && (timers[timer].freq_hz == -1)) {
129129
free_timer_found = timer;
130-
// Continue to check if a channel with the same freq is in used.
130+
// Continue to check if a channel with the same freq is in use.
131131
}
132132
}
133133

134134
return free_timer_found;
135135
}
136136

137-
// If the timer is no longer used, clean it
138-
STATIC void cleanup_timer(int prev_channel, int timer) {
139-
bool used = false;
137+
// Return true if the timer is in use in addition to current channel
138+
STATIC bool is_timer_in_use(int current_channel, int timer) {
140139
int i;
141140
for (i = 0; i < LEDC_CHANNEL_MAX; ++i) {
142-
if (i != prev_channel && chan_timer[i] == timer) {
143-
used = true;
144-
break;
141+
if (i != current_channel && chan_timer[i] == timer) {
142+
return true;
145143
}
146144
}
147145

148-
// If timer is not used, clean it
149-
if (!used) {
150-
ledc_timer_pause(PWMODE, timer);
151-
152-
// Flag it unused
153-
timers[timer].freq_hz = -1;
154-
chan_timer[prev_channel] = -1;
155-
}
146+
return false;
156147
}
157148

158149
/******************************************************************************/
@@ -210,8 +201,7 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
210201
freq = chan_timer[self->channel] != -1 ? timers[chan_timer[self->channel]].freq_hz : PWFREQ;
211202
}
212203

213-
timer = found_timer(freq);
214-
204+
timer = found_timer(freq, false);
215205
if (timer == -1) {
216206
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
217207
}
@@ -289,10 +279,15 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
289279
// Valid channel?
290280
if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) {
291281
// Clean up timer if necessary
292-
cleanup_timer(chan, chan_timer[self->channel]);
282+
if (!is_timer_in_use(chan, chan_timer[chan])) {
283+
ledc_timer_rst(PWMODE, chan_timer[chan]);
284+
// Flag it unused
285+
timers[chan_timer[chan]].freq_hz = -1;
286+
}
293287

294288
// Mark it unused, and tell the hardware to stop routing
295289
chan_gpio[chan] = -1;
290+
chan_timer[chan] = -1;
296291
ledc_stop(PWMODE, chan, 0);
297292
self->active = 0;
298293
self->channel = -1;
@@ -311,22 +306,48 @@ STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) {
311306

312307
// set
313308
int tval = mp_obj_get_int(args[1]);
314-
cleanup_timer(self->channel, chan_timer[self->channel]);
315309

316-
// Check if a timer already use the new freq, or grab a new one
317-
int new_timer = found_timer(tval);
310+
if (tval == timers[chan_timer[self->channel]].freq_hz) {
311+
return mp_const_none;
312+
}
313+
314+
int current_timer = chan_timer[self->channel];
315+
int new_timer = -1;
316+
bool current_in_use = is_timer_in_use(self->channel, current_timer);
318317

319-
if (new_timer == -1) {
320-
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
318+
// Check if an already running timer with the same freq is running
319+
new_timer = found_timer(tval, true);
320+
321+
// If no existing timer was found, and the current one is in use, then find a new one
322+
if (new_timer == -1 && current_in_use) {
323+
// Have to find a new timer
324+
new_timer = found_timer(tval, false);
325+
326+
if (new_timer == -1) {
327+
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
328+
}
321329
}
322330

323-
chan_timer[self->channel] = new_timer;
331+
if (new_timer != -1 && new_timer != current_timer) {
332+
// Bind the channel to the new timer
333+
chan_timer[self->channel] = new_timer;
334+
335+
if (ledc_bind_channel_timer(PWMODE, self->channel, new_timer) != ESP_OK) {
336+
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to bind timer to channel"));
337+
}
338+
339+
if (!current_in_use) {
340+
// Free the old timer
341+
ledc_timer_rst(PWMODE, current_timer);
342+
// Flag it unused
343+
timers[current_timer].freq_hz = -1;
344+
}
324345

325-
if (ledc_bind_channel_timer(PWMODE, self->channel, new_timer) != ESP_OK) {
326-
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to bind timer to channel"));
346+
current_timer = new_timer;
327347
}
328348

329-
if (!set_freq(tval, &timers[new_timer])) {
349+
// Set the freq
350+
if (!set_freq(tval, &timers[current_timer])) {
330351
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval);
331352
}
332353
return mp_const_none;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy