AVR - Power management или как правильно спать

AVR
Когда начинаешь задумываться о снижении потребления камня — обычно все остальное уже вылизано. И светодиод мигает как надо, и RTOS исправно щелкает задачами, и экранчик подмигивает курсором. Соответственно, этот раздел можно рассматривать как мини-квалификационный экзамен на AVR-джедая. После него остается только всякая экзотика — вроде асинхронных счетчиков или External Memory Interface у старших мег.

Как вообще мы можем влиять на энергопотребление кристалла? Что там вообще потребляет?

Основной элемент кристалла — полевой транзистор. Он в стабильном режиме практически не потребляет энергии — емкость затвора изолирована и практически не разряжается, сопротивление в открытом состоянии мало. А вот при переключении нам надо очень быстро перезарядить эту емкость. Соответственно, чем быстрее, тем больше тока надо вдуть в затвор. А чем больше ток при постоянном сопротивлении, тем больше потери. И поэтому, чем выше тактовая частота, тем больше энергопотребление. Отсюда вывод — если хотим экономить, то сразу надо снижать частоту.

Память. То же самое — в стабильном режиме практически ничего не потребляет (наноамперы). Основные затраты — при чтении и записи.

Отсюда вывод — остановив процессор, затормозив его часы до нуля, можно снизить энергопотребление кристалла до минимума. Попробуем достичь его.

Начнем с классики — мигаем светодиодом:


...
DDRB = _BV(PB4); // запрограммируем порт B на выход
while (1) {
    PORTB |= _BV(PB4); // зажгем светодиод
    _delay_ms(500); // пауза 500 мсек
    PORTB &= ~_BV(PB4); // погасим светодиод
    _delay_ms(500); // пауза 500 мсек
}
...


Что мы здесь видим? Большую часть времени процессор ничего не делает — отсчитывает полсекунды. Если мы одним глазиком заглянем в описание функции _delay_ms(), то увидим внутри простой цикл. Главная задача которого — загрузить процессор на требуемое число тактов.
По большому счету такая ситуация будет практически всегда — по сравнению с 8-16 мегагерцами тактовой частоты весь внешний мир для процессора — тупые медленные улитки, которые раз в вечность соизволят нажать кнопку.
Ну а каждый такт процессора — это переключение сотен транзисторов, перезарядка сотен конденсаторов, потери, потери, потери…

Крепкий здоровый сон


Нам для устранения такой несправедливости даны Sleep Modes (режимы сна). В зависимости от камня, режимов сна может быть от двух до шести. Все зависит от того, чем спать.
Лезем в даташит на attiny13a (он у нас будет за базовый камень):
на первой странице — Low Power Idle, ADC Noise Reduction, and Power-down Modes
Чем они отличаются друг от друга? Крепкостью сна. Как и у человека, чем глубже спишь, тем труднее просыпаться. Поэтому всегда есть выбор — покемарить на рабочем месте или поспать дома.

Заглянем в раздел 7. Power Management and Sleep Modes — там есть табличка 7.1

attiny13a sleep modes

Чтобы разобраться с табличкой, надо сначала понять, кто чем тактируется.
Казалось бы, есть кварц или RC на 8 МГц, значит все на этих мегагерцах щелкает. А вот фиг.
В шестом разделе есть схема источников тактовых сигналов. Приведу ее фрагмент:

attiny13a clocks

Тут мы видим знакомые буквы. Видно, что на каждый блок идет отдельная тактовая линия. Остановив соответствующие часы, можно приостановить работу определенной части контроллера. Об этом и говорят крестики в табличке 7.1.

Например, в режиме Idle останавливается только clkCPU и clkFLASH — останавливается центральный процессор и флэш, поскольку из флэш кроме ЦП никто читать-то и не умеет. Зато все остальное работает — таймеры щелкают, порты дергаются (например, ШИМ), прерывания возникают. Но уже и этого достаточно — согласно даташиту, потребление должно снизиться как минимум в три-четыре раза.

Сопоставив режимы, видно, что режим сна идут в порядке возрастания глубины сна Idle — самый неглубокий, ADC Noise Reduction — поглубже, а Power-down — вообще летаргия.

Встает вопрос — а как же просыпаться? А по прерываниям, батенька. О том, кто может разбудить, написано в правой части таблицы 7.1

INT0 and Pin Change — изменение уровня на пинах PCINTx. Как-то так случилось, что у тиньки все шесть рабочих портов могут быть источником прерываний. Особняком стоит INT0 — он может срабатывать не только по смене уровня, но и еще по уровню. Но для определения смены уровня для этого прерывания требуется тактирование порта. Поэтому, как это и написано в сноске, для глубоких режимов сна INT0 может происходить только по уровню.
SPM/EEPROM Ready — при окончании работы инструкции записи в EEPROM или Self Programming Mode. То есть запустили запись/чтение в EEPROM, заснули, когда бодяга закончилась — проснулись.
ADC — прерывание по окончанию преобразования АЦП. Поскольку частота часов АЦП порядка сотни килогерц, а требуется 13-26 тактов на захват одного значения, то для центрального процессора АЦП почти настолько же медлителен, как и пользователь. Вдобавок, на точность преобразования влияют и шумы цифровой части кристалла. Вот второй режим сна как раз и придуман для того, чтобы остановить всю цифровую периферию, спокойненько и чистенько завершить преобразование и, проснувшись, уже обрабатывать результат.
Other I/O — все остальные прерывания ввода-вывода. SPI, UART и т.д. Работают, как видно из таблицы, только в режиме Idle. Во всех остальных режимах периферия отключается, соответственно и прерывания вызвать не может.
Watchdog Interrupt — отдельный асинхронный таймер. Для упрощения я его не показывал на фрагменте схемы 6.1, хотя он там есть. Он ни от чего не зависит и тикает себе с невысокой частотой. В принципе, его можно использовать как дополнительный таймер. Например, выставить на 2 секунды, проснуться, отряхнуться, оглядеться, если ничего подозрительного не произошло, то заснуть опять.

На работу, на работу, на любимую работу


Как, собственно, происходит просыпание?

Как только возникает прерывание, камень просыпается, ждет столько, сколько указано битами SUT (для тиньки это 6 тактов), ждет еще четыре такта, выполняет обработчик прерывания, потом продолжает работу с того места, где остановились до засыпания.

Чем можно отмерять время? Таймером. Но поскольку в тиньке недостаток таймеров (всего один), то можно задействовать WDT — WatchDog Timer. Он вполне себе отмеряет полсекунды за один заход. Один из плюсов ватчдога — он тактируется независимо, поэтому способен пробудить от самой глубокой спячки.

Опять же, особенности тиньки — ватчдог в ней может генерировать сброс или прерывание (у мег такого нет — ватчдог только на резет).

Соответственно, главный цикл нашей программы изменится на такую конструкцию:

...
// зажечь светодиод
// взвести таймер
// заснуть
// погасить светодиод
// взвести таймер
// заснуть
...


Как я уже говорил, если мы используем ватчдог, то в данном случае без разницы, на какой уровень сна мы провалимся — нас разбудят гарантированно. Значит смело погружаемся на самый глубокий уровень — режим Power-down. В этом режиме отключается практически все. И разбудить нас сможет только ватчдог и внешнее прерывание.


#include <avr/io.h>
#include <avr/wdt.h> // здесь организована работа с ватчдогом
#include <avr/sleep.h> // здесь описаны режимы сна
#include <avr/interrupt.h> // работа с прерываниями

ISR (WDT_vect) {
	PORTB ^= _BV(PB4); // переключаем светодиод
	WDTCR |= _BV(WDIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
}

int main() {

	// инициализация порта светодиода
	DDRB = _BV(PB4); // на этом пине висит светодиод
	PORTB = _BV(PB4); // зажгем его

	//инициализация ватчдога
	wdt_reset(); // сбрасываем
	wdt_enable(WDTO_1S); // разрешаем ватчдог 1 сек
	WDTCR |= _BV(WDIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
	sei(); // разрешаем прерывания
	
	set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
	while(1) {
        	sleep_enable(); // разрешаем сон
		sleep_cpu(); // спать!
	}
}


Померял потребление тиньки мультиметром — без сна потребляет 1,5мА, со сном — 240мкА. В шесть раз, неплохо.

Краткие пояснения (хотя из комментариев и так все ясно. Если не ясно — читайте соответствующие .h файлы):

ISR (WDT_vect) — обработчик прерывания от ватчдога. В данном примере ватчдог настроен так, чтобы генерировать прерывание, а не сброс.
wdt_reset() — команда сброса ватчдога. Макрос разворачивается в обычный asm(«wdr»);
wdt_enable(WDTO_1S) — у тинек, чтобы случайно не похерить настройки ватчдога, есть специальная последовательность работы с битами. Обязательно сначала выставить биты WDE и WDCE, а потом в течение 4 тактов указать остальные настройки. Подробнее — читаем даташит.
set_sleep_mode(SLEEP_MODE_PWR_DOWN) — просто макросы, выставляющие соответствующие биты в регистрах MCUCR, MCUCSR и EMCUCR. Ничего сверхобычного.
sleep_cpu() — разворачивается в asm(«sleep»);

Вот, в принципе, все основы для крепкого и здорового сна.

Лунатизм, или бег по граблям во время сна

0. Не забыть разрешить прерывания!
1. Не забыть настроить источники прерываний!
2. В случае просыпания по внешнему прерыванию по уровню необходимо обеспечить удержание уровня до момента полного просыпания процессора, иначе прерывание не отработается.
3. Засыпание процессора никак не изменяет состояние ног. При этом, если горел светодиод и потреблял 10 мА, то и после засыпания он будет гореть и потреблять те же 10 мА.
4. Не забывать про разные режимы работы ватчдога для тинек и для мег!
5. Заснуть можно, если все прерывания обработаны и мы находимся в главной программе. (спасибо dcoder)

Как спать и не храпеть

Несмотря на то, что мы погасили главный осциллятор, есть еще асинхронные части кристалла, которые работают независимо. На то они и асинхронные, что независимо от центрального тактования. Типичный пример, который мы уже проходили — ватчдог.

Естественно, если оно не нужно, то перед сном — отключать нафиг.

Brown-out Detector — он работает асинхронно, всегда контролирует напряжение питания. В тиньках есть возможность его остановить программно (Brown-out Detection Circuit with Software Disable Function). Если он останавливается программно, то перед заходом в режим сна он отключается автоматически (не контролирует уровень питания во время сна), а при просыпании включается также автоматически.

Watchdog — то же самое. Если он не нужен для просыпания, а батарейку жалко — отключаем.

АЦП и аналоговый компаратор — в режиме Idle, если они не нужны — отключить. В режиме Power-Down отключаются сами.

Internal Voltage Reference — внутренний источник опорного напряжения для АЦП и компаратора. Также используется для контроля напряжения питания (BOD). Отключается, если отключены все указанные компоненты.

Порты — как я уже отмечал выше, порты сами не сбрасываются при переходе в режим сна. Соответственно, убедиться в правильном состоянии портов — задача программиста. На входящем порту есть буфер. Если ножка просто болтается в воздухе или на ней около VCC/2, то в некоторых случаях это буфер будет хаотично переключаться, потребляя дополнительную энергию. Для пущего энергосбережения (да и для проектирования хороший тон) нужно эти порты привести в какое-то определенное состояние. Подтянуть к питанию, например.

У тиньки есть еще такой интересный порт — PRR (Power Reduction Register). Он позволяет отключать некоторую периферию в режиме Idle и в обычном активном режиме. Например, у attiny13 в нем используются два бита: PRTIM0 и PRADC. Позволяют остановить тактирование таймера0 и АЦП соответственно. У более толстых тинек — больше периферии.

PS. Добавлю — у атмела есть аппнот AVR4013 — PicoPower basics
В нем описали следующий опыт: от конденсатора питали ATMega88PA, она каждую секунду выполняла замер АЦП и посылала строку в USART. Без оптимизации питания — 6 секунд. С полной оптимизацией и засыпанием — более 217 секунд жизни.

Комментарии (44)

RSS свернуть / развернуть
Статья очень кстати. Большое спасибо за толковое описание. +1
0
Надо же, не знал что новые тиньки могут по кускам обесточиваться на лету. Я с таким только на STM32 столкнулся, где любую периферию перед использованием надо затакатовать сначала.
0
Та я сам офигел :)
Это, судя по всему, их технология picoPower
0
На технологию вроде не тянет. А так прикольно, надо в других новых камнях и в А'шках эту фичу поискать.
0
В Мега48...168 тоже есть.
0
Тоже глянул. На сайте атмела они помечены как picoPower среди списка мег
0
Вообще, с увеличением частоты ток потребления растет не только от того, что надо перезарядить емкость затвора, но и от протекания тока (сквозного, если не ошибаюсь его называют) через транзисторы в момент переключения.
Я так понял у вотчдога совсем отдельный, собственный генератор, от которого он работает? Т.е. он будет работать даже без внешнего кварца было бы питание?
0
Ну так а куда протекает этот ток? В какую-нить емкость или в затвор следующего транзистора. Как только емкость перезарядилась, то и ток прекратился, даже если транзистор открыт.

У ватчдога отдельный таймер на 128 кГц. От него, кстати, может и тинька тактоваться. Тиньки, кстати, без внешнего кварца и идут — у них и так ног мало.

А камни, которые идут с внешними кварцами, обладают еще двумя дополнительными режимами сна — там наоборот, работает кварцевый генератор, поскольку он мало жрет.
0
Он протекает от + к — :) Если ячейка из 2-х транзисторов в верхнем и нижнем плече. Я думаю во всех КМОП также сделано и сегодня такая схема используется.
0
Ну и ёмкость след. транзисторо, конечно, тоже надо зарядить
0
Тиньки, кстати, без внешнего кварца и идут — у них и так ног мало.
У тини15 (8 ног) он уже есть. XTAL1 и XTAL2 не обязательно на отдельные пины выводить. В тиньках (да и меге 8...168) их вместе с обычными IO линиями совмещают.
0
Вру. В тини15 его нету, но в тини25 уже есть.
0
Из шести ног две занимать кварцем… Это ваще какая-то особая ситуация должна быть.
0
Забыл добавить (а может я не увидел), что засыпать можно только находяcь в основной программе, а попытка задремать посреди обработчика прерывания ни к чему не приведет. Sleep просто не сработает.

Иногда прерывания юзать нельзя (надо отреагировать на какое-то специфическое событие, а не на будильник-INT0). В таком случае для снижения потребления есть пара хитростей:

1) Снизить частоту. Это дает довольно ощютимое снижение энергопотребления, а проц продолжает работать. Только задержки придется считать вручную — с учетом делителя. Частоту можно снизить в 256 раз у некоторых тинек и мег.
Задетектив что-то важное, можно поднять частоту, считать/записать/обработать кучу данных и опять пойти отдыхать на низкой частоте.

2) Глубокий сон + вачдог. Суть в том, что МК отваливается в power down сон, предварительно запустив собаку. Несколько десятков миллисекунд здорового сна и собака безжалостно будит MCU (Вачдог interrupt) или загоняет его в ресет. О том, что перезагрузка произошла по вине пса, можно узнать по биту WDRF в регистре MCUSR.
0
Опять же, особенности тиньки — ватчдог в ней может генерировать сброс или прерывание (у мег такого нет — ватчдог только на резет).
У мег это тоже есть. Как минимум у atmegaxx4 и atmegaxx8

И да, про PRR тема не раскрыта. Кстати, глючновая штука — наступал пару раз на грабли с использованием PRR — теперь юзаю только через макросы который одним махом по всей проге отключить можно.
0
А вот при переключении нам надо очень быстро перезарядить эту емкость. Соответственно, чем быстрее, тем больше тока надо вдуть в затвор. А чем больше ток при постоянном сопротивлении, тем больше потери.

Больше ток, но зато меньше время его прохождения. Энергия потерь при этом не меняется.
Другое дело что при большей частоте больше переключений за то же время.
0
Потери пропорциональны квадрату тока, а время уменьшается всего лишь линейно. Емкость и сопротивление-то остались те же. Так что потери растут.
0
Ток зарядки и разрядки конденсатора определяется сопротивлением, через которое он проходит. Если мы хотим увеличить ток, то для этого должны уменьшить сопротивление, на котором (вне зависимости от номинала) выделится энергия накопленная конденсатором W = CU^2 / 2.
0
эээ. А как ты предлагаешь уменьшить сопротивление? Представь себе, например, реальный триггер. Попытаемся его опрокинуть — открывается внешний транзистор, соединенный со входом (гейтом одного из транзисторов триггера), в гейт вдувается нужный заряд. Пока заряд не вдулся, течет ток. Как только емкость зарядилась, ток течь перестал. Естественно, сила тока зависит от напряжения питания. Поэтому и нормируется максимальная частота в зависимости от напряжения питания. Потому что при тех же сопротивлениях (а при изменениях частоты мы же схему кристалла не меняем) требуется больший ток. Больше ток — больше потери.
0
при большей частоте больше выделяется энергии потому, что мы чаще перезаряжаем конденсатор, а не потому, что конкретная перезарядка стала энергозатратнее.
0
Или ёмкость в том транзисторе не успевает зарядиться на высоких частотах? Я так понимаю при этом уменьшится ток.
0
Чем выще частота, тем меньше сопротивление конденсатора, тем больше ток протекает=)
0
да, сопротивление меньше, а ток больше. Но я говорю про конкретное переключение: если конденсатор не полностью зарядился, то меньше энергии выделится на резисторе, по которому шёл ток.
0
А что будет с МК если отключить питание во время сна?
0
К.О. «Она утонула».
0
Не совсем понял?
0
А что будет, если телевизор из розетки вырубить? Смысл вопроса. Спит контроллер, жрет мало. Отрубил питание, он сожрал энергию из фильтров питания и TOTAL K.O.(C)
0
После такого контроллер вообще не запускается, приходиться пререпрошивать
0
С какого перепуга вдруг. Раскройте страшную тайну!
0
Кто-нибудь нормально ответит, объяснит в чем дело, а то отвечают одни зазнавшиеся тела.
0
Во-первых, не тот у Вас уровень, чтобы остальных «зазнавшимися телами» называть.
Во-вторых, что вы там у себя в проекте делаете, какая у вас схема и задача, при каких условиях все работает, знают только астрономы и Вы.
В-третьих, если у Вас контроллер требует перепрошивки после того, как он вошел в сон и пропало питание, значит емкости на Вашей плате не разрядились до конца, и контроллер может питаться от них.
P.S. Грамотно заданный вопрос всегда найдет свой ответ. Здесь про атомные технологии ни кто не говорит. Здесь сообщество (читай друзья), к которым всегда можно обратиться в личку. Вежливость — залог хороших отношений и правильного расположения других участников к Вашей персоне. Удачи!
0
Ну вот, можете ведь когда захотите
0
Повторюсь, как правило никто гадать не будет «почему у Вас не так, как Вам хочется или как должно быть». Конкретный вопрос — конкретный ответ. Жаль, что у Вас не было желания уточнить проблему и получить сразу же конкретный ответ. Успехов в начинаниях.
0
Я так понял, что эта «ПРОБЛЕМА» обсуждалась на radioparty.ru??? Просто прочитал Ваш профиль и глянул на эту страничку…
0
ничего с ним не будет. просто еще один обычный день в жизни контроллера. когда опять питание подашь, он начнет работать с начала.
0
это видео не по вашей статье снято? :)
www.youtube.com/watch?v=Ob5fHhPDqvU
0
  • avatar
  • 286
  • 06 мая 2012, 19:56
Всем привет. Не могу придумать как запускать АЦП в режиме ADC Noise Reduction для преобразования в заданные промежутки времени.
Делаю устройство которое измеряет сетевое напряжение 50Гц. Настроил таймер чтобы за период сети срабатывало 128 прерываний, и в каждом прерывании запускаю АЦП на преобразование. Тут всё работает проблем нет. Хочется получить большей точности, а для этого усыпить микроконтроллер во время преобразования АЦП, но я не смогу усыпить микроконтроллер из прерывания. Если в прерывании только выставлять какой либо флаг, а в основной программе проверять этот флаг, и при необходимости запускать АЦП, то время семплирования будет гулять, и в итоге я получу ерунду, а не измеренное значение.
Может у Вас есть какие то идеи? Спасибо.
0
маааленькое уточнение — PCINT может будить МК из любого режима
0
вот интересно, если ресет к земле прижать — будет ли МК что либо потреблять?
0
Должен по идее, там же подтяжка.
0
ну кроме тока через подтяжку.
или вот так например: сделать выключатель, в одном положении на ресет подается +5В через 10Ком, в другом зацеплено на землю
0
Там внутренняя подтяжка. От внешней можно отказаться вообще.
0
Нуу, внутренняя там 100500 КОм, по этому тупо пальцем сбрасывается без подтяжки:) По этому не надо от неё отказываться:)
0
Бывает. Хотя если не использовать в среде с помехами, исключить контакт с пальцем и не тянуть дорожку ресета через полплаты (а лучше — вообще не тянуть) — то можно и встроенной обойтись.

Но вопрос-то был не в этом, а в том, что с придавленным ресетом проц все равно будет жрать через подтяжку ресета, и жрать не так мало — она так килоом сто.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.