Сторожевой таймер в Xmega(Watchdog)

    Данная статья посвящена особенностям использования сторожевого таймера (Watchdog timer) в микропроцессорах Xmega.
    Сторожевой таймер (англ. Watchdog timer) – аппаратно реализованная схема контроля за зависанием системы. Представляет собой таймер, который периодически сбрасывается контролируемой системой. Если сброса не произошло в течение заданного интервала времени, происходит принудительная перезагрузка системы. В некоторых реализациях сторожевой таймер может посылать системе сигнал на перезагрузку («мягкая» перезагрузка), в других же — перезагрузка происходит аппаратно (замыкание сигнала Reset).
    Сторожевые таймеры используются для того, чтобы гарантировать восстановление системы после непредвиденных программных или аппаратных отказов. При корректном использовании сторожевого таймера, он в состоянии оценить отклонение от требуемого выполнения программы и реагировать сбросом центрального процессора. Сброс переводит центральный процессор в определенное и известное состояние, при котором может быть восстановлена нормальная работа системы.
    Семейство Xmega имеет очень четкий внутренний сторожевой таймер. Обычно, встроенные сторожевые таймеры используют в качестве источника тактирования часы центрального процессора, но сторожевой таймер Xmega имеет независимый от центрального процессора источник тактирования, что позволяет ему сохранять работоспособность при нарушении работы основных часов микропроцессора.
    Также сторожевой таймер Xmega неограничен работой только в «нормальном режиме», когда он должен быть сброшен до превышения определенного времени, существует «оконный режим», в котором сторожевой таймер может быть сброшен в пределах определенного интервала времени, если он сброшен слишком рано или слишком поздно будет запушен механизм перезагрузки системы (процессора).
    Принцип работы    Дадим определение нескольким важным терминам:
    Сторожевой таймер (англ. сокр. WDT) является периферийным устройством, который может быть настроен на сбрасывание системы при сбросе его слишком рано или слишком поздно, согласно настроенному периоду выдержки. Текущее значение таймера не может быть прочитано или записано, а может быть только сброшено.
    Сброс сторожевого таймера (WDT reset) – процесс обнуления значения сторожевого таймера. Сброс заставляет таймер опять начать счет с нуля и таким образом перезапустить период выдержки.
    Сбросом системы является сброс микроконтроллера AVR, при котором происходит сброс центрального процессора и регистров ввода-вывода в значения по умолчанию и перезапуск программы с адреса 0x0000 (или загрузочной секции). Сторожевой таймер может вызвать системный сброс по окончанию периода выдержки или по слишком раннему сбросу (в оконном режиме).
    Нормальный режим
    Сторожевой таймер может быть настроен на работу в нормальном режиме имеющий только один устанавливаемый период выдержки. Если сторожевой таймер не сброшен до окончания установленного периода выдержки будет произведен системный сброс. Работа сторожевого таймера в нормальном режиме показана на следующем рисунке:
    В течение открытого периода расположенного вдоль оси «Счетчика WDT» сторожевой таймер может быть сброшен в любое время до окончания периода выдержки (TOWDT).
    Оконный режим
    Когда сторожевой таймер работает в оконном режиме, он использует два периода выдержки, закрытый оконный период выдержки (TOWDTW) и нормальный период выдержки (TOWDT). Закрытый оконный период выдержки может быть величиной от 8мс до 8с и на его протяжении сторожевой таймер не может быть сброшен, если же сигнал сброс таймера пришел в этот период, то будет произведен системный сброс. Нормальный период выдержки сторожевого таймера также может быть величиной от 8мс до 8с и определяет продолжительность открытого периода, в течение которого сторожевой таймер может (и должен) быть сброшен. Открытый период всегда идет после закрытого периода, а общая длительность периода выдержки сторожевого таймера является суммой оконного и нормального периодов выдержки. Работа сторожевого таймера в оконном режиме проиллюстрирована на следующем рисунке:
    Часы таймера
    Сторожевой таймер тактируется от внутреннего RC-генератора ультранизкой мощности «ultra low power» (ULP) частотой 1 кГц. Этот генератор также может использоваться для тактирования таймера часов реального времени и цепи контроля за питанием. Генератор ULP будет запущен, если хотя бы один из этих модулей будет настроен на его использование. Включение дополнительных модулей использующих генератор ULP увеличивает текущее потребление несущественно.
    Важно знать, что часы сторожевого таймера не очень точные, вследствие того, что его генератор рассчитан на низкое потребление для возможности использования сторожевого таймера в применениях с использованием в качестве питания долгоживущих батарей. Задний фронт ULP генератора не точен (имеет медленный спад). Обычно точность часов сторожевого таймера +/-30%, более точная информация указана в документации на процессор. Такой разброс по точности означает, что процессоры одного типа могут иметь разные точности. При написании программного обеспечения использующего сторожевой таймер должно быть учтено, что процессоры могут иметь разную точность часов сторожевого таймера и гарантировать то, что установленные периоды выдержки будут корректны для всех устройств, а не только тех, что испытываются в лабораторных условиях в процессе разработки.
    Также нужно учитывать, что источник часов может изменяться при изменении температуры и питающего напряжения, хотя это изменение значительно меньше +/-30%, точную информацию об этом можно узнать в документации на используемый микропроцессор.
    Периоды выдержки
    Сторожевой таймер может быть настроен на широкий диапазон периода выдержки – от 8мс до 8с. Величина периода выдержки сторожевого таймера настраивается битовым полем PER в регистре управления сторожевым таймером CTRL, а величина оконного периода выдержки устанавливается битовым полем WPER в регистре управления окном сторожевого таймера WINCTRL.
    При изменении регистров CTRL или WINCTRL сторожевой таймер будет сброшен.
    Цифровое тактирование сторожевого таймера
    Сторожевой таймер использует часы отличные от часов центрального процессора и синхронизация между ними требует отдельного рассмотрения при использовании сторожевого таймера.
    Для настройки сторожевого таймера требуется 2-3 цикла часов: при записи настроек в регистры управления (CTRL и WINCTRL) изменения вступают в силу со следующего такта часов (по возрастающему фронту часов сторожевого таймера), т.е. между 2 и 3 миллисекундой, после того как конфигурация была записана. Это означает, что начальный период выдержки увеличивается на 3мс по сравнению с установленным, т.е. если установлена выдержка в 8 миллисекунд, то реальная будет 10-11мс. Это главным образом значимо при использовании оконного режима с короткими периодами выдержки. Данная особенность также актуальна для всех асинхронных таймеров работающих с синхронизацией между двумя источниками тактирования.
    Напомним, что сторожевой таймер сбрасывается при записи (изменении) значений в регистрах управления таймером.
    Другой важной временной характеристикой является время между вызовом инструкции на сброс сторожевого таймера и его фактическим сбросом, которое также подвергается синхронизации между используемыми часами – сторожевой таймер сбрасывается по третьему нарастающему фронту (на третий импульс) после непосредственного вызова инструкции сброса WDT, это 2-3мс. При использовании сторожевого таймера с периодом выдержки 8мс первый вызов инструкции сброс должен быть вызван через 5 мс после его включения. С учетом точности генератора ULP +/-30% вызов инструкции должен быть произведен через 3,5мс или раньше. Последующие вызовы инструкции должен генерироваться через 4,9мс или раньше (4,9мс = 8мс – 1мс неточности – 30% неточности генератора). Чем больше период выдержки, тем меньше влияние синхронизации. Наиболее четкого контроля за временем сброса требует использование оконного режима с короткими временами периодов выдержки.
    На следующем рисунке показан процесс цифрового тактирования сторожевого таймера:

    Если системный сброс генерируется сторожевым таймером, например, по окончанию периода выдержки, то он произойдет по переднему фронту часов сторожевого таймера. Это означает, что системный сброс происходит спустя 1мс после окончания периода выдержки сторожевого таймера. Как правило, данная особенность не является проблемой, но о ней полезно знать для измерения периода выдержки сторожевого таймера при контроле логического уровня сигнала на ножке. Лучшим способом определения фактической частоты часов сторожевого таймера является использование таймера часов реального времени Xmega, который также тактируется от генератора ULP.
    Все выше перечисленные условия относятся как нормальному, так и к оконному режимам сторожевого таймера
    Настройка и использование сторожевого таймера
    Сторожевой таймер может быть запущен и настроен двумя способами: 1) через настройку fuse-битов, которые загружаются процессором в процессе системного сброса; 2) включение и настройка в процессе выполнения программы, программной записью соответствующих настроек в регистры управления сторожевого таймера.
    Включение сторожевого таймера через fuse-биты
    Сторожевой таймер может инициализироваться автоматически в течение системного сброса, установкой соответствующих fuse-битов для нормального и оконного режимов работы. Fuse-биты определяют период выдержки сторожевого таймера, продолжительность закрытого периода в оконном режиме, а также могут настроить сторожевой таймер на запуск при включение процессора. Детальное описание fuse-битов, используемых для управления сторожевым таймером, находится в описании на микропроцессор.
    Отметим, что хотя настройки для оконного режима работы сторожевого таймера могут быть установлены через fuse-биты, но включить оконный режим через них невозможно. Он включается в процессе выполнения программы для гарантии корректного выбора необходимых времен оконного режима.
    Для обеспечения максимальной защищенности возможно установить блокирующий fuse-бит WDLOCK, который гарантирует, что сторожевой таймер не может быть отключен в процессе работы ни случайно, ни специально. Это может быть полезно в случае продолжительного сбоя системы, который может не допустить запуска сторожевого таймера в процессе выполнения программного кода.
    Процесс запуска сторожевого таймера через fuse-биты показан на следующем рисунке:
    Включение сторожевого таймера в процессе работы программы
    В некоторых приложениях может быть полезна возможность отключения сторожевого таймера для уменьшения потребляемой мощности в спящих режимах, например в применениях, где в качестве питания используются
    долгоживущие батареи. Сторожевой таймер можно включать и отключать, для того чтобы он был активен при работе центрального процессора, но отключен в режимах сна, хотя такие переключения могут уменьшить защищенность создаваемую сторожевым таймером. Однако, отметим, что существуют и другие модули (блок контроля за питанием и часы реального времени) использующие генератор ULP в спящих режимах увеличивающие ток потребления, по сравнению с которыми потребление сторожевого таймера не велико.
    Для включения сторожевого таймера в процессе работы программы или изменения периодов выдержки необходимо использовать регистр защиты от изменения настроек (CCP), который управляет доступом к определенным регистрам. После записи значения 0xD8 в регистр CCP сторожевой таймер может быть перенастроен в течение следующих четырех командных циклов. Во время этих четырех командных циклов глобальные прерывания автоматически отключатся для гарантии того, что последовательность действий не будет прервана прерыванием. Обратите внимание, что время перерыва задается в командных циклах, а не тактах часов, т.к. DMA передачи не привязаны к времени они не подсчитываются и как командные циклы – подсчет идет только команд центрального процессора.
    В течение четырех командных циклов после записи 0xD8 в CCP могут быть изменены контрольные регистры сторожевого таймера (CTRL и WINCTRL).
    Также отметим, что невозможно изменить настройки и работы сторожевого таймера, пока установлен fuse-бит WDLOCK, но можно включить/отключить оконный режим.
    Процесс запуска сторожевого таймера в процессе работы программы показан на следующем рисунке:
    Назначение применения сторожевого таймера
    Сторожевой таймер предназначен для восстановления работоспособности устройства, если произошел непредвиденный отказ системы, который не может быть преодолен программными или аппаратными средствами и приводит систему в неработоспособное состояние. Качественно настроенный сторожевой таймер в состояние произвести системный сброс, так что конечный пользователь его и не заметит.
    Основной рекомендацией по использованию сторожевого таймера является установка его сброса в основном цикле программы. Не устанавливайте сброс сторожевого таймера в процедурах обработки прерываний, если только они не проверяют флаги, последовательности выполнения частей программы. Если соблюдать эти простые правила, то ошибиться в использовании сторожевого таймера сложно.
    Оконный режим сторожевого таймера является более сложным, по сравнению с нормальным режимом, так как требует большего контроля за выбором времени сброса таймера. При использовании оконного режима, сброс сторожевого таймера должен находиться в основном цикле программы, и никак не в процедуре обработки прерываний, поскольку это уменьшит защиту по закрытому периоду. Закрытый период определяет минимальную продолжительность выполнения основного цикла (или его части), что может использоваться для определения случаев, когда часть когда основного цикла не была выполнена или случаев, когда произошел слишком ранний выход из вызванной функции. Примером может служить случай, когда сбой алгоритма или аппаратный сбой приводят к слишком быстрому выполнению операции. Например, ожидаемая продолжительность записи значения в EEPROM составляет 4 миллисекунды, но если она завершается через несколько микросекунд (обнаружен флаг ошибки), то сброс сторожевого таймера придет слишком рано. Другим примером является сбой при возврате стека или указателя стека, вызывающие неправленое выполнение программы.
    Другим случаем, когда оконный режим сторожевого таймера дает хорошую защиту, является случай, когда выполнение программы застревает в цикле, в котором инструкция сброса сторожевого таймера постоянно выполняется. Если сброс таймера будет происходить чаще, чем настроено, то сторожевой таймер определит отказ и перезапустит систему для восстановления работоспособности.
    Ну и как обычно, напоследок рабочий пример.
    Пример.
    Задача: Написать программу проверки работоспособности сторожевого таймера. Программа выдает меандр на какую-либо ножку порта, на которую можно повесить светодиод для индикации работы. Сторожевой таймер настраивается на определенную выдержку. Также на какую-либо ножку вешается кнопка, при нажатии на которую время выполнения программы существенно увеличивается, превышая установленную выдержку сторожевого таймера и тем самым, приводя к сбросу системы до выдачи меандра на светодиод.
    В качестве опорной частоты процессора возьмем частоту по умолчанию – 2 МГц. Для наглядности будем использовать два счетчика: 1) по таймеру настроенному на опорную частоту 1кГц; 2) в теле основного цикла с частотой выполнения программы. В качестве входной ножки, на которую вешается кнопка (джампер), будем использовать ножку 2 порта K. Также подключим два светодиода на выходы микропроцессора Xmega: первый будет отображать достижение максимума счетчика по таймеру и подсоединим его к ножке 4 порта К; второй будет отображать достижение максимума счетчика основного цикла и подсоединим его к ножке 5 порта К. Настроим сторожевой (Watchdog) таймер на нормальный режим и на срабатывание через 512 мс. Счетчик по таймеру настроим на повторение через каждые 400 мс (значительно меньше 500 мс, т.к. генератор сторожевого таймера не отличается точностью и может иметь существенный разброс). Счетчик в основном цикле примерно настроим на повторение через каждые 400 мс (при отпущенной кнопке) и примерно на 600 мс (при нажатой кнопке). Т.е. при отпущенной кнопке оба светодиода должны моргать примерно с одинаковой частотой - 5 раз в 2 секунды, а при нажатой кнопке: первый светодиод будет всегда отключен, так как сторожевой таймер должен сбрасывать систему раньше, чем основной счетчик досчитает до 600 мс; второй светодиод будет успевать включиться, т.к. счетчик по таймеру успевает досчитать значения соответствующие 400 мс, но сбрасываться будет раньше времени сбросом системы от сторожевого таймера.
    Код работающей программы для процессора Xmega128A1 имеет следующий вид:
#define ENABLE_BIT_DEFINITIONS // разрешение использования групповых битовых имен 
/* Объявление используемых библиотек */
#include <ioxm128a1.h>
#include <ina90.h>
unsigned int count=0; // объявление счетчика основного цикла
int count2=400; // объявление счетчика таймера
void main(void)
{
__disable_interrupt(); // Запрещение прерываний
CCP = 0xD8; // Снятие защиты от записи на 4 цикла
WDT.CTRL=WDT_PER_512CLK_gc| WDT_ENABLE_bm | WDT_CEN_bm; // Включение WDT в нормальном режиме, период выдержки 512мс
while ((WDT.STATUS & WDT_SYNCBUSY_bm) == WDT_SYNCBUSY_bm) {} // Ожидание синхронизации
PORTK.DIRSET = 0x30; // Настройка ножек 4 и 5 порта K как выходы
PORTK.PIN2CTRL = PORT_OPC_PULLUP_gc; // Установка подтянутого входа порта K ножки 2
TCC0.CTRLA=0x04; // N=8
TCC0.PER=250-1; // частота таймера 1кГц при системной частоте 2МГц
TCC0.INTCTRLA=1; // разрешение прерываний по таймеру c приоритетом low
PMIC.CTRL = 1; // приоритет прерываний уровня low
__enable_interrupt(); // разрешение прерываний
while(1) // основной бесконечный цикл
{
unsigned int temp; // объявление временной переменной
if (!(PORTK.IN & 0x04)) // если кнопка нажата, то
temp=40000; // установить максимум основного цикла равным примерно 600мс
else // иначе
temp=25600; // установить максимум основного цикла равным примерно 400мс
if (count>=temp) // если счетчик основного цикла достиг максимума,
{
count=0; // сброс счетчика основного цикла
PORTK.OUTTGL = 0x20; // инверсия светодиода 2
__watchdog_reset(); // сброс сторожевого таймера
}
else // иначе
count++; // инкрементация счетчика основного цикла
}
}
#pragma vector=TCC0_OVF_vect // обработка прерываний по переполнению таймера С0
__interrupt void irqTCC0_OVF_vect(void)
{
if (count2) // если счетчик таймера не достиг минимума, то
count2--; // уменьшение счетчика на 1
else // иначе
{
PORTK.OUTTGL = 0x10; // инверсия светодиода 1
count2=400; // установить максимум таймера равным примерно 400мс
}
}
    Blogger Comment
    Facebook Comment

0 коммент.:

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