-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32/machine_pwm: handle multiple timers. #6276
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
Conversation
d1e7ce0
to
23ca3d4
Compare
23ca3d4
to
edfbe35
Compare
Thanks for the contribution. I understand that PWM on esp32 is lacking because it is fixed to LEDC_TIMER_1 and cannot have independent frequencies on different pins, so an improvement like this is welcome. Compared to #3608 it does not change the API, as described above. Ideally I want to work towards a |
ports/esp32/machine_pwm.c
Outdated
// Find a free PWM Timer using the same freq | ||
for (timer = 0; timer < LEDC_TIMER_MAX; ++timer) { | ||
if (timers[timer].freq_hz == freq) { | ||
break; |
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.
could just return timer
here
ports/esp32/machine_pwm.c
Outdated
break; | ||
} | ||
if ((timer_found == -1) && (timers[timer].freq_hz == -1)) { | ||
timer_found = 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.
could just return timer
here
ports/esp32/machine_pwm.c
Outdated
timer_found = timer; | ||
} | ||
} | ||
if (timer >= LEDC_TIMER_MAX) { |
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.
could just return -1
here if above suggestions are used
ports/esp32/machine_pwm.c
Outdated
int freq = args[ARG_freq].u_int; | ||
|
||
if (freq == -1) { | ||
freq = PWFREQ; |
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.
If freq
is not passed in as an argument (so it's -1) then the frequency should not be reconfigured (that's the existing behaviour of this function). Eg:
pwm = machine.PWM(machine.Pin(0), freq=500)
pwm.init(duty=200) # this should retain the existing freq setting
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 think this can be fixed by:
if (chan_timer[self->channel] == -1) {
freq = PWFREQ;
} else {
freq = timers[chan_timer[self->channel]].freq_hz;
}
Hi @dpgeorge, thanks for the review. Regarding the init, I think I kept the behavior you described. It freq is not passed in as an argument, I just set the freq with the default value. And that was the case before. (channel struct init). The main difference, is that not reuse the "global" frequencie. Not sure about this one. Let me know. |
edfbe35
to
7bf1bc8
Compare
Before this patch the behaviour was:
With the patch running the same code gives:
Note the last line: the freq changed back to 5000 for this patch. |
Understood. I will work on it. Thanks. |
3237d03
to
3913bd6
Compare
Thanks for updating, it looks good now, is this ready to merge? (the CI failures can be ignored) |
Actually, doing some tests, it seems that, even with only 1 active PWM, changing the frequency while it's active does not work. Eg:
The pin stops outputing a PWM signal. |
ports/esp32/machine_pwm.c
Outdated
} | ||
|
||
// set | ||
int tval = mp_obj_get_int(args[1]); | ||
if (!set_freq(tval)) { | ||
cleanup_timer(self->channel, chan_timer[self->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.
I think it's important to make it so that there is a smooth transition to another frequency, if the same timer that's currently connected to the pin/channel can be reused. Eg, when freq changes, if the timer on this pin is not used by any other PWM channel, and there is no other timer with the requested freq, then just call set_freq()
on the current timer.
I think all you valuable review has been taken in account. I made some tests with the oscilloscope today. It seems pretty ok. But It would be better if we have some tests suite around that. Whats will be the best way to do that ? (it could be an other PR) |
With the latest changes it seems that there is an error when trying to increase the frequency on a pin. Eg:
|
6e87272
to
62b53fa
Compare
62b53fa
to
f629bc2
Compare
f629bc2
to
4bf8c33
Compare
Are any problems still exist with this PR? |
@dpgeorge, I think this PR is mature now. Can I do something to move forward on it ? |
a7024c0
to
91a0744
Compare
return true; | ||
} | ||
} | ||
|
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.
Newline not really needed
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.
Not sure about that one. Consistency is not matched in this file.
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.
That's fair, but I just don't see why it's needed :)
The commit messages should start with a capital after the colon, see other commits in the repository. So for the first commit that would be for instance:
|
This commit allow to use all the available timer for the ledc subsystem, without affecting the API. If a new frequency is set, first it check if an other timer is using the same freq. If yes, then it use this timer, otherwise it create a new one. If all timers are used, the user should set an already used frequency, or de-init a channel.
f6dc6a2
to
8239774
Compare
ports/esp32/machine_pwm.c
Outdated
// Find a free PWM Timer using the same freq | ||
for (timer = 0; timer < LEDC_TIMER_MAX; ++timer) { | ||
if (timers[timer].freq_hz == freq) { | ||
// A timer already use the same freq. Use it now. |
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.
'already use' -> 'already uses' (sorry missed this one earlier)
In order to smooth the pwm transition. If the timer is only use by one channel just set the frequency.
8239774
to
4bfa0ed
Compare
@dpgeorge how can i move forward on this work ? |
I think this PR is completely ready for approval and I see no reason to further postpone its implementation. |
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 see two issues: one is that the error code on esp-idf calls are not checked (all it takes is wrapping the call in check_esp_err) and that some initialization routine needs to be tied into the soft reset in main.c so PWM isn't in a limbo state after a soft reset.
return MP_OBJ_NEW_SMALL_INT(duty); | ||
} | ||
|
||
// set | ||
duty = mp_obj_get_int(args[1]); | ||
duty &= ((1 << PWRES) - 1); | ||
duty >>= PWRES - timer_cfg.duty_resolution; | ||
duty >>= PWRES - timers[chan_timer[self->channel]].duty_resolution; | ||
ledc_set_duty(PWMODE, self->channel, duty); | ||
ledc_update_duty(PWMODE, self->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.
Why do you no longer check the error code on these two calls?
This pull request is obsolete since |
Aah, sorry for not getting back to this! @IhorNehrutsa thanks for working on it. Can you please explain (briefly) how your #7817 is different to this one? Is it just that you updated it to work with latest master and the new |
This commit allows using all the available PWM timers (up to 8) and channels (up to 16), without affecting the PWM API. If a new frequency is set, first it checks if another timer is using the same frequency. If yes, then it uses this timer, otherwise, it creates a new one. If all timers are used, the user should set an already used frequency, or de-init a channel. This work is based on #6276 and #3608.
This commit allow to use all the available timer for the ledc subsystem,
without affecting the API.
If a new frequency is set, first it check if an other timer is using
the same freq.
If yes, then it use this timer, otherwise it create a new one.
If all timers are used, the user should set an already used frequency,
or de-init a channel.
This PR is related to the work done in #3608, but without the API changes.
Tested on esp32-wrover.