10000 esp32/machine_pwm: re-use existing timer if possible. · micropython/micropython@91a0744 · GitHub
[go: up one dir, main page]

Skip to content

Commit 91a0744

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 8716dcc commit 91a0744

File tree

1 file changed

+52
-28
lines changed

1 file changed

+52
-28
lines changed

ports/esp32/machine_pwm.c

Lines changed: 52 additions & 28 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,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,16 @@ 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) {
139-
bool used = false;
137+
// return true if the timer is in use in addition to curr_channel
138+
STATIC bool is_timer_in_use(int curr_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 != curr_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
/******************************************************************************/
@@ -204,13 +195,13 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
204195
int timer;
205196
int freq = args[ARG_freq].u_int;
206197

207-
//Check if freq wasn't passed as an argument
198+
// Check if freq wasn't passed as an argument
208199
if (freq == -1) {
209200
// Check if already set, otherwise use the defaut freq
210201
freq = chan_timer[self->channel] != -1 ? timers[chan_timer[self->channel]].freq_hz : PWFREQ;
211202
}
212203

213-
timer = found_timer(freq);
204+
timer = found_timer(freq, false);
214205

215206
if (timer == -1) {
216207
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
@@ -289,10 +280,15 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
289280
// Valid channel?
290281
if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) {
291282
// Clean up timer if necessary
292-
cleanup_timer(chan, chan_timer[self->channel]);
283+
if (!is_timer_in_use(chan, chan_timer[chan])) {
284+
ledc_timer_rst(PWMODE, chan_timer[chan]);
285+
// Flag it unused
286+
timers[chan_timer[chan]].freq_hz = -1;
287+
}
293288

294289
// Mark it unused, and tell the hardware to stop routing
295290
chan_gpio[chan] = -1;
291+
chan_timer[chan] = -1;
296292
ledc_stop(PWMODE, chan, 0);
297293
self->active = 0;
298294
self->channel = -1;
@@ -311,24 +307,52 @@ STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) {
311307

312308
// set
313309
int tval = mp_obj_get_int(args[1]);
314-
cleanup_timer(self->channel, chan_timer[self->channel]);
315310

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

319-
if (new_timer == -1) {
320-
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
315+
int current_timer = chan_timer[self->channel];
316+
int new_timer = -1;
317+
bool current_in_use = is_timer_in_use(self->channel, current_timer);
318+
319+
// Check if an already running with the same freq is running
320+
new_timer = found_timer(tval, true);
321+
322+
// If no existing timer was found, and the current one is in use, then find a new one
323+
if (new_timer == -1 && current_in_use) {
324+
// Have to found a new timer
325+
new_timer = found_timer(tval, false);
326+
327+
if (new_timer == -1) {
328+
mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers"));
329+
}
321330
}
322331

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

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"));
348+
current_timer = new_timer;
327349
}
328350

329-
if (!set_freq(tval, &timers[new_timer])) {
351+
// Set the freq
352+
if (!set_freq(tval, &timers[current_timer])) {
330353
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval);
331354
}
355+
332356
return mp_const_none;
333357
}
334358

0 commit comments

Comments
 (0)
0