Skip to content

ports/esp32:* Implementation of deep sleep, esp32 module, machine.RTC #3531

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

Closed
wants to merge 2 commits into from

Conversation

MrSurly
Copy link
Contributor

@MrSurly MrSurly commented Dec 31, 2017

Note 1: Copied over from the old micropython-esp32 repo.
Note 2: Fixed the 1970/2000 bug in RTC.datetime()

Current API:

Basic sleep

import machine
machine.deepsleep() # Sleep until hard reboot
machine.deepsleep(5000) # Deep sleep for 5 seconds

machine.sleep() is implemented, but currently throws an error. If/when the IDF "light sleep" works, this can be removed.

EXT0 wakeups, using the common Micropython idiom

EXT0 wakes are for a single pin, either high or low level.

This is separate from the IRQ handler; the WAKE_LOW and WAKE_HIGH only setup the EXT0 type wake. Using a value other than WAKE_LOW or WAKE_HIGH will clear the EXT0 wake from that pin.

Additionally, any EXT0 wake will fail if esp32.wake_from_touch(True) has been called, since wake from touch and EXT0 are mutually exclusive in the IDF.

>>> 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 machine

machine.reset_cause() has been implemented, though usually returns machine.WDT_RESET since most of the time the IDF doesn't reset properly. Does properly return machine.DEEPSLEEP_RESET when waking from deep sleep.

machine.wake_reason() has been implemented.

The new top-level esp32 module

esp32.wake_on_touch(<True|False>) Configures waking on touch. Throws ValueError('no resources') in the event that EXT0 is already configured, since they are not compatible. For this to work, you need to use machine.TouchPad().config() to configure the threshold; an interrupt handler is not required.

esp32.wake_on_ext0(<Pin>, level = <0 | 1>). Configures the EXT0 wake. This will raise ValueError('no resources') if esp32.wake_on_touch(True) has been called. It will not raise this error if another pin has already been configured, it will simply configure the new pin for EXT0 and deconfigure the old pin. If level is not specified, then it is unchanged, and defaults to 0 (low).

esp32.wake_on_ext1(pins = <sequence of Pin object>, level = <esp32.WAKEUP_ALL_LOW | esp32.WAKEUP_ANY_HIGH> ): As described above, wake on multiple pins, either "all low" or "any high".

The new machine.RTC module

machine.RTC.datetime() and machine.RTC.init() work as documented in mainline MicroPython.

machine.RTC.memory() Without arguments returns the RTC nonvolatile memory, as bytes. To write memory, pass a bytes, bytearray, or str object.

@mactijn
Copy link

mactijn commented Dec 31, 2017

@MrSurly This patch seems to remove esp_debug stuff, is that intended?
Also, MICROPY_PY_WEBSOCKET is changed to 0, not sure if this is wanted

@MrSurly
Copy link
Contributor Author

MrSurly commented Dec 31, 2017

@MrSurly This patch seems to remove esp_debug stuff, is that intended?
Also, MICROPY_PY_WEBSOCKET is changed to 0, not sure if this is wanted

Unintended side-effects of the merge. Let me get that fixed up.

@MrSurly
Copy link
Contributor Author

MrSurly commented Dec 31, 2017

@mactijn Fixed, squashed, pushed

@mactijn
Copy link

mactijn commented Dec 31, 2017

Funnily enough I ran into a similar thing yesterday.

Anyway, seems to work as promised. I'll do some more testing tomorrow, and hopefully release my M5Stack framework.

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 1, 2018

I'll do some more testing tomorrow, and hopefully release my M5Stack framework.

Is that a MicroPython framework for the M5Stack? I received my hardware a couple of days ago.

@mactijn
Copy link

mactijn commented Jan 1, 2018

Is that a MicroPython framework for the M5Stack? I received my hardware a couple of days ago.

Yep. Awesome stuff. Great support from the supplier. I've ordered the faces kit too, so I can add support for those modules as well.

@Lisa999
Copy link

Lisa999 commented Jan 6, 2018

@MrSurly : Just to let you know, i immediately put your pr to work in my firmware version... ;-)
Wonderful work, just what i needed..

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 6, 2018

@Lisa999 Glad it's working well for you. Please let me know if you have any issues.

@Lisa999
Copy link

Lisa999 commented Jan 13, 2018

tm = (2018, 1, 13, 0, 16, 18, 31, 0)
machine.RTC().datetime(tm)
print(utime.localtime())
(2018, 1, 12, 16, 18, 39, 4, 12)

I'm missing a day?

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 13, 2018

@Lisa999
I think this is an issue with RTC. Under the hood, I'm using C gmtime, and off-setting the year by 1930 (to get to year 2000). Python localtime is using a special function to deal with 2000 vs 1970, and I should probably be using that, because my way likely screws up a leap year somewhere.

I'll take a look tonight (PST).

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 14, 2018

@Lisa999
Fixed, squashed, pushed; give it a shot, please?

@Lisa999
Copy link

Lisa999 commented Jan 17, 2018

git pull origin pull/3531/head
From https://github.com/micropython/micropython
branch refs/pull/3531/head -> FETCH_HEAD
Auto-merging ports/esp32/machine_rtc.c
CONFLICT (add/add): Merge conflict in ports/esp32/machine_rtc.c
Automatic merge failed; fix conflicts and then commit the result.

?

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 17, 2018

@Lisa999
You have a merge conflict. The file in question was changed by two or more different sources, and the changes are not compatible (same lines changed by each source). This usually happens when you edit a file, then attempt to pull or merge code that was modified by someone else.

@Lisa999
Copy link

Lisa999 commented Jan 20, 2018

Ok, resolved (i hope)
Now i get this error:

machine_rtc.c:192:1: error: no return statement in function returning non-void [-Werror=return-type]
};
^
cc1: all warnings being treated as errors
../../py/mkrules.mk:47: recept voor doel 'build/machine_rtc.o' is mislukt
make: *** [build/machine_rtc.o] Fout 1

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 21, 2018

Ok, resolved (i hope)
Now i get this error:

The errors you're experiencing are unusual if you're simply trying to merge this PR into master. I think you have an XY problem. What are you trying to accomplish?

@Lisa999
Copy link

Lisa999 commented Jan 21, 2018

git pull origin master
git pull origin pull/3531/head
And then build so that i have micropython ESP32 master + your PR for using the RTC on ESP32
Dump everything and clone again?

@MrSurly
Copy link
Contributor Author

MrSurly commented Jan 21, 2018

From scratch:

git clone https://github.com/micropython/micropython.git 
cd micropython/
git remote add mrsurly https://github.com/MrSurly/micropython.git
git fetch mrsurly 
git checkout -b my_new_branch
git merge mrsurly/dev-deepsleep

@Lisa999
Copy link

Lisa999 commented Jan 24, 2018

Thx! Worked like a charm!
After a 'git submodule update --init'
Everything is now working as it should be.
Bug solved

@dpgeorge
Copy link
Member

@MrSurly thanks very much for persisting with this and getting it moved across from the old repo to this one. Much appreciated, and sorry for letting it sit for so long.

Most of it looks good, but the main two items to discuss are:

  1. Licensing and copyright: can you please confirm that you and Tom Manning can release this under an MIT license and you didn't in any way use any other code (apart from referring to the IDF) to write this code.

  2. Can I please bother you to split it up into a few commits, like: addition of machine.deepsleep and machine.sleep; addition of machine.RTC class; addition of esp32 module? Or whatever makes the most sense and whatever order of adding them makes the most sense. Thank you!

@@ -23,7 +23,7 @@
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1
#define CONFIG_ESP32_DEBUG_OCDAWARE 1
#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 0
#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly does this do? What is 2000 measured in, seconds?

Copy link
Contributor Author

@MrSurly MrSurly Feb 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly does this do?

Ensures proper wakeup

Discussion here: micropython/micropython-esp32#32 (comment)

2000 is now the default value (instead of 0) in the ESP-IDF as of 9 months ago: espressif/esp-idf@3c583a7

What is 2000 measured in, seconds?

Microseconds

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks, understood.

@MrSurly
Copy link
Contributor Author

MrSurly commented Feb 14, 2018

Can I please bother you to split it up into a few commits, like: addition of machine.deepsleep and machine.sleep; addition of machine.RTC class; addition of esp32 module? Or whatever makes the most sense and whatever order of adding them makes the most sense. Thank you!

Certainly, but n the past, it has been requested (by pfalcon, IIRC) that these sorts of things be not split into multiple commits. I can split this up if desired, but would appreciate consistent policy.

Also not sure if you mean separate commits, or separate PRs for RTC / deepsleep ?

@MrSurly
Copy link
Contributor Author

MrSurly commented Feb 14, 2018

Licensing and copyright: can you please confirm that you and Tom Manning can release this under an MIT license and you didn't in any way use any other code (apart from referring to the IDF) to write this code.

Yes, this code was written by Mr. Manning and myself. You have my full release uner the MIT license. @manningt, You ok with this?

@manningt
Copy link
Contributor

@MrSurly Yes - You have my full release under the MIT license and I didn't in any way use any other code.

@dpgeorge
Copy link
Member

@MrSurly @manningt thanks for confirming re copyright/license.

I can split this up if desired, but would appreciate consistent policy.

Yes I understand it's not always consistent, sorry. In this case adding a new module (esp32) should be a separate commit. And ideally have a separate commit for a new class (RTC). They can just be separate commits in this PR here (no need at all for a new PR). (I would be happy to do the split myself when merging but then I couldn't retain you as the commit author.)

@MrSurly MrSurly closed this Feb 15, 2018
ports/esp32/modmachine*: RTC class, sleep impiementation
ports/esp32/Makefile: Changes to support RTC/sleep
ports/esp32/sdkconfig: Changes to support RTC/sleep
ports/esp32/machine_pin.c: esp32 wake-on-pin changes
ports/esp32/Makefile: modified to support pin wake
ports/esp32/mpconfigport.h: New top-level module for esp32 wake features
@MrSurly
Copy link
Contributor Author

MrSurly commented Feb 15, 2018

@dpgeorge Split.

@dpgeorge
Copy link
Member

Thank you very much @MrSurly and @manningt! Merged in 44033a1 and abec47a with some very minor edits to whitespace formatting.

@dpgeorge dpgeorge closed this Feb 16, 2018
@diginfo
Copy link

diginfo commented Jun 1, 2018

This is also reported here: https://forum.micropython.org/viewtopic.php?f=18&t=4856

This is what I thought would be a simple toggling of the wake pin trigger edge, but it turns out not !

This code should get the current value of door pin, and set the wake from deepsleep edge based on the pin value high or low and then put the device into deepsleep awaiting the trigger edge.

There is a 10K pull-down on pin 34 and the switch pulls it high.

The purpose is to wake up and sleep again each time the interrupt is triggered on a different edge.

The time.sleeps() are just to give time to view the output and should not have any other effect other than de-bouncing, but given that the esp32 startup time is 2 seconds, debouncing should not be needed.

It appears to work the first time deepsleep is fired, but thereafter door.value() always reads 0 even though the switch is closed and pulled high !

boot.py

import machine as mc, time
time.sleep(1)
door = mc.Pin(34,mc.Pin.IN)
edge =  5- door.value()
edgeMc = {
  5:'WAKE_HIGH',
  4:'WAKE_LOW'
}[edge] or 'BAD'

print('door:{}, edge:{}, edgeMc: {}'.format(door.value(), edge, edgeMc))
door.irq(trigger = edge, wake = mc.DEEPSLEEP)

time.sleep(5)
mc.deepsleep(60000)

Initially the switch was low:
door:0, edge:5, edgeMc: WAKE_HIGH

Then switch was then enabled (high):
door:1, edge:4, edgeMc: WAKE_LOW

Then, without changing the switch position, it just continuously loops, apparently unable to read the value of door any more:

door:0, edge:5, edgeMc: WAKE_HIGH
door:0, edge:5, edgeMc: WAKE_HIGH
door:0, edge:5, edgeMc: WAKE_HIGH
door:0, edge:5, edgeMc: WAKE_HIGH
door:0, edge:5, edgeMc: WAKE_HIGH
door:0, edge:5, edgeMc: WAKE_HIGH

@MrSurly
Copy link
Contributor Author

MrSurly commented Jun 2, 2018

@diginfo Please open a new issue rather than necroposting here. I can take a look next week.

@diginfo
Copy link

diginfo commented Jun 2, 2018

Done: #3835

@Singein
Copy link

Singein commented Nov 19, 2018

For this to work, you need to use machine.TouchPad().config() to configure the threshold; an interrupt handler is not required.

machine.TouchPad().config() What parameters are needed?
configure the threshold the threshold means what?

I'm a little confused.

@MrSurly
Copy link
Contributor Author

MrSurly commented Nov 19, 2018

When reading the touchpad, you generally just get a number. When the touch sensor is touched, this value changes. When that change crosses a certain value (the threshold), then it's considered to be triggered.

config() takes a single integer parameter setting the threshold. Generally, you'd read the touchpad value for both touched and not touched, and set the threshold somewhere between. The actual values will vary based on the physical design of your circuit.

@Singein
Copy link

Singein commented Nov 20, 2018

em...Thank you for your answer.
I'm a newbie to MicroPython..So I still have the following confusion:

>>> import machine
>>> from machine import Pin
>>> t = machine.TouchPad(Pin(32))
>>> t.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Touch pad error

Could you please help me again about Touc pad error?
I would be grateful if you could show me the sample code below.

@MrSurly
Copy link
Contributor Author

MrSurly commented Nov 20, 2018

@nickzoic
I'm getting this error as well with touchpads on pins 0, 32, 15, and 33 -- Is there something we're missing?

@manningt
Copy link
Contributor

It works for me on all pins mentioned (0,15,32,33) with the latest release:

MicroPython v1.9.4-684-g51482ba92 on 2018-11-20; ESP32 module with ESP32
Type "help()" for more information.
>>> from machine import TouchPad, Pin
>>> t32 = TouchPad(Pin(32))
>>> t32.read()
1269

The ESP32 PCB I'm using is custom and none of the aforementioned pins are connected to anything. The pin read values returned are all different, but within the expected range.
Not sure why you get the error, but I posted this to show it does work.

@MrSurly
Copy link
Contributor Author

MrSurly commented Nov 20, 2018

Mystery Solved (probably)

Using MP @51482ba92568a9793fea34213ed74be850920a5a (HEAD as of today):

import machine
tp = {}
for i in (4,0,2,15,13,12,14,27,33,32):
 tp[i] = machine.TouchPad(Pin(i))
 
for i,t in tp.items():
 try:
  print (i, end=' ')
  print (t.read(), end = '')
 except:
  print ('error', end = '')
 finally:
  print()

Result:

0 error
32 error
2 290
13 409
14 436
4 260
12 428
27 428
15 error
33 error

Here's why

I've checked the schematic for my board:

GPIO0 is connected to an auto-reset circuit
GPIO32, GPIO33 are connected to pullups for I2C
GPIO15 is connected to a resistor / LED

@MrSurly
Copy link
Contributor Author

MrSurly commented Nov 20, 2018

@fuermohao

It's likely that the pin you're using on your PCB is already connected to something (likely internal to the PCB), resulting in an error (see above). You should use a different pin.

@nickzoic
Copy link
Contributor

nickzoic commented Nov 20, 2018

@fuermohao thanks for reporting this, although this might not be quite the right place for it ...

What board are you using, or if it is a custom board could you let me see a schematic?

I'll check it out, but the pins work with a free-running oscillator, so just about anything connected to them, even pullups/pulldowns and LEDs, will prevent the oscillation from happening at all. I'm not sure whether this will produce the error you mentioned, but I'll check ASAP & we can add this

EDIT: ... "& we can add this to the documentation", I meant to say :-)

@Lisa999
Copy link

Lisa999 commented Nov 20, 2018

MTDO (gpio15) is a strapping pin used for timing of the SDIO slave...
Gpio0 is used for boot control...

@Singein Singein mentioned this pull request Nov 21, 2018
@Singein
Copy link

Singein commented Nov 21, 2018

@MrSurly @nickzoic
I created the new issuse #4313
Thanks for your contribution to the MciroPython community!

@Singein
Copy link

Singein commented Nov 21, 2018

@MrSurly
final question: how can I wake up esp32 from touchpad?

esp32.wake_on_touch(True)
machine.TouchPad(Pin(32)).config(200)
machine.deepsleep()

These codes don't seem to work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants