-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32/machine_pwm: Add PWM duty_u16() and duty_ns(). #7907
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: Add PWM duty_u16() and duty_ns(). #7907
Conversation
I did a little bit of testing. duty_u16 is fine. The duty_ns seems fine so far, a little bit too short. b.t.w.: I would suggest that you get yourself a simple logic analyzer probe, like the usual 10$ items sold at Amazon etc. The have a sampling rate of 25Mhz/8 channel, which is good enough for low frequency up to ~6MHz. At e.g. AliExpress, you can get 200MHz/16channel (e.g. KingstVIS) device for about 80$. When developing code like this PWM or Encoder, you need independent testing tools. |
This phenomenon of changing duty when changing the frequency also exists in the master branch, but at different frequencies. Like when going form 100000 down to 10000 and 1000Hz. So to be safe, the duty cycle should be set again after changing the frequency. |
The last commit makes the PWM more accurate. |
Could natives English speakers review/correct the docs/esp32/quickref.rst? |
Please report about the good well-tested results. |
you really should consider adding a property for the maximum resolution. It is something that would be super helpful due to the resolution changes that can occur based on the frequency. something like this should also be available for duty_u16 and duty_ns STATIC mp_obj_t machine_pwm_maximum_duty_get(mp_obj_t self_in) {
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)];
return MP_OBJ_NEW_SMALL_INT((1 << timer ->duty_resolution) - 1);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_maximum_duty_get_obj, machine_pwm_maximum_duty_get);
STATIC const mp_obj_property_t machine_pwm_maximum_duty_obj= {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&machine_pwm_maximum_duty_get_obj,
(mp_obj_t)mp_const_none,
(mp_obj_t)mp_const_none},
}; |
@kdschlosser I agree about the actual PWM resolution, but just now |
@IhorNehrutsa Some quick checks: When duty() is set e.g. to 512, it stays like that when the frequency is changed, e.g. i steps 100-1000-10000-100000 up and down. The problem with changing duty comes back when using duty_u16. What also not works well is using duty_ns. At 1 kHz it's fine, at higher frequencies it fails. Some results:
|
I understand. It is best for another PR once things are functioning properly. |
It is still not working well. Three examples:
results in a duty_ns value of 600ns instead of 10000 ns.
After the last command, there is no signal anymore, instead of the expected 100 kHz signal. You can only set 100kHz then after rebooting.
The duty is set to 512 = half of the period. Which is 5µs correctly at 100kHz. |
Some improvement about duty_ns staying stable when the frequency changes, but these sequences still fails:
When trying to change freq to 10kHz, the signal disappears. Calling p.duty(512) explicitly brings back the signal. But on the next step to 100k the signal disappears again. When stepping the frequency down it works as expected. b)
This sequence locks up the PWM machine completely. To restart it, a hard reset is required. |
@robert-hh
|
ESP-IDF v4.4-dev-3235-g3e370c4296-dirty |
With V4.3 other things happen:
|
@robert-hh |
Configuring Pin as Output twice in a row is generally not a problem. If you do that outside the PWM call it works well. I see that it is a problem here, which is strange. It looks like a bug. Do you reconfigure the Pin object in your code? |
This commit looks good. The tests from my various post pass now. |
I agree that it is not the common case to reconfigure PWM and the Pin when changing the frequency or duty cycle. So a glitch should not harm. If re-configuring is a problem, then a hint in the docs may be helpful, hoping that someone reads it. |
Two files for tests...
|
Pin(5) is not ideal for tests. |
@robert-hh Do you have time to test pwm_test_freq.py and pwm_test_duty.py ? |
I can do that. What do you expect from the test? |
I noticed that on soft reset PWM will not be disabled. Maybe you could add that. |
From https://docs.micropython.org/en/latest/wipy/tutorial/reset.html?highlight=unaffected A solution is maybe to use try-except-finally in main.py
|
Changing the frequency is done in ESP-IDF ledc_timer_config(). |
The code below shows what is done on ESP32 soft reset. It's a little bit more than just the MP virtual machine. It does indeed not deinit UART or USB or the RAM.
|
I have a question regarding the changes made. I feel it needs to be mentioned if how I think this things works is correct. Would it be useful to provide some kind of a class/static method to return the status of the ISR's. and maybe be able to optionally pass the frequency to the method to see if there is an ISR that is running for that frequency. If no frequency is supplied then it would return the number if ISRs that are currently running. This way if for some reason a user is dynamically creating PWM's and the frequencies are also being set dynamically an easy check can be done to make sure there is an available ISR for 1 and if all ISRs are being used to be able to know if they are able to create a PWM at a given frequency because there is an ISR already running for that frequency. While I know that exception catching can be used to handle it it's more expensive to run then simply asking if it can be made. And asking lends to cleaner code and is easier to follow. |
I could be wrong in my understanding of how it works and if my understanding is not correct if there is someone willing to edjumicate (intentional) me on it I would appreciate it. |
@kdschlosser
Generic ESP32 can generate 8 different PWM frequencies at the same time, ESP32-S2 and ESP32-C3 - 4 different PWM frequencies at the same time. Note: PWM does not use ISR, you may use word "handler" to designate it hardware. Please open new issue to discuss new PWM API methods, like actual PWM resolution and available handlers. This affects other hardware ports. |
@robert-hh @dpgeorge |
Thanks for the work on this! No need to squash, I'll do it during merge. Will do a review first. |
Codecov Report
@@ Coverage Diff @@
## master #7907 +/- ##
==========================================
- Coverage 98.24% 98.23% -0.01%
==========================================
Files 154 154
Lines 20007 20014 +7
==========================================
+ Hits 19656 19661 +5
- Misses 351 353 +2
Continue to review full report at Codecov.
|
@dpgeorge |
I've squashed this and merged it in b491967 Thank you @IhorNehrutsa for the hard work to get this done and in mainline! |
Backward compatible.
Correspond to #7806 and #7887 and #7909