-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32/machine_pwm.c: Handle multiple timers: Bugfix PWM.deinit() critical error and fix pwm_print() #6654
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
esp32/machine_pwm.c: Handle multiple timers: Bugfix PWM.deinit() critical error and fix pwm_print() #6654
Conversation
pwm_print() show real (duty/resolution) in brackets. Use ESP_EXCEPTIONS() macro.
Several questions on the forum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been using this PR for a few days. In general "it works" :-)
There is also #3608, which is a slightly different, more explicit approach.
A big issue I'm having is that this PR doesn't work with soft-reset. After a soft-reset the PWM unit continues running and when the python code creates a fresh PWM object of the same pin as an existing PWM unit then the outcome is somewhat undefined. At least, during interactive testing I was running into situations where a pin was stuck on an old PWM and despite creating a new one for it in python nothing would change. At the very least, there needs to be an init
method that is called from main.c where the soft-reset comes in that stops all PWM activity.
return 0; | ||
} | ||
return 1; | ||
} | ||
|
||
STATIC int found_timer(int freq, bool same_freq_only) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be called find_timer
int free_timer_found = -1; | ||
int timer; | ||
// Find a free PWM Timer using the same freq | ||
for (timer = 0; timer < LEDC_TIMER_MAX; ++timer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to for (int timer = 0;
// return true if the timer is in use in addition to curr_channel | ||
STATIC bool is_timer_in_use(int curr_channel, int timer) { | ||
int i; | ||
for (i = 0; i < LEDC_CHANNEL_MAX; ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to for (int i = 0;
STATIC void set_duty(esp32_pwm_obj_t *self, uint32_t duty) { | ||
duty &= ((1 << PWRES) - 1); | ||
duty >>= PWRES - timers[chan_timer[self->channel]].duty_resolution; | ||
ESP_EXCEPTIONS(ledc_set_duty(PWMODE, self->channel, duty)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should use check_esp_err
, found in mphalport.c
freq = chan_timer[self->channel] != -1 ? timers[chan_timer[self->channel]].freq_hz : PWFREQ; | ||
} | ||
|
||
timer = found_timer(freq, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to int timer =
} | ||
} | ||
|
||
if (new_timer != -1 && new_timer != current_timer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comment: // If another timer already has the right freq then just switch over to it
How could new_timer == current_timer
here? I believe this whole if statement would be clearer if placed right after the call to found_timer
.
|
||
current_timer = new_timer; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cases here are very confusing and difficult to follow. It would be nice to find a better way to structure this.
chan_timer[self->channel] = new_timer; | ||
|
||
if (ledc_bind_channel_timer(PWMODE, self->channel, new_timer) != ESP_OK) { | ||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("failed to bind timer to channel")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you use check_esp_err
?
} | ||
|
||
// Set the freq | ||
if (!set_freq(tval, &timers[current_timer])) { | ||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use check_esp_err
?
|
||
// Flag it unused | ||
timers[current_timer].freq_hz = -1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this can return here.
FIXED in esp32/machine_pwm: handle multiple timers. #6276 |
Fixes micropython#6654 and fixes micropython#6689
This PR is inherited from esp32/machine_pwm: handle multiple timers. #6276 and replace it.
This PR uses PR ESP32: New feature: EspError exception #6638
This PR was tested together with PR ESP32: New features PCNT() and QUAD() #6639
It is tested with 4 different frequencies at 8 different channels with different duties.
Frequencies and duties are right on proper pins.
Output is