Skip to content

Commit 4bf8c33

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 daeccc1 commit 4bf8c33

File tree

1 file changed

+51
-25
lines changed

1 file changed

+51
-25
lines changed

ports/esp32/machine_pwm.c

+51-25
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,7 +125,7 @@ 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;
130130
// Continue to check if a channel with the same freq is in used.
131131
}
@@ -134,25 +134,18 @@ STATIC int found_timer(int freq) {
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) {
137+
// return if the timer is in use in addition to curr_channel
138+
STATIC bool is_timer_in_use(int curr_channel, int timer) {
139139
bool used = false;
140140
int i;
141141
for (i = 0; i < LEDC_CHANNEL_MAX; ++i) {
142-
if (i != prev_channel && chan_timer[i] == timer) {
142+
if (i != curr_channel && chan_timer[i] == timer) {
143143
used = true;
144144
break;
145145
}
146146
}
147147

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-
}
148+
return used;
156149
}
157150

158151
/******************************************************************************/
@@ -204,13 +197,13 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
204197
int timer;
205198
int freq = args[ARG_freq].u_int;
206199

207-
//Check if freq wasn't passed as an argument
200+
// Check if freq wasn't passed as an argument
208201
if (freq == -1) {
209202
// Check if already set, otherwise use the defaut freq
210203
freq = chan_timer[self->channel] != -1 ? timers[chan_timer[self->channel]].freq_hz : PWFREQ;
211204
}
212205

213-
timer = found_timer(freq);
206+
timer = found_timer(freq, false);
214207

215208
if (timer == -1) {
216209
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
@@ -289,7 +282,12 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
289282
// Valid channel?
290283
if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) {
291284
// Clean up timer if necessary
292-
cleanup_timer(chan, chan_timer[self->channel]);
285+
if (!is_timer_in_use(chan, chan_timer[chan])) {
286+
ledc_timer_rst(PWMODE, chan_timer[chan]);
287+
// Flag it unused
288+
timers[chan_timer[chan]].freq_hz = -1;
289+
chan_timer[chan] = -1;
290+
}
293291

294292
// Mark it unused, and tell the hardware to stop routing
295293
chan_gpio[chan] = -1;
@@ -311,24 +309,52 @@ STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) {
311309

312310
// set
313311
int tval = mp_obj_get_int(args[1]);
314-
cleanup_timer(self->channel, chan_timer[self->channel]);
315312

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

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

323-
chan_timer[self->channel] = new_timer;
334+
if (new_timer != -1 && new_timer != current_timer) {
335+
// Bind the channel to the new timer
336+
chan_timer[self->channel] = new_timer;
337+
338+
if (ledc_bind_channel_timer(PWMODE, self->channel, new_timer) != ESP_OK) {
339+
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to bind timer to channel"));
340+
}
341+
342+
if (!current_in_use) {
343+
// Free the old timer
344+
ledc_timer_rst(PWMODE, current_timer);
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+
// Flag it unused
347+
timers[current_timer].freq_hz = -1;
348+
}
349+
350+
current_timer = new_timer;
327351
}
328352

329-
if (!set_freq(tval, &timers[new_timer])) {
353+
// Set the freq
354+
if (!set_freq(tval, &timers[current_timer])) {
330355
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval);
331356
}
357+
332358
return mp_const_none;
333359
}
334360

0 commit comments

Comments
 (0)