Главная » Микроконтроллеры » Энергосбережение в микроконтроллерах STM32

Энергосбережение в микроконтроллерах STM32

Снижение энергопотребления микроконтроллером может быть достигнуто путем уменьшения его тактовой частоты (что связано с замедлением работы) или путем выборочного отключения периферийных систем, встроенных в его структуру. Этот второй механизм идеально подходит для микроконтроллеров STM32, которые конструктивно адаптированы для выборочного включения и выключения большинства встроенных периферийных блоков.

Мы начнем с обсуждения доступных режимов сохранения, которые были протестированы на наборе STM3210B — EVAL / A.

Спящий режим

Этот режим энергосбережения является неотъемлемой частью ядра Cortex-M3, поэтому информацию о нем следует искать не в документации, подготовленной производителем микроконтроллеров STM32, а в описании ядра, подготовленное ARM.

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

Максимальное потребление, когда микроконтроллер работает с тактовой частотой 72 МГц (HSE и PLL включены) и все периферийные устройства включены, микроконтроллер может потреблять около 15 мА. Минимальное потребление — работа ядра с тактовой частотой 125 кГц с использованием внутреннего генератора HSI и после отключения всех периферийных устройств. В таких условиях микроконтроллер потребляет ток не более 0,5 мА.

В зависимости от механизмов «сна» и «пробуждения» различают несколько типов режимов работы. За управление этими режимами отвечают две инструкции: WFI (ожидание прерывания) и WFE (ожидание события). Использование этих инструкций в программе, написанной на C, требует использования двойного подчеркивания в качестве префикса. Например: чтобы вызвать инструкцию WFI, используйте следующую запись:

__WFI ();

Sleep-on-exit

Использование инструкции WFI позволяет, помимо прочего, перевести ядро ​​в состояние ожидания на выходе. В этом случае ядро ​​переводится в спящий режим только после завершения всех прерываний. Выход из режима происходит тогда, когда в системе обнаружен запрос обработки прерывания. Примером программы, которая работает, как описано, является пример 1 . Контроль за режимами сна осуществляет NVIC, поэтому были использованы функции, контролирующие его работу.

Пример 1. Фрагмент программы, иллюстрирующий режим энергосбережения в режиме ожидания.

int main (void)
{
EXTI_InitTypeDef EXTI_InitStructure;
RCC_Conf ();
NVIC_Conf ();
GPIO_Conf ();
// Информируем об источнике прерывания
GPIO_EXTILineConfig (GPIO_PortSourceGPIOD, GPIO_PinSource0);
// Прерывание будет сгенерировано по заднему фронту на EXTI_Line0
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init (& EXTI_InitStructure);
// После обработки прерывания режим сна будет восстановлен
NVIC_SystemLPConfig (NVIC_LP_SLEEPONEXIT, ENABLE);
while (1);
}

Прерывание от вывода PD0 микроконтроллера, к которому была подключена кнопка, было настроено по спадающему фронту. После его появления ядро ​​выйдет из спящего режима и будет вызвана функция обработки прерываний.

Функция обработки прерываний выглядит следующим образом:

void EXTI9_5_IRQHandler (void)
{
EXTI_ClearITPendingBit (EXTI_Line9);
GPIO_SetBits (GPIOC, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);
delay_ms (2000);
GPIO_ResetBits (GPIOC, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);
}

Ядро просыпается примерно на 2 секунды, зажигает четыре светодиода, гасит их и снова «засыпает».

Запуск этого режима во время отладки остановит отладчик. Ядро не работает, поэтому нет необходимости искать ошибки. Однако микроконтроллер можно настроить таким образом, чтобы даже в режимах пониженного энергопотребления соединение отладчика и микроконтроллера не нарушалось. Для этого используется функция DBGMCU_Config (), например, если вы используете спящий режим, введите в программе следующую строку:

DBGMCU_Config (DBGMCU_SLEEP, ENABLE);

Sleep-now

Работа этого режима заключается в немедленном переводе ядра в режим пониженного энергопотребления. Это можно сделать с помощью инструкций WFI и WFE. Разница заключается в том, что в первом случае система будет ожидать прерывания, а во втором — события.

Время, необходимое для выхода ядра из спящего режима в ожидании события (команда WFE), почти в два раза короче и составляет около 2 с. Это связано с тем, что для обработки прерывания не требуется времени. Вывод заключается в том, что использование инструкции WFE очень хорошо подходит для работы с часами реального времени RTC, задачей которых может быть генерация событий (аварийных сигналов).

Пример 2. Программа, которая выводит микроконтроллер из спящего режима каждые 30 секунд

int main (void)
{
EXTI_InitTypeDef EXTI_InitStructure;
DBGMCU_Config (DBGMCU_SLEEP, ENABLE);
RCC_Conf ();
NVIC_Conf ();
GPIO_Conf ();
// Строка 17 как событие (RTC)
EXTI_StructInit (& EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init (& EXTI_InitStructure);
PWR_BackupAccessCmd (ENABLE); // Разрешение на доступ к Backup domain
BKP_DeInit ();
RCC_LSEConfig (RCC_LSE_ON); // Включаем LSE
while (RCC_GetFlagStatus (RCC_FLAG_LSERDY) == RESET); // Ждем старт
RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE); // Ссылочный номер источника LSE ZEG. для RTC
RCC_RTCCLKCmd (ENABLE); // Включить время RTC
RTC_WaitForSynchro (); // Ожидание синхронизации RTC с APB
RTC_WaitForLastTask ();
RTC_SetPrescaler (32768); // Будут подсчитываться импульсы каждые 1 с
RTC_WaitForLastTask ();
while (1)
{
NVIC_SystemLPConfig (NVIC_LP_SEVONPEND, ENABLE);
// Высший приоритет
NVIC_SETPRIMASK ();
RTC_SetAlarm (RTC_GetCounter () + 30); // Просыпаюсь каждые 30 секунд
RTC_WaitForLastTask ();
GPIO_ResetBits (GPIOC, GPIO_Pin_6);
__WFE (); // Ожидание события
GPIO_SetBits (GPIOC, GPIO_Pin_6);
delay_ms (2000);
}
}

В программе примера 2 RTC настроен на пробуждение микроконтроллера каждые полминуты. Светодиод LD1 загорается в нормальном режиме работы. Кроме того, в этом примере состояние текущей задачи достигает наивысшего приоритета, и, таким образом, NVIC не будет прерывать ее выполнение для обслуживания прерывания. Это можно увидеть, например, если активировано прерывание от кнопки (PB9) и фрагмент кода помещен в функцию обработки прерываний, которая будет оказывать видимое влияние на оценочную плату.

Пример такой функции:

void EXTI0_IRQHandler (void)
{
EXTI_ClearITPendingBit (EXTI_Line0);
GPIO_SetBits (GPIOC, GPIO_Pin_9);
}

Чтобы проверить, работает ли приложение должным образом, вы можете запустить программу из примера 2, добавив следующую строку в начале основного бесконечного цикла:

NVIC_SystemLPConfig (NVIC_LP_SEVONPEND, DISABLE);

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

Deep-sleep

Последний режим пониженного энергопотребления ядра — Deep-sleep (глубокий сон). Это не какой-то отдельный режим. Его получают путем объединения режима ожидания или режима ожидания после обработки всех прерываний (режим ожидания при выходе). Режим активируется установкой бита SLEEPDEEP в регистре управления питанием контроллера прерываний NVIC.

Программист, использующий библиотеку API, не должен вдаваться в эти детали, просто используйте соответствующую функцию: если приложение требует перевода ядра в состояние глубокого сна, вы должны поместить в код дополнительную строку:

NVIC_SystemLPConfig (NVIC_LP_SLEEPDEEP, ENABLE);

Следствием активации Deep-sleep является отключение часов, тактирующих ядро, включая систему PLL. Это позволяет дополнительно снизить энергопотребление по сравнению с предыдущими режимами. Негативный эффект от глубокого сна заключается в более длительном времени, необходимом для полного пробуждения и начала нормальной работы. Это связано с тем, что контур фазовой синхронизации требует времени для генерации стабильного тактового сигнала.

Stop Mode

Он использует режим глубокого сна, который обсуждался ранее. Все тактовые сигналы отключены (система PLL и оба быстрых генератора: HSI и HSE). Кроме того, внутренний регулятор напряжения 1,8 В может быть установлен за счет более позднего и более длительного запуска системы в состоянии пониженного энергопотребления.

Несколько блоков все еще работают в режиме остановки. К ним относится независимая сторожевая система. Это следует учитывать в приложениях, использующих IWDG и работающих в режимах пониженного энергопотребления.

Если часы реального времени и медленные генераторы (LSE и LSI) не были выключены ранее, они находятся в активном состоянии во всех режимах пониженной мощности.

Пример 3. Способ перевода микроконтроллера в режим остановки

int main (void)
{
EXTI_InitTypeDef EXTI_InitStructure;
DBGMCU_Config (DBGMCU_STOP, ENABLE);
RCC_Conf ();
NVIC_Conf ();
GPIO_Conf ();
// Строка 17 как событие (RTC)
EXTI_StructInit (& EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init (& EXTI_InitStructure);
PWR_BackupAccessCmd (ENABLE); // Разрешение на доступ к Backup domain
BKP_DeInit ();
RCC_LSEConfig (RCC_LSE_ON); // Включаем LSE
while (RCC_GetFlagStatus (RCC_FLAG_LSERDY) == RESET); // Ждем старт
RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE); // Ссылочный номер источника LSE ZEG. для RTC
RCC_RTCCLKCmd (ENABLE); // Включить время RTC
RTC_WaitForSynchro (); // Ожидание синхронизации RTC с APB
RTC_WaitForLastTask ();
RTC_SetPrescaler (32768); // Будут подсчитываться импульсы каждые 1 с
RTC_WaitForLastTask ();
while (1)
{
RTC_SetAlarm (RTC_GetCounter () + 10); // Просыпаться каждые 10 секунд
RTC_WaitForLastTask ();
GPIO_ResetBits (GPIOC, GPIO_Pin_6);
PWR_EnterSTOPMode (PWR_Regulator_LowPower, PWR_STOPEntry_WFE);
// *** Снова включить PLL и HSE ***
RCC_HSEConfig (RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp ();
if (HSEStartUpStatus == SUCCESS)
{
RCC_PLLCmd (ENABLE);
while (RCC_GetFlagStatus (RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource ()! = 0x08);
}
// *** HSE и PLL включены ***
GPIO_SetBits (GPIOC, GPIO_Pin_6);
delay_ms (2000);
}
}

Способ перевода микроконтроллера в режим остановки показан на примере 3, Задача этой простой программы — переводить микроконтроллер в режим остановки примерно каждые 2 секунды, а сама остановка длится 10 секунд. Сигнализация нормальной работы осуществляется путем свечения светодиода LD1. Пробуждение происходит под воздействием сигналов тревоги, генерируемых с использованием часов реального времени.

После сброса флага события из RTC устанавливается время, после которого должен быть сформирован следующий сигнал тревоги. В этом примере микроконтроллер должен просыпаться каждые 10 секунд, поэтому каждый раз к текущему значению счетчика RTC следует прибавлять значение 10. Достижение числа, полученного таким образом, приведет к тревоге. Задача следующей вызываемой функции PWR_EnterSTOPMode () — правильно перевести систему в состояние остановки. В программе, из-за отсутствия специальных требований относительно минимального времени запуска системы, регулятор напряжения переводиться в режим low power

В этот момент работа микроконтроллера будет приостановлена ​​и начнется с этого места после пробуждения. В связи с тем, что в режиме остановки отключаются фазовая синхронизация и быстрые генераторы, их следует снова включить после возврата к нормальной работе. Если приложение использует внутренний генератор HSI и не использует систему PLL, то перенастройка этих устройств не требуется: система автоматически задействует HSI в качестве источника своего тактового сигнала.

Standby mode

Использование этого режима позволяет максимально снизить энергопотребление. Как и в режиме остановки, также в режиме ожидания используется глубокий сон, но стабилизатор 1,8 В отключается без дополнительного вмешательства пользователя. Переход в режим ожидания приводит к потере данных, содержащихся в оперативной памяти, чего нет в предыдущих режимах. Однако данные, содержащиеся в регистрах, защищенных от потери, не изменяются, и свободные генераторы (резервный домен) все еще работают при условии, что резервный источник питания батареи Vbatt подключен к микроконтроллеру. Работа продолжается с независимой сторожевой системой (если ранее была включена) и системами восстановления.

Потребляемый ток при включенном медленном генераторе и часов реального времени варьируется от 3 до 3,5 мА, в зависимости от значения напряжения питания.

Микроконтроллер активируется, сигнал сброса появляется после независимого переполнения сторожевого таймера (IWDG), с нарастающим фронтом на линии пробуждения или после тревоги RTC.

Система начинает нормальную работу так же, как после сигнала аппаратного сброса. По этой причине время, необходимое для нормальной работы системы, является самым длительным (около 50 сек.). Индикатором того, что активация произошла после выхода из режима ожидания, является флаг SBF, установленный в регистре PWR_CSR. В библиотеке функций API это называется PWR_FLAG_SB.

Пример 4. Фрагмент программы, иллюстрирующий использование режима ожидания

int main (void)
{
RCC_Conf ();
GPIO_Conf ();
// При отладке соединение не будет разорвано
DBGMCU_Config (DBGMCU_STANDBY, ENABLE);
// Включить поддержку распиновки Wakeup (PA0)
PWR_WakeUpPinCmd (ENABLE);
// Разрешение на доступ к «Backup domain»
PWR_BackupAccessCmd (ENABLE);
// Установлен ли флаг ожидания?
if (PWR_GetFlagStatus (PWR_FLAG_SB)! = RESET)
{
// Если это так, система выходит из режима ожидания
GPIO_SetBits (GPIOC, GPIO_Pin_7);
// Очистить флаг PWR_FLAG_SB
PWR_ClearFlag (PWR_FLAG_SB);
// Ожидание синхронизации с APB1
RTC_WaitForSynchro ();
}
else
{
// Система загружается нормально, поэтому RTC должен быть настроен
BKP_DeInit ();
// Включаем свободный внешний генератор
RCC_LSEConfig (RCC_LSE_ON);
// Ждем правильного сигнала
while (RCC_GetFlagStatus (RCC_FLAG_LSERDY) == RESET);
// LSE будет источником тактового сигнала для RTC
RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE);
// Включить время RTC
RCC_RTCCLKCmd (ENABLE);
// Ожидание синхронизации с APB1
RTC_WaitForSynchro ();
RTC_WaitForLastTask ();
// RTC будет считать отдельные секунды
RTC_SetPrescaler (32768);
// Дождаться завершения команды
RTC_WaitForLastTask ();
}
NVIC_Conf ();
GPIO_SetBits (GPIOC, GPIO_Pin_6);
пока (1)
{
if (! GPIO_ReadInputDataBit (GPIOB, GPIO_Pin_9))
{
GPIO_ResetBits (GPIOC, GPIO_Pin_6);
// Включаем режим ожидания
PWR_EnterSTANDBYMode ();
}
}
}

В примере 4 приведен фрагмент программы , использующий режим ожидания. Приложение информирует о состоянии микроконтроллера с помощью светодиода LD1. Когда он загорается, он указывает на нормальную работу, а при его тушении — режим ожидания. Система возвращается в нормальное состояние при нажатии кнопки RESET или WAKEUP.

В дополнение к перечисленным функциям также настроена система часов реального времени. Благодаря этому текущее состояние микроконтроллера можно наблюдать во время отладки. Режим ожидания возвращается в режим после нажатия кнопки (PB9).

Задача основного, бесконечного цикла программы — постоянно проверять состояние линии PB9. Когда на нем появляется низкое состояние, система готова к переходу в режим ожидания. Наконец, вызов PWR_EnterSTANDBYMode () включает режим ожидания.

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

Другим важным шагом является проверка, начинает ли микроконтроллер работать после пробуждения или нет. Если установлен флаг PWR_FLAG_SB, светодиод LD2 горит, и вызов функции PWR_ClearFlag () сбрасывает флаг ожидания. Наконец, функция RTC_WaitForSynchro () заставляет микроконтроллер ожидать синхронизацию со схемой часов реального времени. Это необходимо, поскольку эта система подключена к внутренней шине APB1, и ее тактирование было отключено в режиме ожидания.

В случае, если флаг PWR_FLAG_SB был сброшен, то конфигурируются часы реального времени и ее сигнал синхронизации.

Оставить комментарий

Ваш email нигде не будет показан. Обязательные для заполнения поля помечены *

*