Why can MicroPython not use the ULP WAKE instruction

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
ellisjr
Posts: 24
Joined: Sun May 17, 2020 8:30 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by ellisjr » Thu Dec 03, 2020 9:49 pm

@mattyt
Oh dear, I've looked at the code you referred to and it's fairly much mumbo-jumbo to me :cry:

I guess we need to add another bool called wake to the typedef for machine_rtc_config and also another static object similar to esp32_wake_on_touch called esp32_wake but I don't see where these connect to the "real world" which for the ulp timer wakeup API is here and for our new ULP wakeup for the WAKE instruction would be this.

I so want this to work but I fear that I am going to need so much help that my input will be negligible. However, I can see that the code required is small and so maybe I can stumble through it with some help ;) After all, I did used to write machine code for Z80 before assemblers were available to joe public, but that was (sigh) a long time ago :shock: and had the benefit of being essentially simple even if a lot of care was required :lol:

Anyway, still waiting to find non-V0/V1 chip dev boards, so there's no rush I guess...
John Ellis
What cannot go wrong, will. What definitely cannot go wrong absolutely will... :roll:

User avatar
mattyt
Posts: 410
Joined: Mon Jan 23, 2017 6:39 am

Re: Why can MicroPython not use the ULP WAKE instruction

Post by mattyt » Sat Dec 12, 2020 11:10 pm

Re-reading the ESP-IDF, I've definitely over-stated this:
mattyt wrote:
Mon Nov 30, 2020 12:59 am
...wasn't implemented because it didn't work on rev 0 and 1 versions of the ESP32
The IDF says this:
ESP-IDF wrote: In revisions 0 and 1 of the ESP32, ULP wakeup source cannot be used when RTC_PERIPH power domain is forced to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup source is used.
Those are fairly specific conditions so I think v0 and v1 chips should work ok.

User avatar
mattyt
Posts: 410
Joined: Mon Jan 23, 2017 6:39 am

Re: Why can MicroPython not use the ULP WAKE instruction

Post by mattyt » Sun Dec 13, 2020 12:04 am

ellisjr wrote:
Thu Dec 03, 2020 9:49 pm
Oh dear, I've looked at the code you referred to and it's fairly much mumbo-jumbo to me :cry:
Some of that code was a bit...hairy. ;)

Having briefly read a little more I think all we need to do is enable the ULP to wake up the CPU and then put the CPU into a deep sleep (after running code on the ULP that will trigger a WAKE).

I think this means that the only missing link is to enable the ULP to wake the CPU. That's just an IDF call that can be exposed like this:

Code: Select all

diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c
index 28d1762d2..8d304d4a3 100644
--- a/ports/esp32/modesp32.c
+++ b/ports/esp32/modesp32.c
@@ -45,6 +45,13 @@
 #include "modmachine.h"
 #include "machine_rtc.h"
 #include "modesp32.h"
+#include "esp_sleep.h"
+
+STATIC mp_obj_t esp32_enable_ulp_wakeup(void) {
+    return mp_obj_new_int(esp_sleep_enable_ulp_wakeup())
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_raw_temperature_obj, esp32_raw_temperature);

 STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) {

@@ -173,6 +180,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_idf_heap_info_obj, esp32_idf_heap_info);
 STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) },

+    { MP_ROM_QSTR(MP_QSTR_enable_ulp_wakeup), MP_ROM_PTR(&esp32_enable_ulp_wakeup_obj) },
     { MP_ROM_QSTR(MP_QSTR_wake_on_touch), MP_ROM_PTR(&esp32_wake_on_touch_obj) },
     { MP_ROM_QSTR(MP_QSTR_wake_on_ext0), MP_ROM_PTR(&esp32_wake_on_ext0_obj) },
     { MP_ROM_QSTR(MP_QSTR_wake_on_ext1), MP_ROM_PTR(&esp32_wake_on_ext1_obj) },
That would enable you to do something like:

Code: Select all

import machine
import esp32

# Allow ESP32 to be woken by ULP WAKE opcode
esp32.enable_ulp_wakeup()

# Load and run pre-compiled ULP binary
ulp = esp32.ULP()
f = open('ulp_main.bin')
binary = f.read()
load_addr, entry_addr = 0, 4
ulp.load_binary(load_addr, binary)
ulp.run(entry_addr)

# Put ESP32 to sleep, relying on the ULP to wake
machine.deepsleep()

# Note that machine.wake_reason() == machine.ULP_WAKE
Now, a big disclaimer; I haven't tested any of that. I'm going to have to leave that to you! :oops:

ellisjr
Posts: 24
Joined: Sun May 17, 2020 8:30 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by ellisjr » Tue Dec 15, 2020 2:26 pm

Those are fairly specific conditions so I think v0 and v1 chips should work ok.
Yes, I think I just got there yesterday, empirically, when I bit the bullet and installed the whole ESP-IDF thing and worked through an example to use the WAKE instruction (with the ADC as it happens) and it all works just fine, so the revision 1 chips clearly work. I now have enough dev boards, all revision 1 from different suppliers, to wallpaper my office :lol: :lol:

So, now knowing I have h/w that will allow me to test, I will look at your (no doubt excellent) code and see what I can do with it! Thank you!

Just an interesting titbit: When I run that ULP ADC program and I power the ESP32 from an Anker USB battery pack, after 1 minute, the battery pack switches off the juice. I assume that the current is so low that it thinks nothing is connected!? Cases with battery holders have been ordered for the next phase of testing ;)

The light at the end of the tunnel has reappeared...
John Ellis
What cannot go wrong, will. What definitely cannot go wrong absolutely will... :roll:

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by kevinkk525 » Tue Dec 15, 2020 4:12 pm

ellisjr wrote:
Tue Dec 15, 2020 2:26 pm
Just an interesting titbit: When I run that ULP ADC program and I power the ESP32 from an Anker USB battery pack, after 1 minute, the battery pack switches off the juice. I assume that the current is so low that it thinks nothing is connected!? Cases with battery holders have been ordered for the next phase of testing ;)
yeah that happens with most battery packs sadly. Had that problem with my esp8266 too :lol: Apparently you can force them to stay on if you make consumption peaks in a certain interval. But didn't quite work with my battery pack.. Ultimately I gave up on that :D
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Why can MicroPython not use the ULP WAKE instruction

Post by pythoncoder » Tue Dec 15, 2020 5:31 pm

Yup, me too. Fixed (or rather bodged) with a resistor between the 5V supply and gnd. ISTR 47Ω 0.5W did the trick with mine.
Peter Hinch
Index to my micropython libraries.

clone
Posts: 2
Joined: Sun Dec 20, 2020 2:06 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by clone » Sun Dec 20, 2020 2:53 pm

mattyt wrote:
Sun Dec 13, 2020 12:04 am
Now, a big disclaimer; I haven't tested any of that. I'm going to have to leave that to you! :oops:
Thanks, there is one mistake in the patch, it should be:

Code: Select all

+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_enable_ulp_wakeup_obj, esp32_enable_ulp_wakeup);
I can confirm that the ULP wake-up works on patched firmware after calling esp32.enable_ulp_wakeup()

To test if the system is ready for wake up and avoid unnecessary interrupts the

Code: Select all

READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
can be written as

Code: Select all

reg_rd 0x3ff480c0, 19, 19
So the ULP code can be compiled using py-esp32-ulp that lacks of macro support.

Where 0x3ff480c0 = DR_REG_RTCCNTL_BASE + 0xc0:

Code: Select all

> hex(0x3ff48000 + 0xc0)
'0x3ff480c0'

It would be nice if this change could be added to the official micropython source code among adc1_ulp_enable() (and other ULP related calls if there is any)

ellisjr
Posts: 24
Joined: Sun May 17, 2020 8:30 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by ellisjr » Mon Dec 21, 2020 4:42 pm

@clone
Welcome to the party! Or should I say, thank goodness, the cavalry have arrived! I have spent three days getting to the point where I can build Micropython, so that I could test Mattyt's code, but I have finally just done it. Many traps for the unwary/uninitiated...

So, I will also test the change and add to the calls for it to be added to the official release.

Also, I am impressed that you could work out the raw reg_rd instruction instead of the macros; I tried it with no success, but somehow that doesn't surprise me :lol: That IS very useful though so that we can use py-esp32-ulp with ease.
John Ellis
What cannot go wrong, will. What definitely cannot go wrong absolutely will... :roll:

ellisjr
Posts: 24
Joined: Sun May 17, 2020 8:30 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by ellisjr » Wed Dec 23, 2020 4:27 pm

@mattyt
So, I built MP with the changes as debugged by @clone and of course, it works perfectly. Thank you both!

I'm guessing that this is a silly question, but why can't esp32.enable_ulp_wakeup() take a Boolean to enable and disable the use of the ULP WAKE instruction? It would seem good to be able to turn it off as well as on, but I guess maybe when I start building real applications I might see why one would not need to turn it off (though on that basis, why is it not always on? :? )

Anyway, if we ignore my NOOB question this all seems good and I would welcome it in the standard build asap.
John Ellis
What cannot go wrong, will. What definitely cannot go wrong absolutely will... :roll:

clone
Posts: 2
Joined: Sun Dec 20, 2020 2:06 pm

Re: Why can MicroPython not use the ULP WAKE instruction

Post by clone » Tue Dec 29, 2020 6:01 pm

ellisjr wrote:
Wed Dec 23, 2020 4:27 pm
I'm guessing that this is a silly question, but why can't esp32.enable_ulp_wakeup() take a Boolean to enable and disable the use of the ULP WAKE instruction? It would seem good to be able to turn it off as well as on, but I guess maybe when I start building real applications I might see why one would not need to turn it off (though on that basis, why is it not always on? :? )
There is no disable_ulp_wakeup in official API, because you have to call enable_ulp_wakeup() every time before you go to deep sleep if you want to enable ULP wake.

Probably esp32.wake_from_ulp(wake: bool) would be the closest to current micropython function names: there is already a esp32.wake_on_touch(wake: bool) function to call esp_sleep_enable_touchpad_wakeup(void).

Probably it will require more modification based on current esp32.wake_on_touch that stores the enable/disable status in rtc memory to preserve it between restarts.

Post Reply