3.29. Режимы пониженного энергопотребления и сна

Камерам с питанием от батареи и периодически активным датчикам не нужно, чтобы CPU всё время работал на полной скорости. Модуль machine предоставляет четыре последовательно углубляющихся состояния энергосбережения – active, idle(), lightsleep() и deepsleep(). Каждый шаг вглубь отключает большую часть микросхемы и экономит больше энергии ценой более долгого пробуждения. Выбор правильного состояния – это компромисс между тем, сколько энергии экономит камера, и тем, насколько быстро она может среагировать, когда что-то происходит.

3.29.1. Active

Состояние по умолчанию. CPU выполняет Python, на каждое периферийное устройство подаётся тактовый сигнал, а потребляемый ток максимален – десятки миллиампер по логической линии питания камеры плюс всё, что потребляют через неё подключённые аксессуары.

3.29.2. idle()

machine.idle() останавливает тактирование CPU до тех пор, пока не сработает любое прерывание (периферийное устройство, таймер, прерывание вывода). RAM активна, периферийные устройства остаются включёнными, тактовые сигналы продолжают работать – приостанавливается только сам CPU, и он просыпается за микросекунды, когда появляется работа.

Используйте это внутри любого плотного цикла опроса, который ждёт наступления какого-либо внешнего события:

import machine

while not button_pressed():
    machine.idle()

CPU перестаёт тратить такты на саму проверку while и естественным образом просыпается, когда приходит следующее событие – небольшая экономия, которая накапливается в цикле, выполняющемся миллионы раз.

3.29.3. lightsleep()

machine.lightsleep() – следующий шаг вниз. CPU останавливается полностью, а большинство внутренних тактовых сигналов микросхемы отключаются, но состояние RAM и периферийных устройств сохраняется. Когда срабатывает источник пробуждения, скрипт возобновляется ровно с того места, где он вызвал lightsleep – переменные, открытые дескрипторы и ожидающие данные остаются целыми – спустя порядка миллисекунд.

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

Источник пробуждения – здесь прерывание вывода – должен быть настроен до вызова сна. Потребление энергии значительно падает относительно активного режима; точное значение зависит от платы и от того, какие периферийные устройства всё ещё настроены.

3.29.4. deepsleep()

machine.deepsleep() – самое глубокое состояние. CPU останавливается, периферийные устройства обесточиваются, а содержимое RAM может быть потеряно. Энергию продолжают потреблять только схема пробуждения и небольшой блок постоянно работающей логики.

Когда срабатывает источник пробуждения, микросхема загружается с начала основного скриптаdeepsleep не возвращает управление. Скрипт отличает пробуждение из deepsleep от свежего включения питания или аппаратного сброса с помощью 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

Аргумент в миллисекундах для deepsleep() внутренне взводит будильник встроенного RTC – именно RTC переносит время пробуждения через сон, поскольку большинство других таймеров обесточены. Вызов deepsleep() без аргумента оставляет пробуждение на тот источник, который вы настроили отдельно (прерывание вывода, отдельно взведённый будильник RTC).

Поскольку скрипт перезапускается, всё, что нужно следующей итерации, должно либо воссоздаваться в начале main.py, либо сохраняться во флеш-память (или в резервные регистры RTC на тех компонентах, где они есть). Deepsleep даёт наибольшую экономию энергии, но требует наибольшей перестройки программы – приложение должно вести себя как последовательность коротких «всплесков измерений», разделённых периодами сна, а не как долго работающий цикл с состоянием в RAM.

3.29.5. Выбор состояния

Правильное состояние зависит от того, чего ждёт камера:

  • Плотный цикл опроса, ожидание в миллисекундах. Используйте idle(). Экономия мала за цикл, но велика в сумме, а пробуждение незаметно.

  • Простой в секунды или минуты между событиями. Используйте lightsleep(). Состояние сохраняется, пробуждение быстрое, а потребление энергии – доля от активного режима.

  • Простой в минуты или дольше между короткими всплесками работы. Используйте deepsleep(). Между событиями микросхема фактически выключена, а структура скрипта смещается к циклу пробуждение, измерение, сон.

Каким бы ни было состояние, источник пробуждения важен не меньше самого состояния – deepsleep, просыпающийся только по таймеру, – это цикл измерений с рабочим циклом; lightsleep, просыпающийся по прерыванию вывода, – это датчик, управляемый событиями. Функции сна модуля machine, будильники RTC и irq() вместе дают строительные блоки.