Режимы сна и энергосбережение 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 | Режим | Что продолжает работать | Чем разбудить |
|---|---|---|---|
| 000 | Idle | вся периферия: SPI, USART, АЦП, компаратор, TWI, таймеры, сторожевой таймер; остановлены только ядро и Flash | любое прерывание, внешнее или от периферии |
| 001 | ADC Noise Reduction | АЦП, внешние прерывания, адресное совпадение TWI, Timer/Counter2 в асинхронном режиме, сторожевой таймер | окончание преобразования АЦП, прерывания Timer/Counter2, сторожевого таймера, SPM/EEPROM, INT0/INT1 по уровню, pin change, адрес TWI, сбросы |
| 010 | Power-down | только асинхронные узлы: внешние прерывания, адресное совпадение TWI, сторожевой таймер; основной генератор остановлен | сброс, сторожевой таймер, BOD, адрес TWI, INT0/INT1 по низкому уровню, pin change |
| 011 | Power-save | как Power-down, плюс Timer/Counter2 | то же плюс переполнение и совпадение Timer/Counter2 |
| 110 | Standby | как Power-down, но генератор не останавливается | как Power-down, пробуждение за 6 тактов |
| 111 | Extended 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 мА |
| Idle | 1 МГц, 2 В | 0,04 мА | 0,15 мА |
| Idle | 4 МГц, 3 В | 0,3 мА | 0,7 мА |
| Idle | 8 МГц, 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 по низкому уровню.
Источники
- 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
- AVR-LibC: <avr/sleep.h> (github.com/avrdudes/avr-libc) — set_sleep_mode, sleep_enable, sleep_cpu, sleep_disable, sleep_bod_disable и безопасная последовательность засыпания
Нашли ошибку?
Смотрите также
- AVRATmega, ATtiny, AVR Dx/Ex: семейства, прошивка, инструменты
- ATmega328PРаспиновка, фьюзы, Optiboot, периферия, питание, схема и код на C
- Сторожевой таймер AVRВремя WDT по WDP, режимы, константы WDTO, код с последовательностью WDCE
- АЦП AVR: ADPS и кодЧастота АЦП, время преобразования, код по напряжению, ADMUX и ADCSRA
- Архитектура AVRЯдро, конвейер, память, порты, прерывания, сброс, такты и сон