-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
ESP32: new/reworked GPIO hold functionality #8284
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: new/reworked GPIO hold functionality #8284
Conversation
Note, that if the pin = Pin(NUMBER, Pin.OUT, value=1, hold=True)
...
pin.init(value=0, hold=True) and have these always work – including the original config working on a watchdog/internal reset. Without this, one would have to explicitly disable the hold before doing anything else, i.e.: pin = Pin(NUMBER, hold=False)
pin.init(Pin.OUT, value=1, hold=True)
...
pin.init(hold=False)
pin.init(value=0, hold=True) which both looks clunky to me and feels like it'd be forgotten and result in subtle bugs creeping in. I also fear crazy race conditions like a MicroPython task switch occurring between the line releasing the hold and the one changing the config and reapplying the hold, then that other task triggering a reset. This way isn't foolproof – it doesn't use a critical section – but it feels safer. However, it still means that casual use of something like: Pin(NUMBER, Pin.IN) or: pin.value(0) on a held pin would be (silently) ignored. I am basically saying that if you use the |
Actually, I thought a bit more about this but I can't see a clean way of adding this compatibility behaviour that doesn't defeat the new Making Pin(NUMBER, Pin.IN, pull=Pin.PULL_UP) would reconfigure a held pin, but: Pin(NUMBER, Pin.IN) would be ignored. |
2b1bf67
to
5904db9
Compare
Useful to note: iirc it is possible (and IDF docs seem to confirm) to change the pin configuration on a held pin, then call So there is no need to call It would probably also be very nice to add an extra method to allow setting the hold after the Pin is initialized, which would be more explicit than having to re-init the entire pin. So we could do things like:
As for |
5904db9
to
e331b84
Compare
Ah! Good spot. I hadn't realised that the docs were implying this behaviour, but have been able to confirm it in my hardware. So I've simplified my code to move the disable back to the end. I'm still doing it even if hold is then to be immediately re-enabled so that any config changes will be latched.
The I thought about adding a method, but felt that being able to do everything in one hit felt more useful. One could obviously add a method anyway the same as
Yeah, looking at that code I can't see what purpose the use of I'm gonna have a hunt around and see if I can find anyone using |
My bad, I didn't read the read the code before commenting and blindly assumed there'd be a downside.
A better reason might be parity (in addition to |
Interesting. I'd never noticed those methods before (I mainly use MicroPython on ESP32). In the docs it says:
So does this indicate that they are counted as legacy? Or incomplete implementations in the other ports? Other than endless forks of the It looks like it wants to hold the level of a bunch of keypad row output pins through deep-sleep to allow the column input pins to wake the chip on an Note to self: me2d13/cml@40dc5b0 |
e331b84
to
8a22f61
Compare
I've pulled the drive strength commits out of here into #8313 in the hope that they can be accepted faster on their own. |
8a22f61
to
87a7c4c
Compare
87a7c4c
to
653f304
Compare
I've put the I've tried to do all of this as separate commits that can be cherry-picked – e.g., the new power-saving documentation in 41c86f7 stands alone even if nothing else is accepted. However, my documentation of |
bf13807
to
ccef05f
Compare
Rebased this on top of #8313 as the merge conflicts in my local repo were driving me crazy. |
I'm now using this in the wild for a project that requires careful control over pins in deep-sleep to correctly disable external hardware and avoid unnecessary power drain. |
ccef05f
to
d99f23b
Compare
Please rebase on latest master, to pick up the merge of the pin drive strength commits. |
d99f23b
to
32f151b
Compare
If |
32f151b
to
02ece2b
Compare
Fine with me! I've removed the constant completely. I think I'd be happier if this code – and my thinking – could be reviewed by someone with knowledge of the ESP32 architecture. What I've documented seems to work for me in my current project, but I'm nervous about having missed something key in my understanding. |
Quick search for
|
02ece2b
to
d1fe0b6
Compare
d1fe0b6
to
2e3fc57
Compare
This attempts to better explain how pull-ups and pull-downs operate in deep-sleep.
Move pad holding functionality from `pull=PULL_HOLD` constant to new `hold=` argument. `PULL_HOLD` constant is retained for compatibility, but is now equivalend to `pull=None`.
Document new `hold` keyword argument that replaces `pull=Pin.PULL_HOLD`.
Add a new function to control whether held pins will retain their function through deep-sleep.
2e3fc57
to
04e2ceb
Compare
Document new `esp32.gpio_deep_sleep_hold()` function and explain how to use this in quickref to retain pin configuration during deep-sleep.
Change APA102 power handling to not use the (now removed) PULL_HOLD constant.
04e2ceb
to
fbabdbd
Compare
The current pull=Pin.PULL_HOLD argument doesn't make a lot of sense in the context of what it actually does vs what the ESP32 quickref document says it does. This commit removes PULL_HOLD and adds a new hold=True|False keyword argument to Pin()/Pin.init(). Setting this to True will cause the ESP32 to lock the configuration of the pin – including direction, output value, drive strength, pull-up/-down – such that it can't be accidentally changed and will be retained through a watchdog or internal reset. Fixes issue #8283, and see also #8284.
Thanks @jonathanhogg for all the effort on this, with nice clean commits and documentation. I have re-read through this PR and issue #8283, and also looked again at the IDF, and I think your reasoning and implementation here are correct. The API here exposes the IDF functionality in a clean and orthogonal manner, you can enable and disable hold on the GPIO, and enable and disable the hold-during-deep-sleep. |
The current
pull=Pin.PULL_HOLD
argument doesn't make a lot of sense in the context of what it actually does vs what the ESP32 quickref document says it does.This patch proposes dumping this and adding a new
hold=True|False
keyword argument toPin()
/Pin.init()
. Setting this toTrue
will cause the ESP32 to lock the configuration of the pin – including direction, output value, drive strength, pull-up/-down – such that it can't be accidentally changed and will be retained through a watchdog or internal reset.In addition, a new
gpio_deep_sleep_hold(True|False)
function in theesp32
module allows this behaviour to be extended to entering and waking from deep-sleep.Support for configuring output drive strength is also added through the standarddrive
keyword argument and constants:Pin.DRIVE_WEAK
Pin.DRIVE_LOW
Pin.DRIVE_MED
(default pin drive strength)Pin.DRIVE_HIGH
Edit: see comment below about moving of drive strength commits
Will write documentation if this looks like being accepted.
I'm also happy to put back in some kind of legacy compatibility for
pull=Pin.PULL_HOLD
if there's concern that this is being used in the wild for what it actually does (rather than what it's documented as doing).Fixes #8283