Уроки MSP430 LaunchPad. Урок 11: Экономия, должна быть экономной!

Мы уже обрели, определенную степень контроля над MSP430, это хорошая возможность узнать о режимах пониженного потребления энергии. Это одна из важнейших особенностей MSP430, и прекрасная причина для выбора именно этого микроконтроллера, вместо других. Посмотрим, как эти режимы работают.



В руководстве по семейству микроконтроллеров x2xx, на странице 29, приведена диаграмма и таблица, разъясняющие, как работают режимы системы тактирования. Для нашего удобства, TI выделили 6 разных режимов, к которым нам будет проще доступиться через определения в заголовочном файле. MSP430 начинает работу в Активном Режиме, когда ЦПУ и вся периферия включены. Это режим работы, в котором мы использовали микроконтроллер во всех предыдущих уроках. Каждый раз, когда MSP430 необходимо что-то сделать, это происходит в Активном Режиме. Но это не означает, что периферия не способна работать в других режимах. Всего есть 5 режимов пониженного энергопотребления (Low Power Mode (LPM)), сокращенно называющихся LPM0, LPM1, LPM2, LPM3 и LPM4. Они конфигурируются четырьмя битами регистра состояния SR, и являются основными режимами работы микроконтроллера. Маловероятно, что вам понадобится какой-то из десяти других режимов, которые можно получить из комбинаций этих четырёх битов. Единственное исключение, это если вам захочется отключить кварцевый генератор, место под который есть на LaunchPad, от использования в своем проекте, но об этом позже.

Функция _BIS_SR(), с которой мы уже встречались раньше, возможно простейший способ, использования LPM. Заголовочный файл содержит ряд имён, с общим шаблоном LPMx_bits для облегчения установки правильных битов. Для включения режима пониженного энергопотребления, просто добавьте команду _BIS_SR(LPMx_bits); заменив x на номер нужного режима LPM. Помните о том, что если вам нужно использовать прерывания, к битам настроек регистра состояния необходимо добавить GIE, или функцию _enable_interrupt(); до входа в режим LPM.

Другой, важный момент, о котором необходимо помнить, это то, что режимы LPM, индивидуальны, т.е. за один раз, один режим. Не нужно пытаться объединить несколько режимов в одной команде. Речь идет о подобных сочетаниях: _BIS_SR(LPM0_bits + LPM1_bits + GIE); попытка использовать такую команду, приведет к нежелательным побочным эффектам.

Одна из особенностей архитектуры MSP430, это то, что вам не нужно следить за тем, что бы ЦПУ проснулся для обработки прерывания, и не нужно возвращать ЦПУ в режим LPM, после обработки прерывания. Всё это, происходит автоматически. Когда возникает прерывание, регистр состояния помещается в стек, затем ЦПУ просыпается, дабы ублажить обработчик прерывания. Когда обработчик прерывания будет удовлетворен, исходный регистр состояния (SR), вместе с содержащимися в нем битами настройки LPM, возвращается на законное место и усыпляет ЦПУ. Если по логике программы, вам нужно оставить ЦПУ в рабочем состоянии, то, в обработчик прерывания, необходимо включить команду обнуления битов режима LPM:

_BIC_SR(LPMx_bits);  // обнуляем биты LPMx и выходим из режима пониженного энергопотребления

Обратите внимание на отличие имени функции _BIS_SR() (Bit Set Status Register) установка битов регистра состояния, от _BIC_SR() (Bit Clear Status Register) очистка битов регистра состояния, или обнуление.

(Насколько я понимаю, функция _BIC_SR(), обнуляет биты именно в том регистре состояния, который лежит в стеке, и её нужно применять перед самым выходом из обработчика прерывания. В заголовочных файлах IAR, установку режимов LPM, еще больше сократили (сохранив описанные здесь мнемоники), и достаточно написать, что-то вроде LPM1; что бы войти в режим LPM1. А для выхода из режима LPM1, достаточно в конце обработчика прерывания написать LPM1_EXIT; – Прим. пер.)

Пример использования режимов пониженного энергопотребления


В качестве примера, я написал простенькую программку, которая гудит динамиком 8 Ом. У меня есть динамик, с двумя выводами, расстояние между которыми 0.2”, и он идеально воткнулся в линейку выводов на LaunchPad. Что бы он вместился, я использовал выводы P1.0 и P1.2 микроконтроллера. Если у вас нет динамика, вы можете реализовать ту же идею, через зажигание двух светодиодов на LaunchPad. Просто замените в коде значение SOUT, с BIT2 на BIT6, и подберите соответствующую частоту срабатывания таймера.

Идея простая, мы стартуем с высоким уровнем на выводе P1.0 и низким на P1.2, а потом меняем их с заданной частотой. Это будет генерировать квадратную волну, не самый прекрасный звук, но гудит. Запомните, что звуковые частоты главным образом расположены в диапазоне от 10 Гц до 1000 Гц. Интересно узнать, насколько низкую частоту вы сможете услышать (щелчки не считаются, только основной тон) и насколько высокую. Для уменьшения громкости, можно оставить один из выводов в состоянии ноля, и переключать только второй.

Вот текст программы (тест оригинала limboG2211.c):

/* limboG2211: Тест режима пониженного энергопотребления.
*  Проверка как режим LPM влияет на поведение портов ввода/вывода.
*  Необходимо иметь динамик, подключенный к выводам P1.0 и P1.2, но можно
*  эмулировать его работу двумя светодиодами на выводах P1.0 and P1.6,
*  уменьшив частоту достаточно, для наблюдения за миганием.
*  Для эмуляции нужно заменить определение SOUT на
*  #define SOUT BIT6 и понизить частоту, увеличив значение в TACCR0.
*/

#include <msp430g2211.h>

#define SPKR   BIT0
#define SOUT   BIT2

void main(void) {
	
	WDTCTL = WDTPW + WDTHOLD;	// отключаем сторожевой таймер
	
	P1OUT = SPKR;	     // Правильнее было бы начать с обнуленным SPKR,
	                     // но так проще заменить динамик светодиодом.
	P1DIR = SPKR + SOUT; // Другой вывод динамика прижат к земле.
		             // Можно увеличить громкость, переключая
			     // SOUT и SPKR в противоположные состояния, одновременно.
	
	BCSCTL1 = CALBC1_1MHZ;		// Частота тактового сигнала 1 мГц
	DCOCTL = CALDCO_1MHZ;

	TACCR0 = 144;     // С делителем частоты на 8 (125 kHz), это значение
			  // даёт частоту 125000/(TACCR0+1) Гц.
			  // Для TACCR0 = 144, получаем 862 Гц.
							
	TACCTL0 = CCIE;   // Разрешаем прерывание таймера по достижению значения CCR0.
	TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR; // Настройка режима работы таймера Timer_A:
                                                // TASSEL_2 - источник тактов SMCLK (SubMainCLocK),
                                                // по умолчанию настроенных на работу от DCO
                                                // ID_3 - делитель частоты на 8, от 1MHz это будет 125kHz
                                                // MC_1 - режим прямого счёта (до TACCR0)
                                                // TACLR - начальное обнуление таймера
	_BIS_SR(LPM0_bits + GIE);	// Входим в режим LPM0 и разрешаем прерывания
	
} // main


/*  Обработчики прерываний  */
#pragma vector = TIMERA0_VECTOR
__interrupt void CCR0_ISR(void) {
		P1OUT ^= SPKR + SOUT;	// Взаимо-переключение выходов на динамик.
} // CCR0_ISR

Архив с программами из урока.

Упражнение: В этой программе использован режим LPM0. Попробуйте остальные режимы, заменив LPM1_bits на другой. Что случается при попытке включить режим LPM1? LPM2? LPM3? LPM4? Можете объяснить, почему некоторые режимы работают, а некоторые нет?

Примечания переводчика: Я использовал пьезо-зуммер, всё заработало. Только поменял название вектора прерывания на TIMER0_A0_VECTOR, т.к. у меня G2553. Если кто не понял сути примера, то обратите внимание на то, что в функции main(), отсутствует бесконечный цикл. Если не усыпить ЦПУ вечным сном, то он выскочит за границы кода.

Использование вспомогательного тактового сигнала


Если вы делали предыдущее упражнение, то заметили, что программа работает только в режимах LPM0 и LPM1. Причина этого, в выборе источника тактовых сигналов для таймера. Давайте подробней разберем, что именно делает предыдущий пример.

Во-первых, мы устанавливаем внутренний генератор DCO, на откалиброванную частоту 1 мГц. Думаю всем понятно, что основной тактовый сигнал (MCLK), управляет ЦПУ, генерируя ему такты с частотой 1 мГц. То, что может быть не очевидно, что дополнительный тактовый сигнал (SMCLK), так же генерируется DCO, и его частота тоже 1 мГц.

Таймер настроен на работу от SMCLK с делителем на 8, или 125 кГц. Таймер считает до значения TACCR0, и генерирует прерывание, в котором переключается направление тока через динамик (или светодиод, если вы так сделали). Из-за того, что частота переключения, достаточно высока, динамик издаёт однотонный звук.

Между переключениями, MSP430 находится в режиме LPM0. Мы можем понять, что именно происходит с микроконтроллером в этом режиме, если посмотрим на картинку в начале урока. Бит CPUOFF в регистре состояния SR устанавливается в 1, что приводит к отключению ЦПУ и тактовых сигналов MCLK, тактовые сигналы SMCLK и ACLK продолжают работать. Если мы включим режим LPM1, то CPUOFF установится в 1, а так же SGG0 установится в 1. В этом режиме добавляется отключение DCO, но только в случае, если сигналы SMCLK не используются. В нашем случае, сигналы SMCLK используются для управления таймером. Так что, внутренний генератор DCO, продолжает работать. В данной программе, нет никакой разницы между режимами LPM0 и LPM1.

Если мы включим режим LPM2, то установятся биты CPUOFF и SGG1, благодаря чему, отключатся ЦПУ, MCLK, а так же SMCLK и DCO. В нашей программе, при включении режима LPM2, отключается источник тактовых сигналов для таймера А, и он никогда не достигнет значения TACCR0. А значит, прерывание никогда не возникнет и не разбудит спящую красавицу ЦПУ. Тем не менее, в режиме LPM2, прекрасный принц в виде вспомогательного тактового сигнала ACLK, продолжает бодрствовать. И если мы доверим управление таймером А ему, то сможем погружать MSP430 в глубокие режимы сна, что приведет к огромной экономии. Экономия означает долгую жизнь батареек и более эффективное использование ресурсов в вашем проекте.

Обычно тактовый сигнал ACLK, задаётся низкочастотным генератором LFXT1, более экономным, чем генератор DCO, что приближает нас к цели, минимизировать энергопотребление устройства. По умолчанию, он предназначен для работы от кварца 32768 кГц. В комплектации LaunchPad, есть такой кварц, вы можете его впаять, в предназначенное для него место. При отсутствии внешнего кварца, генератор LFXT1, подключается к сигналам встроенного низкочастотного генератора VLO (Very-low Power), похожего на DCO, но работающего на частоте 12 кГц.

Настраиваем LFXT1 и ACLK


Если вы планируете использовать кварцевый генератор для LFXT1, то настроить его будет легко. Кварц, идущий в комплекте с LaunchPad, нуждается в конденсаторах 12.5 пФ для стабильной работы. Вы даже можете увидеть, площадки для распайки этих конденсаторов на плате. Можете их туда впаять, а можете использовать те, которые встроены в MSP430, они подключаются настройкой битов XCAPx в регистре BCSCTL3, и среди них как раз есть на 12.5 пФ. Просто впаяйте кварц, в предназначенное для него место и правильно настройте модуль синхронизации. В других уроках, мы подробней поговорим о подключении внешних кварцев, а пока будем использовать низкочастотный и супер-экономный VLO, как источник тактов для вспомогательного сигнала ACLK.

В разделе, посвященном работе модуля синхронизации, руководства по семейству x2xx (стр. 230), находится вся необходимая информация о его настройке. Регистры, которые нам нужны, это BCSCTL1 и BCSCTL3. Для настройки VLO используются бит XTS (бит 6) в BCSCTL1 и биты LFXT1Sx (5 и 4) в BCSCTL3. Бит XTS, настраивает генератор LFXT1, как низкочастотный (0) или высокочастотный (1). Многие модели MSP430 поддерживают подключение высокочастотных кварцев к LFXT1, но модели ряда Value Line, позволяют использовать только низкочастотные (обычно 32768 кГц) кварцы. Большинство моделей, включая Value Line, позволяют использовать VLO. Для этого биты LFXT1Sx, нужно установить в 0b10. В Си уже есть готовое сокращение из заголовочного файла, используем его:

BCSCTL3 |= LFXT1S1;  // устанавливаем биты LFXT1Sx в 0b10, подключаем VLO

Нет нужды вручную настраивать бит XTS, он по умолчанию включен в низкочастотный режим. Для подключения VLO, достаточно этой строчки.

С генератором LFXT1, теперь работающим от 12 кГц, сигнал ACLK может быть использован для периферии. Если помните из Урока 08, ACLK может работать только от LFXT1 с внешним кварцем или VLO. Тем не менее мы можем настраивать его частоту, применяя делители сигнала VLO на 2, 4 или 8. Это делается с помощью битов DIVAx (5 и 4) регистра BCSCTL1. Для наших целей, мы запустим ACLK на частоте 3кГц, применив делитель на 4. Это делается так:

BCSCTL1 |= DIVA_2;  // частота ACLK делится на 4

Не забывайте, что вы еще можете применить делитель, к частоте работы самого периферийного устройства. Например, мы можем запустить таймер на частоте 750 Гц, с помощью делителя на 4:

TACTL = TASSEL_1 + ID_2 + MC_1 + TACLR;  // используем ACLK, делитель 4, прямой режим, обнуление

Суммируя, всё, о чём говорилось выше, внесём изменения в нашу программу:

BCSCTL1 = CALBC1_1MHZ; // Используем частоту 1 мГц
DCOCTL = CALDCO_1MHZ;
BCSCTL3 |= LFXT1S1; // устанавливаем биты LFXT1Sx в 0b10,
                    // подключаем низкочастотный генератор VLO 

TACCR0 = 14;  // С таймером, работающим от ACLK (12 кГц), это
              // значение даёт частоту 12000/(TACCR0+1) Гц.
              // Для TACCR0 = 14, это 800 Hz.

TACCTL0 = CCIE; // Разрешаем прерывание таймера по достижению значения TACCCR0.
TACTL = TASSEL_1 + MC_1 + TACLR; // используем ACLK, прямой режим, обнуляем таймер
 
_BIS_SR(LPM3_bits + GIE);    // Входим в режим LPM3 и разрешаем прерывания

Архив с программами из урока.

Этот код, запускает ACLK от VLO (на 12 кГц) и затем использует таймер А, для переключения динамика на частоте около 800 Гц. Самое важное изменение, относительно исходного кода. Мы теперь используем сигналы ACLK, для управления таймером, который вызывает прерывания, поэтому можем использовать режимы пониженного энергопотребления LPM2 и LPM3. Последний режим, LPM4, отключает даже ACLK, поэтому его можно использовать, только если у вас есть источник внешних прерываний, например сигнал от одного из портов ввода/вывода (кнопка, например – Прим. пер.).

Принципы программирования устройств с низким энергопотреблением


Несколько советов от Texas Instruments:

В большинстве случаев наиболее действенным методом снижения энергопотребления является максимизация времени пребывания микроконтроллера в режиме LPM3. Типовое потребление тока в этом режиме составляет менее 2 мкА, при включенной схеме часов реального времени и полностью активированной системе прерываний. Для формирования тактового сигнала ACLK используется «часовой» кварц частотой 32 кГц, а ЦПУ тактируется от DCO (выключенного большую часть времени), время выхода на режим которого составляет 6 мкс.

  • Используйте прерывания для «пробуждения» процессора и управления ходом выполнения программы.
  • Включайте периферийные устройства только по необходимости.
  • Используйте вместо программно реализуемых функций встроенные периферийные модули с низким энергопотреблением. Например, Таймер А и Таймер B могут генерировать сигнал с ШИМ и осуществлять захват внешних сигналов автоматически, без использования ресурсов ЦПУ.
  • Используйте вычисляемые переходы и быстрые табличные вычисления вместо опроса флагов и длительных программных вычислений.
  • Постарайтесь избегать частых вызовов подпрограмм, чтобы снизить накладные расходы.
  • В длинных подпрограммах для хранения данных следует использовать регистры ЦПУ, обращение к которым производится за один такт.


Мы еще вернемся к режимам пониженного энергопотребления в следующих уроках. Далее мы начнем изучать, как использовать микроконтроллер для сравнения двух аналоговых сигналов, и постепенно придем к аналогово-цифровому преобразованию.

Упражнение: Если у вас припаян часовой кварц на LaunchPad, но вы не используете ACLK, в своём проекте. То должны знать, что кварц всё время генерирует и потребляет энергию (хоть и очень мало). Стандартными настройками режимов LPM, невозможно отключить генерацию ACLK, за исключением режима LPM4. В качестве упражнения, настройте свой, оригинальный режим LPM, в котором MCLK, SMCLK и DCO продолжают работать, а ACLK и кварцевый генератор отключены.

Оригиналы этого урока на английском: Tutorial 11-a: Going Low Power и Tutorial 11-b: Using the Auxiliary Clock

Предыдущий урок этого цикла: Урок 10: Постой паровоз… (Прерывания)
Следующий урок этого цикла: Урок 12: Всё познаётся в сравнении
  • +17
  • 17 ноября 2012, 06:29
  • Tabke
  • 1
Файлы в топике: lesson11.zip

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

RSS свернуть / развернуть
Хорошие уроки, спасибо переводчику!

Здесь опечатка: 750 кГц Гц.
«Не забывайте, что вы еще можете применить делитель, к частоте работы самого периферийного устройства. Например, мы можем запустить таймер на частоте 750 кГц, с помощью делителя на 4»
+1
Пользуясь последним примером по настройке LFXT1 и ACLK, написал мигалку для светодиода. Тактирование таймера от ACLK (VLO). Работает, только очень медленно. Код проверял. При тактировании таймера от DCO все работает как положено. В чем может быть причина такого странного поведения?
0
У меня почему то в прерывании вызов функции _BIC_SR(LPM0_bits); не возобновляет работу ЦПУ, а вот так все срабатывает _BIC_SR_IRQ(LPM0_bits);
0
  • avatar
  • Atas
  • 29 апреля 2013, 02:04
Это происходит потому что значение регистра SR сохраняется в стеке при обработке прерывания. Значит, при возврате из прерывания, состояние спящего режима будет восстановлено. Что бы процессор проснулся после прерывания надо режим сна корректировать не в регистре SR, а значение в стеке, которое будет записано в SR при выходе из прерывания.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.