3.29. Tryby niskiego poboru mocy i uśpienia

Kamery zasilane z baterii oraz sensory aktywne tylko sporadycznie nie potrzebują, aby CPU stale pracował z pełną prędkością. Moduł machine udostępnia cztery coraz głębsze stany oszczędzania energii – active, idle(), lightsleep() oraz deepsleep(). Każdy głębszy krok wyłącza większą część układu i oszczędza więcej energii, kosztem dłuższego wybudzania. Wybór odpowiedniego stanu to kompromis między tym, ile energii kamera oszczędza, a tym, jak szybko może zareagować, gdy coś się wydarzy.

3.29.1. Active

Stan domyślny. CPU wykonuje Pythona, każde urządzenie peryferyjne jest taktowane, a pobór prądu jest najwyższy – dziesiątki miliamperów na szynie logicznej kamery, plus wszystko, co pobierają przez nią podłączone akcesoria.

3.29.2. idle()

machine.idle() wstrzymuje zegar CPU do czasu, aż zgłosi się dowolne przerwanie (urządzenie peryferyjne, licznik czasu, przerwanie pinu IRQ). Pamięć RAM jest aktywna, urządzenia peryferyjne pozostają włączone, zegary nadal pracują – pauzowany jest tylko sam CPU, który budzi się w ciągu mikrosekund, gdy pojawia się praca do wykonania.

Używaj go wewnątrz każdej ciasnej pętli odpytującej, która czeka na zaistnienie czegoś zewnętrznego:

import machine

while not button_pressed():
    machine.idle()

CPU przestaje marnować cykle na samo sprawdzanie warunku while i budzi się naturalnie, gdy nadejdzie kolejne zdarzenie – niewielka oszczędność, która sumuje się w pętli wykonywanej miliony razy.

3.29.3. lightsleep()

machine.lightsleep() to kolejny krok niżej. CPU jest całkowicie zatrzymany, a większość wewnętrznych zegarów układu jest wyłączona, ale stan pamięci RAM i urządzeń peryferyjnych zostaje zachowany. Gdy zgłosi się źródło wybudzenia, skrypt wznawia działanie dokładnie w miejscu, w którym wywołał lightsleep – zmienne, otwarte uchwyty i oczekujące dane pozostają nienaruszone – rzędu milisekund później.

import machine
from machine import Pin

wake_pin = Pin("P0", Pin.IN, Pin.PULL_UP)
wake_pin.irq(lambda _: None, trigger=Pin.IRQ_FALLING, wake=machine.SLEEP)

while True:
    do_work()
    machine.lightsleep()   # wakes on a falling edge on P0

Źródło wybudzenia – tutaj przerwanie pinu IRQ – musi zostać skonfigurowane przed wywołaniem uśpienia. Pobór mocy znacząco spada względem trybu active; dokładna wartość zależy od płytki i tego, jakie urządzenia peryferyjne pozostają skonfigurowane.

3.29.4. deepsleep()

machine.deepsleep() to najgłębszy stan. CPU zatrzymuje się, urządzenia peryferyjne są wyłączane z zasilania, a zawartość pamięci RAM może zostać utracona. Jedyne, co nadal pobiera energię, to układ wybudzania oraz niewielka część logiki stale zasilanej.

Gdy zgłosi się źródło wybudzenia, układ uruchamia się od początku głównego skryptudeepsleep nie zwraca sterowania. Skrypt odróżnia wybudzenie z deepsleep od świeżego włączenia zasilania lub twardego resetu za pomocą machine.reset_cause():

import machine

if machine.reset_cause() == machine.DEEPSLEEP_RESET:
    # Woke from deepsleep -- restore state from non-volatile storage,
    # take a measurement, etc.
    pass
else:
    # Fresh boot
    pass

do_work()
machine.deepsleep(60_000)    # arm RTC wake for 60 s, sleep, then restart

Argument w milisekundach przekazany do deepsleep() wewnętrznie uzbraja alarm wbudowanego zegara RTC – to właśnie RTC przenosi czas wybudzenia przez okres uśpienia, ponieważ większość pozostałych liczników czasu jest pozbawiona zasilania. Wywołanie deepsleep() bez argumentu pozostawia wybudzenie dowolnemu źródłu, które skonfigurowałeś osobno (przerwanie pinu IRQ, zewnętrznie uzbrojony alarm RTC).

Ponieważ skrypt uruchamia się od nowa, wszystko, czego potrzebuje następna iteracja, musi zostać albo odtworzone na początku main.py, albo zapisane w pamięci flash (lub w rejestrach zapasowych RTC, na układach, które je posiadają). Deepsleep daje największą oszczędność energii, ale wymusza najwięcej zmian w strukturze programu – aplikacja musi działać jako seria krótkich „serii pomiarowych” przedzielonych uśpieniami, a nie jako długo działająca pętla ze stanem w pamięci RAM.

3.29.5. Wybór stanu

Właściwy stan zależy od tego, na co kamera czeka:

  • Ciasna pętla odpytująca, czekająca milisekundy. Użyj idle(). Oszczędności na pojedynczy cykl są niewielkie, ale w sumie duże, a wybudzanie jest niezauważalne.

  • Bezczynność przez sekundy lub minuty między zdarzeniami. Użyj lightsleep(). Stan jest zachowany, wybudzanie szybkie, a pobór mocy stanowi ułamek trybu active.

  • Bezczynność przez minuty lub dłużej między krótkimi seriami pracy. Użyj deepsleep(). Układ jest praktycznie wyłączony między zdarzeniami, a struktura skryptu przechodzi w pętlę typu wybudź, zmierz, uśpij.

Niezależnie od stanu, źródło wybudzenia ma takie samo znaczenie jak sam stan – deepsleep budzony wyłącznie licznikiem czasu to pętla pomiarowa o cyklicznym współczynniku wypełnienia; lightsleep budzony przerwaniem pinu IRQ to sensor sterowany zdarzeniami. Funkcje uśpienia modułu machine, alarmy RTC oraz irq() razem dają elementy składowe.