GPIO wakeup enable

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
husky
Posts: 17
Joined: Wed Jul 15, 2020 7:46 am

GPIO wakeup enable

Post by husky » Mon Aug 17, 2020 11:48 am

Hi, I am using light sleep, and I would like to wake up the processor with the GPIOs, in IDF the function is esp_sleep_enable_gpio_wakeup and gpio_wakeup_enable.
Is there a way to do this in Micropython? I've tried the wake argument of the Pin.irq function but it doesn't work
Thanks

Lixas
Posts: 7
Joined: Fri Aug 21, 2020 9:09 am

Re: GPIO wakeup enable

Post by Lixas » Fri Aug 21, 2020 9:56 am

This works for me to wake up from deepsleep, transmit message, and go sleep again. btn1 and btn2 are reed switch positions (magnet close to reed or far). This way my board sleeps all time possible and only wakes up when magnet position changes. My if...elseif...else statements maybe can help you with your code.

Code: Select all

import sx127x, esp32
import cfg_lora as cfg
from machine import Pin, deepsleep, wake_reason, idle
from time import sleep

Device = 'Balkonas'
Sensor = 'Langas'   # O C

def transmit(Value):
    # payload = '{};{}:{}#Battery:3.82#Temp:23.2'.format(Device, Sensor, Value)
    payload = '{};{}:{}'.format(Device, Sensor, Value)
    lora = sx127x.SX127x(cfg.lora_spi, pins=cfg.lora_pins, parameters=cfg.lora_default)
    print("LoRa Started");
    print(payload)
    lora.println(payload)

led1 = Pin(2, Pin.OUT)
led1.on()

wakeReason = wake_reason()
print('Wake Reason =', wakeReason)

btn1 = Pin(32, Pin.IN, Pin.PULL_DOWN)   # Normally low, high when pressed
btn2 = Pin(33, Pin.IN, Pin.PULL_DOWN)   # Normally low, high when pressed


if( btn1.value() == 1 and btn2.value() == 0 ):
    Pin(32, Pin.IN, None)
    esp32.wake_on_ext0(pin = btn2, level = esp32.WAKEUP_ANY_HIGH)
    transmit("Closed")

elif( btn1.value() == 0 and btn2.value() == 1 ):
    Pin(33, Pin.IN, None)
    esp32.wake_on_ext0(pin = btn1, level = esp32.WAKEUP_ANY_HIGH)
    transmit("Opened")

else:
    esp32.wake_on_ext0(pin = btn1, level = esp32.WAKEUP_ANY_HIGH)
    esp32.wake_on_ext1(pins = (btn2, ), level = esp32.WAKEUP_ANY_HIGH)
    transmit("Unknown")

idle()
print("Waiting five seconds")
sleep(5)        # Do NOT remove this statement
print("Going to sleep")
led1.off()
deepsleep()

husky
Posts: 17
Joined: Wed Jul 15, 2020 7:46 am

Re: GPIO wakeup enable

Post by husky » Mon Aug 24, 2020 11:21 am

thanks Lixas,
I have tried to wake up esp32 using ext0 and ext1 but I want to use any gpio, not just the ones that are connected to the RTC. Using light sleep, I can have more control to wake up esp using different external sources. https://docs.espressif.com/projects/esp ... sleep-only.
I have multiple external interrupts firing on falling, it's impossible to do that with ext0 or ext1.

udmicpy
Posts: 13
Joined: Tue Aug 15, 2017 3:47 pm

Re: GPIO wakeup enable

Post by udmicpy » Fri Sep 04, 2020 7:51 am

Hi all,

I have an additional question to this topic.
On this page https://randomnerdtutorials.com/esp32-e ... eep-sleep/
we can find C-code like this

Code: Select all

void print_GPIO_wake_up(){
  int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
  Serial.print("GPIO that triggered the wake up: GPIO ");
  Serial.println((log(GPIO_reason))/log(2), 0);
}
Is there a way in micropython to get the number of the GPIO pin that causes the wakeup in the case of an external wakeup on an ESP32?

The micropython function machine.wake_reason() only returns "3" which is machine.EXT1_WAKE but not the pin number.

Thanks, Uwe

davef
Posts: 426
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: GPIO wakeup enable

Post by davef » Mon Oct 11, 2021 10:25 pm

Hi Lixas,

Thanks for posting your example, it helped me to respond to any pin change while in light sleep.

Code: Select all

import esp32
from machine import Pin, lightsleep, wake_reason, idle
from time import sleep


btn1 = Pin(32, Pin.IN, Pin.PULL_DOWN)   # Normally low, high when pressed
esp32.wake_on_ext0(pin = btn1, level = esp32.WAKEUP_ANY_HIGH)

#idle()
#print ('waiting 5 seconds')
#sleep(5) #  do NOT remove this statement
print ('Going to sleep')
sleep(1)
lightsleep(10000) #  10 seconds

wakeReason = wake_reason()
print ('Wake Reason =', wakeReason)
print ('now get on with the rest of the program')
One thing I don't understand is the use of idle() in this situation and your comment 'do NOT remove this statement'. I know that you often have to have a short delay after a print statement or it doesn't print it all out.

machine.idle()
Gates the clock to the CPU, useful to reduce power consumption at any time during short or long periods. Peripherals continue working and execution resumes as soon as any interrupt is triggered (on many ports this includes system timer interrupt occurring at regular intervals on the order of millisecond).
Appreciate any clarification.

marcidy
Posts: 69
Joined: Sat Dec 12, 2020 11:07 pm

Re: GPIO wakeup enable

Post by marcidy » Wed Oct 13, 2021 4:31 pm

machine.idle() does one thing: calls taskYIELD()

Code: Select all

STATIC mp_obj_t machine_idle(void) {
    taskYIELD();
    return mp_const_none;
}
taskYIELD() is from FreeRTOS in the ESP-IDF, and passes control from "this" task (the currently running one, aka micropython) back to the OS (FreeRTOS). This allows the OS time to switch to tasks that have otherwise queued up and need CPU time to complete. That might be switch to another thread (possibly related to micropython, maybe dealing with input/output, networking, etc) or possibly things that the RTOS itself needs to get done.

Basically anything that's queue'd up to get done can now complete before you put the MCU to sleep.

'gating the clock to the CPU' is saying 'passing control back to the OS'.

As for why (specifically) it's needed, I don't have a direct answer in the bit of digging I did, however, it's certainly related to "letting something happen before putting the CPU to sleep" and that something might be "correctly completing the configuration the wake interrupts".

You can set the interrupts whenever you want, though, so you don't need machine.idle() to use the interrupts. It's needed in the example to complete tasks before going to sleep, e.g. setting the interrupts and going to sleep in quick succession. I use the wake interrupts and don't use machine.idle() as I set them a long time before going to sleep.

davef
Posts: 426
Joined: Thu Apr 30, 2020 1:03 am
Location: Christchurch, NZ

Re: GPIO wakeup enable

Post by davef » Wed Oct 13, 2021 6:25 pm

Thank you for explaining why one might want to use idle(). Something else that did concern me was ... did the pin return to normal operation after if was used as a wakeup, without the idle() statement. My testing seemed to indicate that it did. I wonder if there is a proper way to ensure that the pin does return to normal operation.

It appears it would be safer to throw the idle() back-in as originally stated.

Post Reply