modmachine: Implemented GPIO wake-up for ESP32-C3.
As ESP32-C3 uses GPIO wake-up instead of EXT0/1 wake-up, several small changes in code was required. Interface stays the same as for generic ESP32 but EXT0 is ignored and EXT1 is used as wake-up source.
Signed-off-by: Ondrej Sienczak [email protected]
i just submitted #9578 about esp32-c3 wake pin not working.hopefully this commit will get merged soon.btw any updates on which pin can be used for wakeup? currently only pin 0,2,4 are useable. according to this useable wakeup pin 0 to pin 5.
i just submitted #9578 about esp32-c3 wake pin not working.hopefully this commit will get merged soon.btw any updates on which pin can be used for wakeup? currently only pin 0,2,4 are useable. according to this useable wakeup pin 0 to pin 5.
Exactly. Only RTC pins are possible to be used as wake-up sources. I have implemented check if all pins in mask are capable to be set as wake-up sources, otherwise exception is raised when you attempt to sleep.
i just submitted #9578 about esp32-c3 wake pin not working.hopefully this commit will get merged soon.btw any updates on which pin can be used for wakeup? currently only pin 0,2,4 are useable. according to this useable wakeup pin 0 to pin 5.
Exactly. Only RTC pins are possible to be used as wake-up sources. I have implemented check if all pins in mask are capable to be set as wake-up sources, otherwise exception is raised when you attempt to sleep.
Care to share which one have you implemented about the wake pins?
i just submitted #9578 about esp32-c3 wake pin not working.hopefully this commit will get merged soon.btw any updates on which pin can be used for wakeup? currently only pin 0,2,4 are useable. according to this useable wakeup pin 0 to pin 5.
Exactly. Only RTC pins are possible to be used as wake-up sources. I have implemented check if all pins in mask are capable to be set as wake-up sources, otherwise exception is raised when you attempt to sleep.
Care to share which one have you implemented about the wake pins?
Any of them. You can use any pin to set it as wake-up source. Pin is assigned to wake-up sources bitmap. When you attempt to sleep, micropython checks if all of this pins are supported as valid wake-up sources and go to deep/light sleep. If any of this pins is not supported, then deep/light sleep raises value error with message "invalid wake-up pin". Check if pin is supported or not is done by espidf function. This means that if we have some other ESP-like chip in future capable of GPIO wake-up, we can reuse this piece of code without any change.
Any of them. You can use any pin to set it as wake-up source. Pin is assigned to wake-up sources bitmap. When you attempt to sleep, micropython checks if all of this pins are supported as valid wake-up sources and go to deep/light sleep. If any of this pins is not supported, then deep/light sleep raises value error with message "invalid wake-up pin". Check if pin is supported or not is done by espidf function. This means that if we have some other ESP-like chip in future capable of GPIO wake-up, we can reuse this piece of code without any change.
thanks, that nice.will try later and report back.currently no c3 board at hand.
Any of them. You can use any pin to set it as wake-up source. Pin is assigned to wake-up sources bitmap. When you attempt to sleep, micropython checks if all of this pins are supported as valid wake-up sources and go to deep/light sleep. If any of this pins is not supported, then deep/light sleep raises value error with message "invalid wake-up pin". Check if pin is supported or not is done by espidf function. This means that if we have some other ESP-like chip in future capable of GPIO wake-up, we can reuse this piece of code without any change.
thanks, that nice.will try later and report back.currently no c3 board at hand.
I tried following code snippet. It is just for one pin, but it can be easily extended for more. ESP32-C3 went to deep sleep and has been woken-up when 3,3V has been connected to IO2:
MicroPython ab317a0d6-dirty on 2022-10-12; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>> import esp32
>>> from machine import Pin
>>> from machine import deepsleep
>>> wake1 = Pin(4, mode=Pin.IN)
>>> esp32.wake_on_ext1(pins=(wake1,), level=esp32.WAKEUP_ANY_HIGH)
>>> deepsleep()
ESP-ROM:esp32c3-api1-20210207
Build:Feb 7 2021
rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0xe3c
load:0x403ce000,len:0x6f4
load:0x403d0000,len:0x28ec
entry 0x403ce000
MicroPython ab317a0d6-dirty on 2022-10-12; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>>
example code:
import machine
import esp32
from time import ticks_ms
def wake_msg():
reset_cause = machine.reset_cause()
if reset_cause is machine.HARD_RESET:
reset_cause = 'HARD_RESET'
elif reset_cause is machine.PWRON_RESET:
reset_cause = 'PWRON_RESET'
elif reset_cause is machine.WDT_RESET:
reset_cause = 'WDT_RESET'
elif reset_cause is machine.DEEPSLEEP_RESET:
reset_cause = 'DEEPSLEEP_RESET'
elif reset_cause is machine.SOFT_RESET:
reset_cause = 'SOFT_RESET'
wake_reason = machine.wake_reason()
if wake_reason is machine.PIN_WAKE:
wake_reason = 'PIN_WAKE'
elif wake_reason is machine.EXT0_WAKE:
wake_reason = 'EXT0_WAKE'
elif wake_reason is machine.EXT1_WAKE:
wake_reason = 'EXT1_WAKE'
elif wake_reason is machine.TIMER_WAKE:
wake_reason = 'TIMER_WAKE'
elif wake_reason is machine.TOUCHPAD_WAKE:
wake_reason = 'TOUCHPAD_WAKE'
elif wake_reason is machine.ULP_WAKE:
wake_reason = 'ULP_WAKE'
return reset_cause,wake_reason
pin_list = [ 0, 1 ,2, 3, 4, 5 ] #C3
for num in pin_list:
try:
wake_pin = machine.Pin(num,machine.Pin.IN)
esp32.wake_on_ext0(pin = wake_pin, level = esp32.WAKEUP_ANY_HIGH)
except Exception as exc:
print(num,exc)
else:
ticks = ticks_ms()
before_sleep = wake_pin()
machine.lightsleep(5000)
ticks = ticks_ms() - ticks
print(num,before_sleep,wake_pin(),wake_msg(),ticks)
for num in pin_list:
try:
wake_pin = machine.Pin(num,machine.Pin.IN)
esp32.wake_on_ext1(pins = (wake_pin,), level = esp32.WAKEUP_ANY_HIGH)
except Exception as exc:
print(num,exc)
else:
ticks = ticks_ms()
before_sleep = wake_pin()
machine.lightsleep(5000)
ticks = ticks_ms() - ticks
print(num,before_sleep,wake_pin(),wake_msg(),ticks)
code output:
MicroPython ab317a0d6 on 2022-10-12; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
0 1 1 ('SOFT_RESET', 'TIMER_WAKE') 5000
1 invalid pin
2 1 1 ('SOFT_RESET', 'TIMER_WAKE') 5000
3 invalid pin
4 1 1 ('SOFT_RESET', 'TIMER_WAKE') 5000
5 invalid pin
0 1 1 ('SOFT_RESET', 'TIMER_WAKE') 5000
1 invalid pin
2 1 1 ('SOFT_RESET', 'TIMER_WAKE') 5000
3 invalid pin
4 1 1 ('SOFT_RESET', 'TIMER_WAKE') 5000
5 invalid pin
all wakeup from timer
expected output:
MicroPython v1.19.1-528-gb8982ec5f on 2022-10-09; LOLIN S3 with ESP32S3
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
0 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
1 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
2 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
3 1 1 ('SOFT_RESET', 'PIN_WAKE') 2
4 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
5 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
0 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
1 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
2 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
3 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
4 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
5 1 1 ('SOFT_RESET', 'PIN_WAKE') 1
with your code:
import esp32
from machine import Pin
from machine import deepsleep
wake1 = Pin(4, mode=Pin.IN)
esp32.wake_on_ext1(pins=(wake1,), level=esp32.WAKEUP_ANY_HIGH)
deepsleep()
output:
ESP-ROM:esp32c3-api1-20210207
Build:Feb 7 2021
rst:0x5 (DSLEEP),boot:0xf (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0xe3c
load:0x403ce000,len:0x6f4
load:0x403d0000,len:0x28d8
entry 0x403ce000
('DEEPSLEEP_RESET', 'TIMER_WAKE') <<-- TIMER_WAKE???
MicroPython ab317a0d6 on 2022-10-12; ESP32C3 module with ESP32C3
Type "help()" for more information.
dont know why it's not working for me.with your code,it will not wakeup when using lightsleep()
wiring: pin(0,1,2,3,4,5) <-> R1 <-> v3.3
There are some missunderstandings and some faulty use. As I originally wanted to preserve interface same as with regular esp32, I decided to ignore ext0 and use ext1 as gpio wake-up mask. This means that ext0 is ignored right now so this part of test will never pass.
Then I tried again the example I posted above and it works to me. With deepsleep the reset_cause showed me DEEPSLEEP_RESET. However as wake reason is returned number 7 which does not match to any of supported wake-up reasons. The reason of this behavior is probably that gpio weak-up uses different reason ID then ext1 reason ID. However processor woken-up from deep sleep without any problems.
Then I tried also lightsleep. It was working as well, with difference that reset_cause showed me SOFT_RESET.
At the end I made more deeper test:
import esp32
import machine
from time import sleep_ms
rc2str = {getattr(machine, i): i for i in ('PWRON_RESET',
'HARD_RESET',
'WDT_RESET',
'DEEPSLEEP_RESET',
'SOFT_RESET')}
ws2str = {getattr(machine, i): i for i in ('EXT0_WAKE',
'EXT1_WAKE',
'TIMER_WAKE',
'TOUCHPAD_WAKE',
'ULP_WAKE')}
ws2str[7] = '(hidden ESP_SLEEP_WAKEUP_GPIO)'
wake1 = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_DOWN)
esp32.wake_on_ext1(pins=(wake1,), level=esp32.WAKEUP_ANY_HIGH)
print('Zzzzz ...')
sleep_ms(100)
machine.lightsleep(10000)
rc = machine.reset_cause()
ws = machine.wake_reason()
print('Woken-up',
rc2str.get(rc, str(rc)),
ws2str.get(ws, str(ws)))
The result is following:
>>> %Run -c $EDITOR_CONTENT
Zzzzz ...
Woken-up SOFT_RESET (hidden ESP_SLEEP_WAKEUP_GPIO)
>>>
This means that I have to add at least WAKEUP_GPIO representation into module machine. In this case another question comes up - shall we change API to prevent from confusions in future?
Anyway, the basics are working to me fine, however I'll do similar test like you as here is still not full explanation of your behavior.
Anyway, I patched GPIO vs. EXT1 issue - 848805e70154cd391c3e23a7f9288f40720220b5:
import esp32
import machine
from time import sleep_ms
rc2str = {getattr(machine, i): i for i in ('PWRON_RESET',
'HARD_RESET',
'WDT_RESET',
'DEEPSLEEP_RESET',
'SOFT_RESET')}
ws2str = {getattr(machine, i): i for i in ('EXT0_WAKE',
'EXT1_WAKE',
'TIMER_WAKE',
'TOUCHPAD_WAKE',
'ULP_WAKE')}
wake1 = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_DOWN)
esp32.wake_on_ext1(pins=(wake1,), level=esp32.WAKEUP_ANY_HIGH)
print('Zzzzz ...')
sleep_ms(100)
machine.lightsleep(10000)
rc = machine.reset_cause()
ws = machine.wake_reason()
print('Woken-up',
rc2str.get(rc, str(rc)),
ws2str.get(ws, str(ws)))
So the result is now correct
>>> %Run -c $EDITOR_CONTENT
Zzzzz ...
Woken-up SOFT_RESET EXT1_WAKE
>>>
I also found the reason why you got "invalid pin". There is embedded check in pins assignment which does not fit on ESP32C3. I'll fix it.
I made second patch (741129355bd32d01929d7b400bbafbffed638e44) related to EXT1 (GPIO) wake-up capable pins. Finaly it seems that there is no need to change original ESP32 inteface.
@puppet13th - could you please test with your code again please?
I made second patch (7411293) related to EXT1 (GPIO) wake-up capable pins. Finaly it seems that there is no need to change original ESP32 inteface.
@puppet13th - could you please test with your code again please?
will retest with latest changes.
from the reference look like any gpio pin can be used as (lightsleep) wake up pin.
have retest your latest changes but still got different result:
MicroPython ab317a0d6 on 2022-10-12; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
Zzzzz ...
Woken-up SOFT_RESET TIMER_WAKE
wiring : v3.3 -- R1 -- pin(4) board : ai-thinker esp32-c3s
i mean time i made changes at modmachine.c:
#if CONFIG_IDF_TARGET_ESP32C3
if (machine_rtc_config.ext0_pin != -1) {
gpio_sleep_set_direction((gpio_num_t)machine_rtc_config.ext0_pin, GPIO_MODE_INPUT);
esp_deep_sleep_enable_gpio_wakeup(
machine_rtc_config.ext0_pin,
machine_rtc_config.ext0_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW);
gpio_wakeup_enable(machine_rtc_config.ext0_pin,
machine_rtc_config.ext0_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW);
esp_sleep_enable_gpio_wakeup();
}
if (machine_rtc_config.ext1_pins != -1) {
gpio_sleep_set_direction((gpio_num_t)machine_rtc_config.ext1_pins, GPIO_MODE_INPUT);
esp_deep_sleep_enable_gpio_wakeup(
machine_rtc_config.ext1_pins,
machine_rtc_config.ext1_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW);
gpio_wakeup_enable(machine_rtc_config.ext1_pins,
machine_rtc_config.ext1_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW);
esp_sleep_enable_gpio_wakeup();
}
#else
code output :
MicroPython v1.19.1-528-gb8982ec5f-dirty on 2022-10-12; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
Zzzzz ...
Woken-up SOFT_RESET 0
I'm using ESP-C3-12F.
Suggested changes can be missleading as there is no EXT0 and EXT1, but only GPIO wake-up. Then I'm not sure if it is good idea to mix them as someone may use different setupt for EXT0 and EXT1. I would rather see that EXT0 throws exception - something like "unsupported" and keep EXT1 as wake-up sources in similar logic as with regular ESP32.
Regarding use of -1, I have to check the code if -1 is only meant as initial value or if it is used in general to disable feature.
have retest your latest changes but still got different result:
i mean time i made changes at modmachine.c:
#if CONFIG_IDF_TARGET_ESP32C3 if (machine_rtc_config.ext0_pin != -1) { gpio_sleep_set_direction((gpio_num_t)machine_rtc_config.ext0_pin, GPIO_MODE_INPUT); esp_deep_sleep_enable_gpio_wakeup( machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW); gpio_wakeup_enable(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW); esp_sleep_enable_gpio_wakeup(); } if (machine_rtc_config.ext1_pins != -1) { gpio_sleep_set_direction((gpio_num_t)machine_rtc_config.ext1_pins, GPIO_MODE_INPUT); esp_deep_sleep_enable_gpio_wakeup( machine_rtc_config.ext1_pins, machine_rtc_config.ext1_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW); gpio_wakeup_enable(machine_rtc_config.ext1_pins, machine_rtc_config.ext1_level ? ESP_GPIO_WAKEUP_GPIO_HIGH : ESP_GPIO_WAKEUP_GPIO_LOW); esp_sleep_enable_gpio_wakeup(); } #else
I'm afraid that this changes are not good idea from the reason I mentioned above (mixing of EXT0 and EXT1). We also shall not compare ext1_pins with -1 as it is defined as unsigned type and it is used as bit array.
I'm using ESP-C3-12F.
Suggested changes can be missleading as there is no EXT0 and EXT1, but only GPIO wake-up. Then I'm not sure if it is good idea to mix them as someone may use different setupt for EXT0 and EXT1. I would rather see that EXT0 throws exception - something like "unsupported" and keep EXT1 as wake-up sources in similar logic as with regular ESP32.
Regarding use of -1, I have to check the code if -1 is only meant as initial value or if it is used in general to disable feature.
for the changes I made, ext0 does not works as intended. I agree that calling esp32.ext0 should throws exception.
from the reference look like any gpio pin can be used as (lightsleep) wake up pin.
It seems to be true. There is used different approach for deep sleep and light sleep. The question is how to handle it directly. Pin checking in time of setting of EXT1 is not sufficient in this case as it may differ based on usage. So I'll have to move it into machine_sleep_helper based on sleep type.
I have modified approach for setting pins for the case of deep and light sleep - 4c7c2b090d8ea4c2db59bfe70d44bf4bd92370c0
@puppet13th - I found that all works perfectly only when I set all the stuff just once after reset. Problem seems to be somewhere inside espidf so I have no way to work around. The suggested strategy for light sleep is to set up wake-up pins just once at the beginning and not to modify them later. I tested it and it worked fine for me. In the case of deep sleep this is not an issue as it always leeds to processor reset.
what do you mean?
I found that all works perfectly only when I set all the stuff just once after reset.
all look good now:
- lightsleep works on any gpio pin
- deepsleep works on rtc gpio pin
- when calling ext0 mpy throws exception
however calling deepsleep on non rtc_gpio does not throw error. review
what do you mean?
I found that all works perfectly only when I set all the stuff just once after reset.
all look good now:
- lightsleep works on any gpio pin
- deepsleep works on rtc gpio pin
- when calling ext0 mpy throws exception
however calling deepsleep on non rtc_gpio does not throw error. review
I agree, it shall rather throw an exception then silently proceed non-functional code. I'll add this check to code as well.
I agree, it shall rather throw an exception then silently proceed non-functional code. I'll add this check to code as well.
MicroPython 45f80abd6 on 2022-10-14; ESP32C3 module with ESP32C3
Type "help()" for more information.
>>> %Run -c $EDITOR_CONTENT
Zzzzz ...
Woken-up SOFT_RESET TIMER_WAKE
Traceback (most recent call last):
File "<stdin>", line 32, in <module>
ValueError: wake-up pin not supported
we should have resolved all issue regarding esp32-c3 wake-pin. waiting to be merged. :)
@puppet13th and @ondiiik. thank you for your work on these changes! Any update on when these might be merged for inclusion in an nightly?
@puppet13th and @ondiiik. thank you for your work on these changes! Any update on when these might be merged for inclusion in an nightly?
should be checked by owner/maintainer before merge. @dpgeorge @jimmo
@dpgeorge @jimmo I can confirm that this works on esp32-c3-12f of AI-Thinker. This is much needed, can we see that this gets merged?
i have manually edit mpy 1.20.0 source code accordingly to this commit and compiled using IDF 4.4.4 i can confirm this commit still valid for mpy 1.20.0 source code.
@puppet13th @ondiiik
After using this, I have two suggestions regarding documentation.
First, I think that the error that is raised when calling ext0 is not indicitive, and may lead to frustration in not understanding what "no supported" means in a generic looking RuntimeError.
Second, the documentation on readthedocs should be updated to reflect this behaviour.
I've tested these changes on an Seeed XIAO-ESP32C3; all good.
Hi all,
I'm sorry as I'm a bit busy now and don't know when I'll be back here to continue :slightly_frowning_face: . Is there anyone who could take over this issue so it can be merged?
What needs to be done?