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

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)
0