PVD - реагируем на изменение напряжения питания (STM8L)

В микроконтроллерах STM8L есть функция, позволяющая определять изменение питающего напряжения и оперативно реагировать на него. Имя ей PVD — Programmable Voltage Detector.

Вообще-то, изменение напряжения питания можно отслеживать и при помощи АЦП, замеряя напряжение внутреннего ИОН относительно AVcc. Но этот способ не работает в спящем режиме и годится скорее для мониторинга питания, чем для оперативного реагирования на его изменение/отключение.

Что это?
По сути — компаратор с Vcc (через делитель) на одном входе, и переключаемым опорным напряжением, на другом. Пороговое напряжение выбирается из 6 вариантов, кроме того можно подать его с какой-нибудь внешней схемы. PVD имеет гистерезис ~100mV, благодаря чему он не будет давать ложные сигналы, если напряжение будет «дрожать» около порогового значения. Самая приятная новость заключается в том, что PVD может работать в спящем (Halt) режиме, потребляя всего пару микроампер. Естественно, прерывание PVD может будить МК из этого режима.

Все операции с PVD осуществляются через регистр PWR_CSR1. Битами PLS[2:0] можно выбрать одно из 6 пороговых напряжений. Минимальное 1.85V, а максимальное — 3.05V.
000 — 1.84
001 — 2.04
010 — 2.24
011 — 2.44
100 — 2.64
101 — 2.83
110 — 3.05
111 — Внешнее напряжение.

Теперь, если надо, можно включить прерывание, установив бит PVDIE. Оно, по какому-то странному стечению обстоятельств, обьединено с прерыванием EXTIE/F.

После того, как порог выбран, PVD будет сообщать о том, что напряжение питания упало ниже порога (или наоборот, поднялось выше него) установкой флага PVDIF. Если разрешено прерывание, то оно будет срабатывать при каждой установке PVDIF. Сбрасывать флаг надо вручную, записав в него 1. А узнать текущее положение дел можно через флаг PVDOF: если он равен 1, то напряжение питания ниже порога, иначе — выше.

В завершение всего, надо разрешить работу PVD, установив бит PVDE.

Настраивается PVD просто и лаконично:

PWR_CSR1_bit.PLS = 6; //6 уровень = 3.05V
PWR_CSR1_bit.PVDIE = 1; //разрешаем прерывание
PWR_CSR1_bit.PVDE = 1; //Запускаем PVD


Обработчик прерывания (вектор которого совпадает с EXTIE/F) должен сбросить флаг PVDIF перед выходом:


#pragma vector=EXTIPVD_vector
__interrupt void pvd_int()
{
 //Сохраняем данные, отключаем нагрузку, готовимся уйти в halt...   
 PWR_CSR1_bit.PVDIF = 1; //Сбрасываем PVDIF
}  


При работе через стандартную библиотеку, нам надо подключить модуль pwr (stm8l15x_pwr.h — для STM8L15x).
Далее, настройка PVD будет выглядеть примерно так:
PWR_PVDLevelConfig(PWR_PVDLevel_3V05); //Порог 3.05V
PWR_PVDITConfig(ENABLE); //Разрешаем прерывание
PWR_PVDCmd(ENABLE); //Включаем PVD

Мониторить состояние флага PVDOF можно функцией PWR_GetFlagStatus. Вот так:

if (PWR_GetFlagStatus(PWR_FLAG_PVDOF)==SET)
{
//Напряжение упало,
//Сделайте что-нибудь!
}


Обработка прерываний с использованием библиотек немного упрощается:

INTERRUPT_HANDLER(PVD_IRQ, EXTIE_F_PVD_IRQn)
{
//Код... код... код...
PWR_PVDClearITPendingBit();
}

Для примера напишем программу для STM8L-Discovery, которая будет реагировать на изменение напряжения питания. Пока оно выше 3.05V, будет гореть зеленый светодиод, а при снижении напряжения он будет тухнуть.

Писать будем с использованием стандартной битблиотеки, ибо так быстрее :)
Чтобы совсем быстро, воспользуемся шаблонами от PRC.

Весь код программы

#include "stm8l15x.h"
#include "stm8l15x_conf.h"
#include "discover_board.h"
#include "delay.h"

void main( void )
{
GPIO_Init(LED_GREEN_PORT, LED_GREEN_PIN, GPIO_Mode_Out_PP_Low_Fast);
GPIO_Init(LED_BLUE_PORT, LED_BLUE_PIN, GPIO_Mode_Out_PP_Low_Fast);

PWR_PVDLevelConfig(PWR_PVDLevel_3V05); 
PWR_PVDITConfig(ENABLE); 
PWR_PVDCmd(ENABLE);


while (1)
{
GPIO_TOGGLE(LED_BLUE_PORT, LED_BLUE_PIN);
delay_ms(300);

if (PWR_GetFlagStatus(PWR_FLAG_PVDOF)==RESET)
{
 GPIO_HIGH(LED_GREEN_PORT, LED_GREEN_PIN);
}
else
{
 GPIO_LOW(LED_GREEN_PORT, LED_GREEN_PIN); 
}
};  
}

Что можно сказать про библиотеки (специально решил писать все на них — попробовать)?
С одной стороны настройка удобнее (не надо помнить все нюансы) и код понятнее. С другой — пришлось копать справку к библиотеке по каждому чиху (понятное дело, что скоро само пройдет, но пока напрягает). Наверное дальше все статьи будут писаться в таком ключе — "описание работы на низком уровне; описание работы через библиотеку; код на базе библиотеки"

Насчет размера кода, генерируемого библиотекой — этот проект в «Release» версии с высоким уровнем оптимизации занял 559 байт, что весьма неплохо, учитывая размер флеша у 152с6 — 32кБ.

Под занавес, небольшое видео с мигающими лампочками:


(Эвакуировался на балкон: подальше из квартиры, где шум, пыль и ремонт)
  • +2
  • 25 сентября 2011, 16:10
  • dcoder
  • 1
Файлы в топике: PVD.zip

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

RSS свернуть / развернуть
Гм. Щупы у мультиметра не в лучшем состоянии) Хотя у меня есть одна пара еще более аццкого вида :)
0
  • avatar
  • Vga
  • 25 сентября 2011, 17:27
Да это старые щупы с пересажеными на них крокодилами. Надо бы новые такие найти…
0
Я тоже старые кроками оснастил. Но по ним этого не скажешь) По крайней мере — не в таком разрешении)
А они риальне старые и провод от шупа раз пять отваливался.
С одними из новых чуть хуже — у них изоляция говно и склонна лопаться. Так что там у штекеров аццкие многослойные конструкции из термоусадки)
0
  • avatar
  • Vga
  • 25 сентября 2011, 17:44
Вот тут

#pragma vector=TIM2_OVR_UIF_vector
__interrupt void pvd_int()

(вектор таймера?)
0
Точно. Скопипастил шаблон из проекта, а поправить забыл. Спасибо
0
Ну а как использовать его для сброса процессора. На подобии BODEN в AVR?
0
Нет, для сброса процессора там есть BOR. Его порог настраивается через option byte. По умолчанию включен на порог 1.8 Вольт
0
Собственно, я случайно наткнулся на вашу статью в поиске, спасибо за описание. А моя проблема с stm32, в основном теле опрашиваю регистр RTC(работает от Vbat), часы идут и вот когда снимаю питание кристалла, а по питанию его через стабилизатор стоит 2200мкф, время сбивается.
0
По сути — компаратор с Vcc (через делитель) на одном входе, и переключаемым опорным напряжением, на другом. Пороговое напряжение выбирается из 6 вариантов, кроме того можно подать его с какой-нибудь внешней схемы.
Скорее — наоборот. Компаратор работает всегда с одним и тем же порогом — Vrefint, а не другой вход подается через делители напряжение питания (0..6) или внешнее напряжение (7). Внеший вход позволяет мониторить «сырое» питание — до стабилизатора, предупреждая о скором его пропадании.
0
  • avatar
  • sgs
  • 10 ноября 2011, 09:21
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.