-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32/machine_pwm: Enhancement of PWM: Add features light_sleep_enable. #16102
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
base: master
Are you sure you want to change the base?
Conversation
a60f5bb
to
4bf685f
Compare
Please have a look at PR #16090 for setting the frequency and duty cycle. That PR fixes a current bug with ESP32S3 and simplifies the setting. |
Yes I've seen it and I've checked that I use the same approach of this PR. I'ven't the chance to test on ESP32-C6 (for PLL_CLOCK) as I've not this Soc in my lab. |
You could add class constants for the clock argument. For that you have to change extmod/machine_pwm.c as well and insert into the local dictionary table a line like:
and then define PLL_CLK works at a ESP32C6. |
4c1d7d7
to
51f1700
Compare
Thanks for your test on ESP32-C6 :-) // A port must add UART class constants defining the following macro.
// It can be defined to nothing if there are no constants.
MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS when adding the define in the table machine_uart_locals_dict_table[] (line: 138 & 164). Does it mean that I've to add a dummy #define in each port ? my proposal is the follwing: // A port may add PWM class constants defining the following macro.
// It can be defined to nothing if there are no constants.
#ifdef MICROPY_PY_MACHINE_PWM_CLASS_CONSTANTS
MICROPY_PY_MACHINE_PWM_CLASS_CONSTANTS
#endif I've pushed the new version. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #16102 +/- ##
=======================================
Coverage 98.57% 98.57%
=======================================
Files 164 164
Lines 21345 21345
=======================================
Hits 21040 21040
Misses 305 305 ☔ View full report in Codecov by Sentry. |
Code size report:
|
@yoann-darche Thanks for the long discussion ahead of implementing this, and for submitting it as a PR. The main concern is really about adding complexity (there's a lot of code here) but also that where possible we try to keep the I've read the discussion and the PR and I understand the extra functionality from adding the |
@projectgus Good point, and it is main raison why I've implemented and auto clock mode to not borrow the developper with that. With it on mind, I think you are right. If look at the table of available clock vs SoC:
The two main options are the "CPU_CLK" (sometimes called APB_CLK or PLL_DIV_CLK) and the RC_FAST_CLK. Clearly, the best choice for precision is the CPU_CLK, which is derived from XTAL_CLK. And the only clock that continues to function in light sleep mode is the RC_FAST_CLK. The other clocks will be used only in very specific cases. I'm fine to keep the clock exposed in order to let the developper to fine tune if necessary @robert-hh : what do you think ? Edit: After some research about the case where we need use XTAL_CLOCK (for example) as the source is very specific and relevant when we change the CPU clock to low frequency (<80Mhz). And in our context it is not relevant. So aggree with @projectgus to remove the clock parameter, and refactor the code to simply it :-) |
I've update the esp32/machine_pwm.c file to remove the clock parameter and constante definition. But I've also to rebase my branch, and I've maybe done some bad things. So now I get the message "This branch cannot be rebased safely". |
You don't need to make a new PR, but there's a merge conflict because we merged #16090. You'll need to update your local working copy and rebase again. There will be some local merge conflicts ("rebase conflicts" I guess) for you to resolve as part of the rebase. If you use the Git CLI then the first steps are something like:
However you might want to read up on resolving conflicts before you dive in. Jimmo has some tips here. If you get totally stuck and think the only way out is to make a new PR then please ping me first and tell me what branch you were going to use for the new PR, I can show you how to update this PR instead of creating a new one. |
0c9cbc4
to
56f820b
Compare
Rebase successfull, thank to the Jimmo tips :-) |
You have now 16 commits in your PR with 5 commits repeated thrice. Better clean that up using |
Test pass on ESP32-S3/ESP32-S2 and ESP32 |
Compiling fails with ESP32C6.
|
It still runs into a bug when compiling. There are duplicated lines. When erasing one of the set, compile succeeds.
Edit: It is the last commit which duplicates the lines. |
d41c91b
to
93591d8
Compare
I've done some tests on ESP32/S2/S3 with the following scenario. And all pass as expected. Compilation Ok for ESP32-C3/C6, Test Script: import os
from machine import PWM, Pin, lightsleep,
from time import sleep_ms
IS_ESP32GEN = 'ESP32' in os.uname().machine
IS_ESP32S2 = 'ESP32-S2' in os.uname().machine
IS_ESP32S3 = 'ESP32S3' in os.uname().machine
# List available pin in function of the SOC
print("\n=====================")
if IS_ESP32S2:
# Support only 8 channels
pinList = (15, 2, 3, 4, 5, 6, 7, 8)
print("ESP32-S2 detected")
elif IS_ESP32S3:
# Support only 8 channels
pinList = (2, 3, 4, 5, 6, 7, 8, 9)
print("ESP32-S3 detected")
elif IS_ESP32GEN:
# support 16 channels (8 in LowSpeed and 8 in HightSpeed)
pinList = (15, 2, 4, 16, 18, 19, 22, 23, 25, 26, 27, 14 , 12, 13, 32, 33)
print("ESP32-GENERIC detected")
if pinList == None:
print("Test Fail: Board not detetected !")
exit(1)
print("=====================\n")
pwms = []
print("\nTest #1: Create all available channels")
# From test in the documentation
try:
f = 100 # Hz
d = 1024 // 16 # 6.25%
for i, pin in enumerate(pinList):
pwms.append(PWM(Pin(pin), freq=f * (i // 2 + 1), duty= 1023 if i==15 else d * (i + 1)))
sleep_ms(200)
print(pwms[i])
finally:
while len(pwms) > 0:
p = pwms.pop()
try:
p.deinit()
except:
print("Error while deinit :",p)
print("\nTest #2: Create all available channels in sleep mode")
try:
for i, pin in enumerate(pinList):
pwms.append(PWM(Pin(pin), freq=f * (i // 2 + 1), duty= 1023 if i==15 else d * (i + 1), light_sleep_enable=True))
sleep_ms(200)
print(pwms[i])
except:
if i>7:
print("In case of ESP32, only low speed mode can use RC_FAST_CLK, so only 8 channels available.")
finally:
while len(pwms) > 0:
p = pwms.pop()
try:
p.deinit()
except:
print("Error while deinit :",p)
print("\nTest #3: Create 2 channel, one in light_sleep mode, second default both shloud run with clock=RC_FAST_CLK")
try:
pLS = PWM(Pin(pinList[0]), freq=10_000, duty=512, light_sleep_enable=True)
sleep_ms(200)
print(pLS)
pDEF = PWM(Pin(pinList[1]), freq=10_000, duty=512)
sleep_ms(200)
print(pDEF)
finally:
pLS.deinit()
pDEF.deinit()
print("\nTest #4: Create 2 channel, one default, second in light_sleep mode shloud generate an exception on the second one")
try:
pLS = PWM(Pin(pinList[0]), freq=10_000, duty=512)
sleep_ms(200)
print(pLS)
try:
pDEF = PWM(Pin(pinList[1]), freq=10_000, duty=512,light_sleep_enable=True)
except:
print("Clock conflict detected !")
finally:
pLS.deinit() Result (concat from output of ESP32, ESP32-S2 and ESP32-S3):
|
93591d8
to
9a62f8e
Compare
Rebase with latest master |
Ok, the code is now ready (and clean). Do I need to provide something else ? |
@projectgus @robert-hh does something need to be done in order to integrate this PR in the next release ? |
There are a few other PRs about ESP32 PWM which may have to get merged first. Then the maintainer may have a look at this PR. So for now you "just" have to wait. |
I'm facing to a complex situation, I've try to follow update on ESP32 to keep teh PR fine, but now I have a mistake somewhere, and I don't how to solve it. The file esp32/machine_pwm is up to date, and it is the only one that I've touch. |
The history of commits looks pretty crowded. So yes, If you changed only a single file, put that aside, start over from the current master and apply the changed machine_pwm.c to that state.
|
Performing a rebase and squash. Enhancement of the PWM constructor by adding a new keywords: light_sleep_enable. Review the precision (of the duty parameter) determination by using the ESP-IDF native function ledc_find_suitable_duty_resolution(). Add LEDC_USE_PLL_DIV_CLK clock source for ESP32-C6 support. Reordering clock source list. Fix some issue inside the PWM.deint(), particulary about the deconfiguration of the timer. Signed-off-by: Yoann Darche <yoannd@hotmail.com>
4e88799
to
2844e29
Compare
Ok, I've clean my PR... I stil have some errors but not related to the ESP32 target witch I've changed ? |
Do not worry about these. |
@yoann-darche Sorry, I was unable to add you as a co-author by means of GitHubDesktop. |
Summary
This PR will add new features of the PWM ESP32 port to enable the use of PWM in ligth sleep mode of the ESP32 series as reported in https://github.com/orgs/micropython/discussions/16033
After some exchange, we have decided to simplify the API and remove the exposer of the clock parameters. We have identified that this parameter dores not bring any adventage and complexify the code.
To perform this we need to add clock source selection of the timer used by the PWM Channel, this selection is totaly transparent and automated.
Adding 1 new keywords to the PWM constructor :
Enhancement of the print PWM object to add information relating the clock source and light sleep enable flag value:
Some parts of the code have been rewritten to improve the precision of duty calculations, Many previously hardcoded instructions have been replaced with IDF utility functions, such as ledc_find_suitable_duty_resolution(), to replace fixed calculations. Alos improved the PWM.deinit() function to correctly unset the timer module.
The code adress SoC hardware limitation for ESP32-S3/C3/C6 that accept only one source of clock for all timer.
Please note dispite of the fact that ESP32 and ESP32-S2 accept multi-clock setup, in our case and with the simplicity in mind, we can not use these capabilites as the APB_CLK is multiplexed with the RC_FAST_CLK. So all SoC does not support multi-clock.
Testing
Test board : ESP32 (high speed mode, and ESP32-S2, ESP32-S3 mono-clock)
Compile test on ESP32-C6
Test concerning API:
Testing light sleep feature
Result:
