-
Notifications
You must be signed in to change notification settings - Fork 220
Conversation
how can I merge this into my local rep so that I can compile and test it ? |
@pacmac |
Thanks so much, simple when you know how :-) I learnt something today. |
Will this allow to wake up on either an external interrupt (pin) or a timeout (RTC) if no pin triggers it within a certain timeframe? Because that would be awesome. Can't wait! |
@formatc1702: Yes, that should work. |
I've compiled this and tested, with everything working as expected. I also merged against the latest esp32 branch and everything still worked as expected. @formatc1702 I explicitly checked your case and it works fine - the following code will wake after 30 seconds or as soon as the pin is brought low: p.init(p.IN, p.PULL_UP)
r.wake_on_ext0(pin = p, level = 0)
m.deepsleep(sleep_ms=30000) @MrSurly I'm not sure what relevance the datetime code has to the deep sleep feature being implemented. Should that really be part of this PR? |
Out of interest I tried uncommenting the wake_on_touch function. If That can totally be a separate feature I feel. Let's just get the basics in! |
This PR could be better named "Implement |
Yeah, I think the connection comes about because on some of the other
platforms the RTC is what wakes the CPU from deepsleep (eg:
machine.RTC.wakeup)
|
@nickzoic Speaking of which -- are there any more roadblocks to merging this? |
Are we ever going to have deepsleep on the esp32 ?, this seems to be taking a VERY long time and so many real-life projects are dependant upon this. |
@dpgeorge if you're generally happy w/ this approach I'm happy to do some testing ... |
I'll fix up the conflicts. |
@MrSurly did you consider changing the API for pin-wakeup as proposed here: #32 (comment) ? |
@dpgeorge I did definitely consider it, and I put a lot of weight on matching existing API. However, that API is very closely tied to the PyBoard hardware, and I personally don't think it's a good idea trying to make substantially different hardware adhere to it. To recap:
It's I'm totally OK with changing the API, but I need a concrete example of how it could work with the ESP32 capabilities in a way that isn't unnecessarily confusing. |
That API was also designed with the cc3200 in mind and the cc3200 port does implement it (for the most part). It was hoped that that API would be good enough for other MCU's as well.
Option 1: use the Pin.irq() method to configure everything and make it smart so it selects ext0 and/or ext1, and raises an exception if the combination of wake pins isn't supported. Eg: pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # configures ext0
pin2.irq(trigger=Pin.IRQ_HIGH_LEVEL, wake=machine.DEEPSLEEP) # configures ext1 with "any high"
pin3.irq(trigger=Pin.IRQ_HIGH_LEVEL, wake=machine.DEEPSLEEP) # reconfigures ext1 with "any high" with pin2 and pin3
pin4.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # raises an exception, no resources left Note that Option 2: use the Pin.irq() method just to configure 1 pin using ext0, then a special esp method for ext1. Eg: pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # configures ext0
pin2.irq(trigger=Pin.IRQ_HIGH_LEVEL, wake=machine.DEEPSLEEP) # raises an exception, no resources left
import esp
esp.wake_on_ext1(pins=(...), level=...) # configure special ext1 Option 2 is simpler to implement and at least gives a similar API for the simplest case of 1 pin waking the device. But Option 1 is not that much more difficult to implement and gives more generality. |
Maybe a hybrid approach. I place value on code readability, thus I think EXT1 should be explicit. I get that the code should work the same as other ports (though arguably this is definitely hardware specific), at least for EXT0, so perhaps: pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # configures ext0, matches CC3200
pin2.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # Raises exception, no resources left
pin1.irq(wake=None) # removed Pin 1 from wake
pin2.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # Now pin 2 works for EXT0
pin5.irq(trigger=Pin.EXT1_ANY_HIGH, wake=machine.DEEPSLEEP) # configures ext1 with "any high"
pin6.irq(trigger=Pin.EXT1_ANY_HIGH, wake=machine.DEEPSLEEP) # reconfigures ext1 with "any high" with pin2 and pin3
pin7.irq(trigger=Pin.EXT1_ALL_LOW, wake=machine.DEEPSLEEP) # raises an exception, no resources left One other thing to consider is the Presently: pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP)
machine.deepsleep()```
But what does the following do?
```python
pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP)
machine.lightsleep() I'd argue to deprecate pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.SLEEP) # << Note 'SLEEP' instead of 'DEEPSLEEP'
machine.deepsleep() # deprecated, but still exists as an alias for machine.sleep(type = machine.DEEPSLEEP)
# or
machine.sleep(type = machine.DEEPSLEEP)
# or
machine.sleep(type = machine.LIGHTSLEEP) Using |
I get your point, but the idea of machine is to be generic and provide a unified interface for all ports. Ports should try their best to conform to the API, rather than adding lots of specific things. The idea of "EXT1" is very specific to esp32 so I think if you want to make it clear that your using this special feature then it should go in the esp module (perhaps even an esp32 module since esp8266 doesn't have this feature...).
The machine module has sleep() and deepsleep(). The former is used exactly in the case where execution resums from where it left off. In fact, I'd argue that machine.sleep() should be renamed to machine.lightsleep() to make this behaviour a bit more clear, and also to disambiguate from time.sleep() which has different semantics (it's not a low-power sleep). There are also machine.SLEEP and machine.DEEPSLEEP constants to say that you want the entity (eg pin) to wake the device from these sleep states. So I think the existing API does cover the esp32's deepsleep and ligthsleep modes. |
Okay, then, how about:
Issues:
Ah, okay. Showing my ignorance =P That will work well, then. |
Hello all, has this stalled again ?? |
Welcome to open source development, where everyone is busy, and nobody gets paid. (Apologies to Whose Line Is It Anyway?) In all seriousness, it is open source -- there's nothing stopping you from using the code right now. Others (e.g. the SHA2017 folks) simply make their own fork and cherry pick the PRs they want. Presumably with the hope of reconciling their Python code with whatever final API shakes out in the future. |
Screwed up a rebase pretty badly, reopening |
@MrSurly your suggestions above in #85 (comment) sound good!
Yes, it should just accept the level-based trigger in the pin.irq() method. |
@dpgeorge |
@dpgeorge
The IDF only allows falling, rising, any edge, low, or high, which makes sense. The documentation above seems a bit odd -- why would you combine an edge trigger with a level, or why would you combine both levels? I'm going to move forward with implementing what the IDF can actually do. |
Here's the plan I'm trying to pursue for ext0:
Problems:
Possible solution:
|
Current API: Basic sleepimport machine
machine.deepsleep() # Sleep until hard reboot
machine.deepsleep(5000) # Deep sleep for 5 seconds
EXT0 wakeups, using the common Micropython idiomEXT0 wakes are for a single pin, either high or low level. This is separate from the IRQ handler; the Additionally, any EXT0 wake will fail if >>> import machine
>>> def h(*args): print(args)
...
>>> p1 = machine.Pin(26)
>>> p2 = machine.Pin(27)
>>> p1.irq(trigger = machine.Pin.WAKE_LOW, wake = machine.DEEPSLEEP)
<IRQ>
>>> p2.irq(trigger = machine.Pin.WAKE_LOW, wake = machine.DEEPSLEEP)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: no resources
>>> p1.irq(trigger=machine.Pin.IRQ_RISING, handler = h) # Clears EXT0 wake
>>> p2.irq(trigger = machine.Pin.WAKE_LOW, wake = machine.DEEPSLEEP) # EXT0 now assigned to p2
<IRQ> Other changes to
|
@pacmac @nickzoic @SmileyChris Any testing/comments you could provide would be appreciated. |
Oh, also, shout out to @manningt for the |
Squashed, pushed. |
* Implement deep sleep using the Pin.irq() idiom * Stub for light sleep, when it works in the IDF * Implement machine.reset_cause() * Implement machine.wake_reason() * Add top-level esp32 module * esp32.wake_on_touch() * esp32.wake_on_ext0() * esp32.wake_on_ext1() * Implement machine.RTC * machine.RTC.datetime() * machine.RTC.memory()
NUDGE Ready for testing/merging |
I'll have a look as soon as I get a chance ...
|
I've been running a prototype alarm clock with this branch for a few days now on an MH-ET Live Mini. Works completely as expected using the ntptime module from esp8266. Thanks for your work! EDIT: if there's anything specific you'd like to have feedback on, please say so, I'd be happy to test things out. |
Just started hacking on ESP32s this week. Would love to see this land ASAP! |
Nice work, RTC() works as expected for me. utime however counts from 2000, whereas RTC() counts from 1970 - utime.localtime() is off by 30 years. |
Counting from year 2000 is intended - refer to: https://docs.micropython.org/en/latest/esp8266/library/utime.html?highlight=utime |
|
Moved to the main MP repo |
I downloaded "esp32-20180216-v1.9.3-315-g73d1d20b.bin (latest)" in 'http://www.micropython.org/download#esp32' to my ESP32 board. However, I can't use RTC. What should I do to use RTC? Followings are error messages.
|
@choies1 this feature (machine.RTC) was only just merged. It should appear in the next latest build, shortly. |
RTC works from 'esp32-20180217-v1.9.3-318-g60c6b880.bin (latest)'. |
EXT0 wake:
EXT1 wake:
Timer wake:
Datetime: