|
Информационный портал технической поддержки Центра проектирования интегральных микросхем |
Уровень ULIMIT.UCCMAX детектора питания Power микроконтроллера 1986ВЕ8Т выставляется некорректно.
Проблема заключается в следующем: при напряжении питания на демонстрационной плате Ucc = 3,3В сброс флага PVDP должен происходить при выставлении UCCMAX = 0хВ, что соответствует порогу 3,4В, но сброс PVDP происходит только при UCCMAX = 0хС, то есть, при LevelPVD = 3,6В. При этом заявленная точность срабатывания детектора питания составляет 100мВ.
Выяснилось, что такое неточное выставление порога в UCCMAX происходит, только если в UCCMAX ранее был выставлен более низкий порог. Если UCCMAX содержал более высокое значение, то выставление порога происходит корректно, то есть, детектор питания зафиксирует событие Ucc > Ulim при значении UCCMAX = 0хВ (3,4В).
Термином Ulim далее будет называться уровень напряжения (порог), который задается параметром UCCMAX в регистре ULIMIT. Это напряжение Ulim сравнивается с Ucc и по результатам сравнения выставляется флага PVDP в регистре STAT.
Более наглядно выставление флага PVDP при сравнении Ucc (3,3В) c последовательно изменяемым значением UCCMAX, а следовательно и порогом Ulim, представлено в таблицах ниже:
Таблица 1 - Выставление флага PVDP в зависимости от увеличения UCCMAX
| Увеличиваем UCCMAX | 0xA | 0xB | 0xC |
|---|---|---|---|
| Ulim, В | 3,2 | 3,4 | 3,6 |
| Флаг STAT.PVDP | 1 | 1 | 0 |
| Уменьшаем UCCMAX | 0xС | 0xB | 0xA |
|---|---|---|---|
| Ulim, В | 3,6 | 3,4 | 3,2 |
| Флаг STAT.PVDP | 0 | 0 | 1 |
В итоге, поскольку понижение уровня дает верное поведение PVDP, можно попробовать задать упреждающее большее значение UCCMAX при задании Ulim следующим упрощённым кодом:
void SetLevel(uint32_t pvdLevel) { if (pvdLevel < 0x1F) PWR->ULIMIT = pvdLevel + 1; PWR->ULIMIT = pvdLevel; } Фрагмент кода 1
Это позволило выставить уровень сравнения в 3.4В, при этом флаг сбросился (STAT.PVDP = 0). Присвоение повышенного значения (pvdLevel + 1) форсирует выставление порога Ulim, цепь зарядки стартует активней, поскольку разница между текущим значением и следующим больше (аналогия с отрицательной обратной связью). Присвоение второго, правильного значения pvdLevel, выставляет порог Ulim в точно заданное значение.
В случае выставления более низкого порога, предлагаемая функция искажений не вносит, то есть при понижении UCCMAX порог выставляется также точно.
Резюме: упрощенный код, написанный выше, исправляет первую таблицу. Теперь уровень Ulim выставляется правильно, флаг PVDP отрабатывает корректно.
Таблица 3 - Выставление флага PVDP в зависимости от увеличения UCCMAX с учётом добавочного кода
| Увеличиваем UCCMAX | 0xA | 0xB | 0xC |
|---|---|---|---|
| Ожидаемый Порог, В | 3,2 | 3,4 | 3,6 |
| Флаг STAT.PVDP | 1 | 0 | 0 |
Вторая таблица изначально верна и сохраняет свою актуальность.
Проект демонстрирующий выставление порога представлен внизу, после статьи, раздел "Файлы для скачивания".
В примере стартовый уровень Ulim заведомо задается больше Ucc - Ulim > Ucc. Далее Ulim в цикле уменьшается до значения, при котором зафиксируется флаг PVDP, то есть устанавливается ситуация Ucc > Ulim. Этот уровень сохраняется в переменной pvdLevelUccFall и далее используется для детектирования падения напряжения - для этого включается инверсия флага PVDP.
В основном цикле выставляется условие возникновения прерывания UCCMAX = pvdLevelUccFall + 1, что вызывает прерывание от блока Power. Чтобы прерывание не возникало снова и снова, порог сбрасывается к исходному состоянию UCCMAX = pvdLevelUccFall. Все это повторяется по циклу.
Для наглядности исполнения мигает светодиод, если алгоритм отрабатывает верно.
Если не использовать дополненный код с форсированным выставлением UCCMAX, то для возникновения прерывания по PVDP необходимо уровень задавать на +1 больше, то есть в основном цикле вызывается UCCMAX = pvdLevelUccFall + 2. Пояснения следующие: pvdLevelUccFall - это максимальный уровень Ulim, при котором прерывание не генерируется (Ucc > pvdLevelUccFall). Следующий уровень уже превышает Ucc и ведет к формированию прерывания Ucc < Ulim.
Использование варианта с форсированным выставлением UCCMAX включается определением USE_PVD_HACK.
Основная часть кода представлена ниже:
#define TO_ULIM_PVD_LEVEL(Vx10) (((Vx10) - 12) / 2)
#define PVD_LEVEL_MIN TO_ULIM_PVD_LEVEL(28) // Uref = 2.8V
#define PVD_LEVEL_MAX TO_ULIM_PVD_LEVEL(38) // Uref = 3.8V
#define USE_PVD_HACK
#define LED_VD7 PORT_Pin_16
int main()
{
POR_disable();
// Clock
CLKCTRL_DeInit();
CLKCTRL_HSEconfig(CLKCTRL_HSE0_CLK_ON);
while(CLKCTRL_HSEstatus(CLKCTRL_HSEn_STAT_HSE0_RDY) != SUCCESS){}
CLKCTRL_MAX_CLKSelection(CLKCTRL_MAX_CLK_HSE0div1);
// Индикация
LED_Init();
// 1 - PVD Init, Uref выставляем в заведомо > Ucc
PVD_Init(PVD_LEVEL_MAX, WAIT_PVD_LEVEL_TICKS);
// 2 - Понижаем Uref, пока не появится флаг PVDP - (Uref < Ucc)
// Это значение и будет порогом срабатывания при просадке питания
pvdLevelUccFall = PVD_SetLevelOfUccFall(PVD_LEVEL_MAX, PVD_LEVEL_MIN, PVDP_CHECK_COUNT, WAIT_PVD_LEVEL_TICKS);
// 3 - Инверсия флага PVDP - теперь прерывания будут срабатывать по (Ucc < Uref)
PWR->CNTR2 = 1;
PWR->STAT = 1;
// 4 - Включение прерывания по Ucc < Uref
NVIC_EnableIRQ(PVD_IF_IRQn);
PWR->CNTR1 = 1;
// 5 - Ожидание прерывания
while (1)
{
// Индикация
PORT_SetBits(PORTC, LED_VD7);
Delay(LED_PERIOD);
// Генерация прерывания по Ucc < Uref
#ifdef USE_PVD_HACK
PVD_SetLevel(pvdLevelUccFall + 1, WAIT_PVD_LEVEL_TICKS);
#else
// Выставляется неточно, поэтому ставится с запасом.
// При +1 прерывание не возникает.
PVD_SetLevel(pvdLevelUccFall + 2, WAIT_PVD_LEVEL_TICKS);
#endif
Delay(LED_PERIOD);
}
}
void PVD_IF_Handler(void)
{
// Сброс в Ucc > Uref
if (pvdLevelUccFall != PWR->ULIMIT)
{
PVD_SetLevel(pvdLevelUccFall, 0);
// Индикация на светодиод
PORT_ResetBits(PORTC, LED_VD7);
}
PWR->STAT = 1;
}
| Сайт: | https://support.milandr.ru |
| E-mail: | support@milandr.ru |
| Телефон: | +7 495 221-13-55 |