pyb.standby() not documented

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
eduardo
Posts: 31
Joined: Mon Jan 05, 2015 6:48 pm

pyb.standby() not documented

Post by eduardo » Tue Jan 06, 2015 6:54 pm

http://docs.micropython.org/en/latest/l ... yb.standby

also pyb.stop() is not documented

AS I want to run a power concious application, I am very interested in this.

Edmund

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: pyb.standby() not documented

Post by Damien » Thu Jan 15, 2015 10:32 am

pyb.stop() works, and puts the MCU in to low-power sleep. It can be woken by an external interrupt (ExtInt class). Eg, we can use the Switch callback to wake up since that generates an external irq:

Code: Select all

import pyb
sw = pyb.Switch()
sw.callback(lambda:None) # do nothing except wake up
pyb.stop()
# pressing the USR switch will now wake the MCU and it'll continue execution from here
I'm working on getting the RTC to wake the MCU periodically. And then pyb.standby() will also work (but waking from standby resets the MCU so pyb.stop() is probably more useful in your case).

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: pyb.standby() not documented

Post by Damien » Thu Jan 15, 2015 11:58 pm

Ok, I got the wakeup mode working. Here is some code that should work with most versions of the firmware:

Code: Select all

import pyb
import stm

# wut is wakeup counter start value, wucksel is clock source
# counter is decremented at wucksel rate, and wakes the MCU when it gets to 0
# wucksel=0b000 is RTC/16 (RTC runs at 32768Hz)
# wucksel=0b001 is RTC/8
# wucksel=0b010 is RTC/4
# wucksel=0b011 is RTC/2
# wucksel=0b100 is 1Hz clock
# wucksel=0b110 is 1Hz clock with 0x10000 added to wut
# so a 1 second wakeup could be wut=2047, wucksel=0b000, or wut=4095, wucksel=0b001, etc
def wakeup_config(wut, wucksel):
    # disable register write protection
    stm.mem8[stm.RTC + stm.RTC_WPR] = 0xca
    stm.mem8[stm.RTC + stm.RTC_WPR] = 0x53

    # clear WUTE
    stm.mem32[stm.RTC + stm.RTC_CR] &= ~(1 << 10)

    # wait untli WUTWF is set
    while not stm.mem32[stm.RTC + stm.RTC_ISR] & (1 << 2):
        pass

    # program WUT
    stm.mem16[stm.RTC + stm.RTC_WUTR] = wut

    # program WUCKSEL
    stm.mem32[stm.RTC + stm.RTC_CR] |= wucksel & 7

    # set WUTE
    stm.mem32[stm.RTC + stm.RTC_CR] |= 1 << 10

    # set WUTIE to enable interrupts
    stm.mem32[stm.RTC + stm.RTC_CR] |= 1 << 14

    # enable register write protection
    stm.mem8[stm.RTC + stm.RTC_WPR] = 0xff

    # enable external interrupts on line 22
    stm.mem32[stm.EXTI + stm.EXTI_IMR] |= 1 << 22
    stm.mem32[stm.EXTI + stm.EXTI_RTSR] |= 1 << 22

    # clear interrupt flags
    stm.mem32[stm.RTC + stm.RTC_ISR] &= ~(1 << 10)
    stm.mem32[stm.EXTI + stm.EXTI_PR] = 1 << 22

def do_stop():
    # stop the MCU
    pyb.stop()
    # woken; clear interrupt flags
    stm.mem32[stm.RTC + stm.RTC_ISR] &= ~(1 << 10)
    stm.mem32[stm.EXTI + stm.EXTI_PR] = 1 << 22
Call wakeup_config to set the wakeup timer, then call do_stop to stop the MCU when you are finished processing. Example usage:

Code: Select all

# demo to wakeup every 2 seconds and toggle led
wakeup_config(32767, 0b011)
while True:
    do_stop()
    pyb.LED(2).toggle()
The above demo should get you around 0.9mA current consumption when the LED is off (and about 3mA when it's on). You can get down to 0.45mA current consumption if you disable the USB (you can't disable USB with the current firmware, that feature will be added very soon!).

If you need even lower power, you need to use pyb.standby(). This has not been tested thoroughly, but in principle the above code should work by simply replacing pyb.stop() with pyb.standby(). Except that when it wakes up it completely resets the MCU. In the future, features will be added so you can detect such a reset and act accordingly. This standby mode can get down to around 10-20uA on the pyboard.

eduardo
Posts: 31
Joined: Mon Jan 05, 2015 6:48 pm

Re: pyb.standby() not documented

Post by eduardo » Fri Jan 16, 2015 7:08 pm

Dear Damien,
Thank you very much for your code. It works great after a power up of the board.

But if I bring the board (with the reset button) into normal mode after running your code once, edit the code in the file, save it (over the USB drive mode), and then disconnect the board from the USB and push the reset button, the code does not start.

Only a power up does start the code. A reset (from Terminal or button) from normal mode
would not start the code.

I need to disconnect the board from the power and then connect it again to the
power. Only then the code starts correctly. Is that an intended behaviour?

This behaviour is in no way a problem to me, but appears strange to me.

Thank you very much for your help.

I hope you already got the GSM modem. I found out that the GSM modem can locate itself in the world quite accurately (about 50 meter error) and delivers long lat coordinates.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: pyb.standby() not documented

Post by Damien » Sat Jan 17, 2015 6:41 pm

eduardo wrote: Only a power up does start the code. A reset (from Terminal or button) from normal mode
would not start the code.

I need to disconnect the board from the power and then connect it again to the
power. Only then the code starts correctly. Is that an intended behaviour?
It's a bug in the above code. After a hard reset (but with the power still connected) everything should be back to default state. *Except* the RTC which retains its setting across a hard reset. This is the reason it worked on first power up, but not a hard reset.

The issue is that the WAKEUP interrupt was continuing to fire after a hard reset, and was not being acknowledged. Then when you reset it and ran the wakeup code again, the edge level triggering for the external interrupt was not detecting an edge, since the WAKEUP interrupt was already high.

The fix is to clear the WAKEUP interrupt after initialising it. I have added this (and the ext-int irq reset) to the above code and it now works across a hard reset.
I hope you already got the GSM modem. I found out that the GSM modem can locate itself in the world quite accurately (about 50 meter error) and delivers long lat coordinates.
I did not yet receive it...

Post Reply