Перейти к содержанию

Режимы сна и энергосбережение AVR

Как перевести AVR в сон и разбудить его: шесть режимов сна ATmega328P, что в каждом работает и что может разбудить кристалл, отключение детектора BOD на время сна у picoPower-версий, регистр PRR, список того, что ещё потребляет ток, и пример на avr-libc с пробуждением от сторожевого таймера.

Обновлено Редакция GAW

Режимы сна останавливают тактовые сигналы ненужных узлов микроконтроллера и снижают ток от единиц миллиампер в активном режиме до долей микроампера. Ниже — режимы сна AVR на примере ATmega328P по даташиту Microchip DS40002061B (глава 10): что работает в каждом режиме, чем кристалл будить, как отключить BOD на время сна и что ещё нужно выключить, чтобы получить паспортные микроамперы.

Коротко

  • Шесть режимов у ATmega328P: Idle, ADC Noise Reduction, Power-down, Power-save, Standby и Extended Standby; режим выбирают биты SM2:0 регистра SMCR.
  • Засыпание: бит SE в SMCR и команда SLEEP. Пробуждение — по разрешённому прерыванию; после него кристалл стоит 4 такта плюс время запуска генератора.
  • Ток ATmega328P при 3 В и 25 °C: Power-down — 0,1 мкА, с включённым сторожевым таймером — 4,2 мкА, Power-save с часовым кварцем — 0,9 мкА; активный режим на 4 МГц — 1,7 мА.
  • picoPower-версии (ATmega328P, 168PA, 88PA, 48PA) умеют отключать детектор BOD на время сна.
  • Регистр PRR останавливает такты отдельных модулей в активном режиме и Idle.

Режимы сна ATmega328P

SM2:0РежимЧто продолжает работатьЧем разбудить
000Idleвся периферия: SPI, USART, АЦП, компаратор, TWI, таймеры, сторожевой таймер; остановлены только ядро и Flashлюбое прерывание, внешнее или от периферии
001ADC Noise ReductionАЦП, внешние прерывания, адресное совпадение TWI, Timer/Counter2 в асинхронном режиме, сторожевой таймерокончание преобразования АЦП, прерывания Timer/Counter2, сторожевого таймера, SPM/EEPROM, INT0/INT1 по уровню, pin change, адрес TWI, сбросы
010Power-downтолько асинхронные узлы: внешние прерывания, адресное совпадение TWI, сторожевой таймер; основной генератор остановленсброс, сторожевой таймер, BOD, адрес TWI, INT0/INT1 по низкому уровню, pin change
011Power-saveкак Power-down, плюс Timer/Counter2то же плюс переполнение и совпадение Timer/Counter2
110Standbyкак Power-down, но генератор не останавливаетсякак Power-down, пробуждение за 6 тактов
111Extended Standbyкак Power-save, но генератор не останавливаетсякак Power-save, пробуждение за 6 тактов

Коды 100 и 101 зарезервированы. Для INT0 и INT1 даташит противоречив: описание Power-down (раздел 10.5) называет только прерывание по низкому уровню, а глава 13 той же редакции говорит, что асинхронно распознаются и фронты. Надёжнее всего будить кристалл низким уровнем или прерыванием pin change — оно распознаётся асинхронно на всех выводах PCINT. Standby и Extended Standby рекомендуются только с внешним кварцем или резонатором. Power-save имеет смысл, если Timer/Counter2 работает — например, асинхронно от часового кварца 32,768 кГц на выводах TOSC: тогда он отсчитывает время, пока кристалл спит, и будит его прерыванием; если Timer/Counter2 не нужен, лучше Power-down. Режим ADC Noise Reduction останавливает такт ввода-вывода, чтобы цифровая периферия не шумела во время преобразования, — АЦП в нём запускается автоматически при входе в сон, так же как в Idle.

Как заснуть и проснуться

Чтобы войти в сон, нужно записать режим в SM2:0, установить бит SE в SMCR и выполнить команду SLEEP. Даташит советует ставить SE непосредственно перед SLEEP и сбрасывать сразу после пробуждения, чтобы случайная команда SLEEP не усыпила кристалл. По разрешённому прерыванию кристалл просыпается, стоит 4 такта плюс время запуска генератора, выполняет обработчик и продолжает программу с команды после SLEEP. Регистры и ОЗУ при этом сохраняются. Если во сне пришёл сброс, выполнение начнётся с вектора сброса.

После Power-down и Power-save генератор запускается заново, и пробуждение задерживается на время запуска, заданное фьюзами CKSEL и SUT, — то же, что после сброса. Поэтому прерывание по уровню на INT0 или INT1 должно держаться, пока кристалл не проснётся: если уровень пропадёт раньше, кристалл проснётся, но обработчик не вызовется.

В avr-libc для этого есть макросы set_sleep_mode(), sleep_enable(), sleep_cpu() и sleep_disable(). Простой sleep_mode() выполняет всё сразу, но может «проспать» прерывание, пришедшее между проверкой условия и засыпанием. Надёжная последовательность — проверить условие при запрещённых прерываниях, затем разрешить их командой SEI и сразу выполнить SLEEP: команда после SEI гарантированно выполняется до того, как сработает прерывание.

Отключение BOD на время сна (picoPower)

Если детектор пониженного питания BOD включён фьюзами BODLEVEL, он работает и во сне и в глубоких режимах заметно добавляет к потребляемому току. У picoPower-кристаллов ATmega48PA, 88PA, 168PA и 328P его можно выключить программно на время сна: сначала записать единицы в биты BODS и BODSE регистра MCUCR, затем в течение четырёх тактов — BODS = 1 и BODSE = 0. Бит BODS начинает действовать через три такта после установки и сам сбрасывается ещё через три такта, поэтому команда SLEEP должна идти сразу за этой последовательностью. После пробуждения BOD включается автоматически, а само пробуждение затягивается примерно на 60 мкс, пока BOD снова не начнёт работать. В avr-libc эту последовательность реализует макрос sleep_bod_disable().

Что ещё потребляет ток

Режим сна выключает тактовые сигналы, но часть узлов продолжает работать, если её не выключить явно (DS40002061B, раздел 10.10):

  • АЦП остаётся включённым во всех режимах сна — сбросьте ADEN перед сном. После повторного включения первое преобразование будет длинным.
  • Аналоговый компаратор выключают в Idle и ADC Noise Reduction, а если он использует внутренний источник опорного напряжения — во всех режимах.
  • BOD — либо выключить фьюзами, либо отключать на время сна, как описано выше.
  • Внутренний источник опорного напряжения работает, пока он нужен BOD, компаратору или АЦП.
  • Сторожевой таймер, если включён, работает во всех режимах сна: с ним ток в Power-down вырастает с 0,1 до 4,2 мкА.
  • Выводы. Ни один вывод не должен питать резистивную нагрузку. Входной буфер с плавающим входом или с напряжением около половины питания потребляет лишний ток; у аналоговых входов цифровые буферы отключают регистрами DIDR0 и DIDR1.
  • Отладка debugWIRE: при запрограммированном фьюзе DWEN основной генератор работает и во сне.

Регистр PRR останавливает такт отдельных модулей — TWI, Timer/Counter0, 1 и 2, SPI, USART0 и АЦП — в активном режиме и в Idle; в более глубоких режимах эти такты и так остановлены. Состояние модуля при этом замораживается, а его регистры недоступны. АЦП перед остановкой через PRADC нужно выключить, а TWI, SPI и USART после возврата лучше заново инициализировать.

Ток потребления ATmega328P

РежимУсловияТипично, 25 °CМаксимум, −40…85 °C
Активный1 МГц, 2 В0,3 мА0,5 мА
Активный4 МГц, 3 В1,7 мА2,5 мА
Активный8 МГц, 5 В5,2 мА9 мА
Idle1 МГц, 2 В0,04 мА0,15 мА
Idle4 МГц, 3 В0,3 мА0,7 мА
Idle8 МГц, 5 В1,2 мА2,7 мА
Power-saveчасовой кварц 32 кГц, 1,8 В0,8 мкА—
Power-saveчасовой кварц 32 кГц, 3 В0,9 мкА—
Power-downсторожевой таймер включён, 3 В4,2 мкА8 мкА
Power-downсторожевой таймер выключен, 3 В0,1 мкА2 мкА

Данные — таблица 29-8 даташита; значения сняты с PRR = 0xFF, то есть с остановленной периферией, и включают ток утечки входов. Батарея ёмкостью 1000 мА·ч при среднем токе 5 мкА теоретически проработала бы больше 20 лет — на практике срок задают саморазряд батареи и потребление остальной схемы.

Пример: просыпаться каждые 8 секунд

Кристалл спит в Power-down с выключенным BOD и просыпается по прерыванию сторожевого таймера. Таймаут 8 с соответствует WDP3:0 = 1001 — 1024K тактов генератора 128 кГц; время для других значений покажет калькулятор сторожевого таймера.

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

ISR(WDT_vect)
{
    /* wake-up only */
}

static void wdt_interrupt_8s(void)
{
    cli();
    wdt_reset();
    MCUSR &= ~(1 << WDRF);                             /* WDRF would keep WDE set */
    WDTCSR = (1 << WDCE) | (1 << WDE);                 /* timed sequence */
    WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);  /* interrupt mode, 8 s */
    sei();
}

int main(void)
{
    ADCSRA &= ~(1 << ADEN);    /* the ADC would stay powered in sleep */
    PRR = 0xFF;                /* stop the clocks of all modules */
    wdt_interrupt_8s();
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);

    for (;;) {
        /* periodic work goes here */
        cli();
        sleep_enable();
        sleep_bod_disable();   /* picoPower parts only */
        sei();
        sleep_cpu();
        sleep_disable();
    }
}

Если программе нужны таймеры, USART или АЦП, соответствующие биты PRR сбрасывают перед их использованием. Как работают сами таймеры и прерывания AVR, описано в статье об архитектуре AVR, а характеристики ATmega328P собраны на его странице атласа.

Частые вопросы

Какой ток потребляет ATmega328P в режиме Power-down?

По таблице 29-8 даташита при 3 В и 25 °C — типично 0,1 мкА с выключенным сторожевым таймером (не больше 2 мкА во всём диапазоне температур) и 4,2 мкА с включённым (не больше 8 мкА). Это ток самого кристалла с остановленной через PRR периферией; подтяжки, светодиоды, стабилизатор и плавающие входы на плате могут потреблять в тысячи раз больше.

Что может разбудить AVR из режима Power-down?

У ATmega328P — внешний сброс, сброс или прерывание сторожевого таймера, сброс по снижению питания (BOD), совпадение адреса на шине TWI, прерывание INT0 или INT1 по низкому уровню и прерывание по изменению состояния вывода (pin change). Прерывания таймеров и USART в Power-down не работают — для пробуждения по таймеру есть режим Power-save с Timer/Counter2.

Что такое picoPower у AVR?

Так Atmel называла свою технологию снижения потребления; в даташите DS40002061B picoPower-кристаллами названы ATmega48PA, 88PA, 168PA и 328P. Их отличие, описанное в главе о сне, — программное отключение детектора BOD на время сна битами BODS и BODSE: в глубоком сне BOD потребляет заметную долю тока. У ATmega328 без P этих битов нет.

Почему AVR не засыпает или сразу просыпается?

Частые причины: не установлен бит SE в SMCR перед командой SLEEP; прерывания запрещены и кристалл засыпает навсегда — или, наоборот, флаг прерывания уже установлен и пробуждает его сразу; прерывание INT0 или INT1 настроено на фронт, а описание Power-down в даташите обещает пробуждение только по низкому уровню. Для пробуждения по внешнему сигналу надёжнее pin change или INT0/INT1 по низкому уровню.

Источники

  1. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — гл. 10 — режимы сна, таблицы 10-1 и 10-2, BOD Disable, PRR, минимизация потребления; MCUCR (BODS, BODSE); гл. 13 — асинхронное распознавание внешних прерываний; сторожевой таймер — WDRF и WDE; таблица 29-8 — ток ATmega328P в активном режиме, Idle, Power-save и Power-down
  2. AVR-LibC: <avr/sleep.h> (github.com/avrdudes/avr-libc) — set_sleep_mode, sleep_enable, sleep_cpu, sleep_disable, sleep_bod_disable и безопасная последовательность засыпания

Нашли ошибку?