Что такое сторожевой таймер

Сторожевой таймер в надежных встраиваемых системах

Как правило, WTD состоит из счетчика и тактирующего устройства. Значение счетчика по сигналам тактового устройства постоянно уменьшается. Когда оно достигает нуля, генерируется короткий импульс, который сбрасывает и перезапускает систему.

Приложению необходимо периодически, до срабатывания таймера, обновлять значение счетчика, иначе WTD вызовет перезагрузку системы. После обновления счетчика его значение вновь продолжит уменьшаться. Проще говоря, WDT постоянно «следит» за выполнением кода и перезагружает систему, если программное обеспечение зависает или больше не выполняет правильную последовательность кода. Перезагрузка значения WDT с помощью программного обеспечения называется “kicking the watchdog” (перезапуск сторожевого таймера).

Особенности разработки с применением сторожевых таймеров

Типы сторожевых таймеров

WDT могут быть разделены на две больших категории – внешние сторожевые таймеры (рисунок 1) и внутренние, или встроенные (рисунок 2). Подавляющее большинство современных микроконтроллеров имеют встроенные сторожевые таймеры. Производители также предлагают специализированные микросхемы сторожевых таймеров.

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

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймерЧто такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер
Рис. 1. Внешний сторожевой таймерРис. 2. Внутренний сторожевой таймер

Проблемы, возникающие при отсутствии сторожевого таймера

В 1994 году для наблюдения за Луной и астероидом 1620 Geo был запущен зонд «Клементина». После нескольких месяцев работы программный сбой привел к включению контрольного двигателя на 11 минут, что привело к большому расходу топлива и вращению аппарата со скоростью 80 об/мин. Управление было в конечном итоге восстановлено, но слишком поздно для успешного завершения миссии.

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

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

Системное программное обеспечение также не должно зацикливаться на длительный период. Общим решением является сброс системы, и в этом поможет сторожевой таймер.

Структура систем, использующих сторожевой таймер

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

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

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

Для надежной разработки внедрение сторожевого таймера является обязательным.

Период срабатывания сторожевого таймера

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

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

Очень короткие временные интервалы сторожевого таймера могут приводить к лишним перезапускам системы. Если система не критична по времени, интервал сброса лучше выбирать в пределах нескольких секунд.

Сторожевой таймер в однопоточном приложении

Обычно обновление/ перезапуск сторожевого таймера происходит в конце основного цикла, перед уходом на новый круг (рисунок 3).

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

Рис. 3. Типовая схема обновления сторожевого таймера в основном программном цикле приложения

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

К примеру, если длительность основного цикла составляет 500 мс, а максимальный интервал сторожевого таймера – 100 мс, то нет возможности перезапускать его в основном цикле. В данном случае можно настроить один из основных таймеров процессора/ микроконтроллера на срабатывание, к примеру, каждые 50 мс и определить флаг, показывающий, что выполнение программы идет штатно, который будет проверен в конце основного цикла.

Каждые 50 мс по срабатыванию основного таймера проверяется флаг состояния, инкрементируется счетчик. Обновление таймера происходит только в том случае, если система находится в известном состоянии. Если значение счетчика превысило десять (прошло более 500 мс), обработчик при следующем прерывании проверяет флаг состояния, и если он соответствует нормальному исполнению кода, то считается, что программа выполняется корректно. В противном случае выставляется состояние «неизвестное», обновления сторожевого таймера при следующем вызове не будет и система будет перезапущена по истечению интервала сторожевого таймера.

—————-CODE——————
ISR() //50ms free running
<
Count++;
If(Count > 10) //10x50ms
<
Count = 0;

If(State == ALIVE)
<
State = RESET;
>
else
<
State = UNKNOWN;
>
>

Не стоит доверять обновление сторожевого таймера, без проверки каких-либо условий, обработчику прерываний или отдельной задаче ОСРВ, так как в случае ошибки в основной ветке кода обработка прерываний или выполнение других задач ОСРВ может продолжиться, и условия срабатывания сторожевого таймера никогда не наступят. Такой подход не рекомендуется, так как нет гарантии, что работает основной код.

Сторожевой таймер в приложениях на базе ОСРВ

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

Рассмотрим подход, в котором существует слово статуса, и каждый бит этого слова ассоциируется с отдельной задачей. К примеру, в нашей системе запущены три задачи, и каждая из задач будет устанавливать отведенный ей бит в слове статуса в конце своего программного цикла.

Подход, представленный на рисунке 4, будет работать в том случае, если длительности циклов всех задач будут меньше и длительности периода сторожевого таймера, и периодичности срабатывания задачи сторожевого таймера. Однако в случае, если хотя бы одна из задач не укладывается в этот период по каким-либо причинам (переход в спящее состояние, ожидание события, обработка прерываний), даже при штатном исполнении сторожевая задача, обнаружив неустановленный бит, не обновит таймер, и произойдет перезапуск всей системы.

Более предпочтительным решением является использование метода передачи сообщений, когда каждая задача блокируется в очереди сообщений (рисунок 5). Задача сторожевого таймера будет отправлять сообщения всем задачам и переходить в спящий режим на определенный промежуток времени (меньший, чем период тайм-аута таймера).

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

Рис. 4. Реализация сторожевого таймера в ОСРВ, вариант 1

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

Рис. 5. Реализация сторожевого таймера в ОСРВ, вариант 2

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

Источник

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

А сторожевой таймер (иногда называемый компьютер работает нормально или же КС таймер, или просто сторожевая собака) является электронным или программным таймер который используется для обнаружения и устранения неисправностей компьютера. Во время нормальной работы компьютер регулярно сбрасывает сторожевой таймер, чтобы предотвратить его истечение или «тайм-аут». Если из-за аппаратного сбоя или программной ошибки компьютеру не удается сбросить сторожевой таймер, таймер истечет и выдаст сигнал тайм-аута. Сигнал тайм-аута используется для запуска корректирующих действий. Корректирующие действия обычно включают перевод компьютерной системы в безопасное состояние и восстановление нормальной работы системы.

Сторожевые таймеры обычно находятся в встроенные системы и другое оборудование с компьютерным управлением, где люди не могут легко получить доступ к оборудованию или не могут своевременно реагировать на неисправности. В таких системах компьютер не может зависеть от человека, который вызовет перезагрузку, если он висит; он должен быть самостоятельным. Например, удаленные встроенные системы, такие как космические зонды физически недоступны для людей-операторов; они могут стать навсегда отключенными, если не смогут самостоятельно восстановиться после сбоев. В подобных случаях обычно используется сторожевой таймер. Сторожевые таймеры также могут использоваться при запуске ненадежного кода в песочница, чтобы ограничить процессорное время, доступное коду и, таким образом, предотвратить некоторые типы атаки отказа в обслуживании. [1]

Сторожевые таймеры также используются в операционных системах, где требуется выполнение определенных высокоприоритетных операций в определенный интервал времени. Если таймер истекает до завершения операции, тогда ОС реагирует на прерывание таймера, записывая данные об ошибке и завершая операцию. Система может иметь оба типа сторожевого таймера.

Содержание

Архитектура и работа

Перезапуск сторожевого таймера

На компьютерах, которые работают операционные системы, сброс сторожевого таймера обычно вызывается через драйвер устройства. Например, в Операционная система Linux, а пространство пользователя программа запускает сторожевой таймер, взаимодействуя с драйвером сторожевого устройства, обычно записывая нулевой символ в / dev / сторожевой таймер. Драйвер устройства, который служит для абстрагирования сторожевого устройства от программ пользовательского пространства, также используется для настройки периода ожидания и запуска и остановки таймера.

Одноступенчатый сторожевой таймер

Сторожевые таймеры бывают разных конфигураций, и многие из них позволяют изменять их. Микроконтроллеры часто включают встроенный сторожевой таймер. В других компьютерах сторожевой таймер может находиться в соседнем чипе, который подключается непосредственно к ЦПУ, или он может быть расположен на внешнем карта расширения в корпусе компьютера. Сторожевой таймер и ЦП могут иметь общий тактовый сигнал, как показано на блок-схеме ниже, или они могут иметь независимые тактовые сигналы.

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

Многоступенчатый сторожевой таймер

Иногда два или более таймера соединяются каскадом, чтобы сформировать многоступенчатый сторожевой таймер, где каждый таймер называется этап таймера, или просто сцена. Например, на блок-схеме ниже показан трехступенчатый сторожевой таймер. В многоступенчатом сторожевом таймере процессор запускает только первый этап. По истечении времени ожидания первого этапа инициируется корректирующее действие и запускается следующий этап каскада. По истечении времени ожидания каждого последующего этапа запускается корректирующее действие и начинается следующий этап. По истечении времени ожидания последнего этапа инициируется корректирующее действие, но никакие другие этапы не запускаются, поскольку достигнут конец каскада. Как правило, одноступенчатые сторожевые таймеры используются для простого перезапуска компьютера, тогда как многоступенчатые сторожевые таймеры последовательно запускают серию корректирующих действий, причем последний этап запускает перезагрузку компьютера. [3]

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

Временные интервалы

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

Корректирующие действия

Сторожевой таймер может инициировать любой из нескольких типов корректирующих действий, в том числе: маскируемое прерывание, немаскируемое прерывание, сброс процессора, безотказный активация состояния, включение и выключение питания или их комбинации. В зависимости от его архитектуры тип корректирующего действия или действий, которые может запускать сторожевой таймер, может быть фиксированным или программируемым. Некоторым компьютерам (например, совместимым с ПК) требуется импульсный сигнал, чтобы вызвать сброс процессора. В таких случаях сторожевой таймер обычно запускает сброс процессора, активизируя внутренний или внешний генератор импульсов, который, в свою очередь, создает необходимые импульсы сброса. [3]

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

Что такое сторожевой таймер. Смотреть фото Что такое сторожевой таймер. Смотреть картинку Что такое сторожевой таймер. Картинка про Что такое сторожевой таймер. Фото Что такое сторожевой таймер

Например, на приведенной выше диаграмме показана вероятная конфигурация двухступенчатого сторожевого таймера. Во время нормальной работы компьютер регулярно запускает Stage1 для предотвращения тайм-аута. Если компьютеру не удается запустить Stage1 (например, из-за аппаратного сбоя или ошибки программирования), Stage1 рано или поздно истечет время ожидания. Это событие запустит таймер Stage2 и одновременно уведомит компьютер (посредством немаскируемого прерывания) о неизбежности сброса. Пока не истечет время ожидания Stage2, компьютер может попытаться записать информацию о состоянии, отладочную информацию или и то, и другое. Компьютер будет перезагружен по истечении времени ожидания Этапа 2.

Обнаружение неисправности

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

Например, в случае операционной системы Linux сторожевой таймер пользовательского пространства демон может просто периодически запускать сторожевой таймер без выполнения каких-либо тестов. Пока демон работает нормально, система будет защищена от серьезных сбоев системы, таких как паника ядра. Для обнаружения менее серьезных неисправностей демон [4] может быть настроен для выполнения тестов, охватывающих доступность ресурсов (например, достаточное объем памяти и файловые ручки, разумное время ЦП), свидетельства ожидаемой активности процесса (например, запущены системные демоны, присутствуют или обновляются определенные файлы), перегрев и сетевая активность, а также могут быть запущены специфичные для системы тестовые скрипты или программы. [5]

Источник

5.4 Сторожевой таймер

Данная статья является наброском к главе «5.4 Сторожевой таймер» книги «Отказоустойчивое ПО для МК».

Определение

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

Также многие WDT могут работать в оконном режиме, когда сигнал от программы на обнуление WDT не допускается раньше какого-то времени. Т.е. он не должен приходить слишком рано или слишком поздно. Такая функция может оказаться полезной для более быстрого реагирования на некоторые виды сбоя. Например, если функция обнуления WDT вызывается раньше времени, то это говорит о том, что какие-то функции отработали быстрее, чем ожидалось, что может свидетельствовать о наличии сбоя. Из такого режима нужно выйти как можно быстрее, не дожидаясь переполнения WDT (т.е. не давая программе еще какое-то время работать во внештатном режиме). Оконные WDT удобно применять в тех случаях, когда нет возможности контролировать время выполнения участков кода с помощью аппаратного таймера.

Типы WDT

Внутренний WDT

Встроенный в МК сторожевой таймер является самым ненадежным из перечисленных и на него можно полагаться только в малоответственных системах. Есть две причины:

Стоит добавить, что некоторые микроконтроллеры допускают тактирование внутреннего WDT от системного генератора, что делает его неэффективным при срыве генерации или при случайном входе в Sleep-режим.

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

Внешний WDT в виде специализированной микросхемы

В зависимости от задач, которые мы хотим возложить на WDT, помимо его основной функции, мы можем выбирать ту или иную микросхему. Для управления WDT в составе такой микросхемы нам понадобится один вывод контроллера, настроенный на выход, для генерации сигналов обнуления WDT (в случае контроля выхода WDO потребуется еще один вывод МК, настроенный на вход).

Также при выборе микросхемы супервизора следует обращать внимание на следующие параметры:

Ниже приведены примеры микросхем-супервизоров, в составе которых имеется WDT (это краткий список, на самом деле таких микросхем великое множество):

TODO: дополнить и разъяснить

Внешний WDT в виде устройства

Отдельное устройство разрабатывается индивидуально с учетом особенностей конкретного устройства, используемого в нем микроконтроллера и конкретной программы. Сердцем такого устройства может быть маленький, например, 8-разрядный микроконтроллер (чаще OTP, например, PIC12CE518), который, помимо стандартного набора функций WDT, может иметь ряд дополнительных возможностей. Т.е. преимущества таких WDT в расширенном функционале и гибкости настройки.

Недостатками таких WDT являются габариты, а также то, что программа в маленьком МК должна соответствовать всем требованиям безопасности (начиная с самодиагностики и заканчивая контролем собственного внутреннего WDT), а также требует тщательнейшей отладки. Кроме того, сам микроконтроллер, используемый в качестве WDT, также подвержен всем видам сбоев, вызванных помехами. Но это компенсируется, во-первых, тем, что такие контроллеры выполнены по более грубой технологии, чем тот, которым они будут управлять, следовательно, они помехам подвержены гораздо меньше; во-вторых, есть возможность организовать «круговую поруку», когда маленький МК следит за большим, а большой следит за маленьким, что во много раз повышает вероятность самовосстановления работоспособности системы после сбоя.

Но построение схем-мониторов (не называю их WDT, т.к. функционал может быть гораздо шире простого счетчика) дает массу дополнительных возможностей, таких как:

К WDT этого типа можно также отнести одновибраторы, собранные на дискретных компонентах (иногда с использованием компараторов). Такие WDT наименее всего подвержены помехам, но они требуют много места на плате, не очень экономичны в энергопотреблении и более сложны в настройке и отладке.

Предпосылки к использованию

Как описано в предыдущем параграфе, все ошибки и сбои программы, возникающие во время ее работы, должны по возможности отслеживаться в ходе ее выполнения средствами самой программы. При обнаружении некорректного ее поведения следует делать анализ состояния программы с целью определить критичность сбоя и, если это возможно, принять адекватные меры по восстановлению работоспособности программы. WDT является последним рубежом при обеспечении отказоустойчивости ПО, он генерирует сигнал сброса в том случае, если средствами программы обнаружить сбой не удалось, или если программа попала в непредусмотренное зацикливание. Причинами такого поведения программы могут быть несколько факторов:

(Детально о причинах отказов ПО см. «2. Причины и последствия сбоев»)

Следует обратить внимание, что многие факторы не зависят ни от программистов, ни от схемотехников, ни от ОТК.

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

Но, во-первых, средствами программы всего проверить и перепроверить нельзя. И ограничения здесь не только в памяти, используемой для тестов, и времени, которое тесты отнимут, но и в том, что сами тесты, являясь частью программы, нужно бы проверять. А потом проверять и эти проверщики и т.д. Поэтому run-time тесты всегда неполные. Во-вторых, существуют непредвиденные сбои, при которых программный счетчик может прыгнуть в такую точку программы, в которой при текущем состоянии ячеек RAM-памяти и текущих настройках периферии, можно задержаться очень надолго. Например, сбоем программного счетчика, программа попала в код передачи байта в программной реализации интерфейса SPI:

На момент сбоя в ячейке памяти, где располагается переменная i, могло находиться любое значение, и безобидный цикл на 8 проходов может превратиться в цикл на 50000 проходов. В общем случае от подобных сбоев может спасти только WDT. В предыдущем параграфе (5.3 run-time контроль) было сказано о контроле стека и сигнатурах, которые могли бы сигнализировать о том, что что-то идет не так, но подобные тесты, во-первых, нецелесообразно применять во всех функциях без исключения, а во-вторых, при большом значении числа в ячейках памяти, занятых переменной i, WDT может успеть переполниться раньше, чем программа дойдет до проверок в конце функции.

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

Также повлиять на качественное выполнение какого-либо этапа разработки могут факторы организационного характера: над программой трудятся несколько человек, каждый из которых может по-своему интерпретировать какие-либо моменты, описанные в ТЗ, или по-своему додумать то, что в ТЗ не указано явно; программа или ее часть может быть поручена программисту, не имеющему достаточной квалификации или достаточного опыта для качественной реализации. Не следует забывать о факторе времени, выделенного на разработку. Программы, имеющие большое количество состояний, режимов работы и параллельных процессов, не могут быть протестированы целиком, т.к. время тестирования может превысить экономически целесообразные сроки выпуска устройства; поэтому к конечному потребителю программа может попасть, грубо говоря, недоотлаженной. Это не означает, что она будет сбоить и виснуть на каждом шагу, просто при совокупности внештатных ситуаций и стечении каких-то обстоятельств, она может зависнуть.

Как уже было сказано, нельзя исключать инструментальные ошибки, т.е. ошибки компиляторов, программаторов, наконец, самих микроконтроллеров. Они составляют лишь малую толику от ошибок, допускаемых самими разработчиками, но, тем не менее, имеют место быть.

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

Порядок обнуления WDT

Примечание: в данном параграфе применяюся вызовы псевдо-функций wdt_clear() и soft_reset().

Что такое порядок обнуления WDT

Умение программиста создавать набор контрольных точек, способных заметить наибольшее число отклонений в поведении программы, акцентируя внимание на ответственных участках, во многом определяет насколько WDT окажется полезным в обнаружении сбоя для конкретной программы.

Довольно часто можно встретить такой подход, при котором счетчик WDT безусловно обнуляется в главном цикле программы, в прерывании по таймеру, возникающему раз в миллисекунду, или несколько раз в программе с интервалом в 5-10 инструкций (или операторов). Другими словами, программист делает все, чтобы сторожевой таймер не успел переполниться ни при каких условиях. Доходит даже до комичного кода:

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

Периодическое обнуление с проверкой флагов

Часто можно встретить такую рекомендацию (в литературе, в интернет-статьях, на технических форумах): основные функции программы должны после своего выполнения устанавливать флажок, подтверждающий, что функция выполнена; в главный цикл в main() или в прерывание добавляется код, который проверяет, что все нужные функции отработали, и только после этого обнуляет WDT.

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

В главном цикле main() (или в обработчике периодического перрывания) вставляется код проверки флагов:

Каждая критическая функция сбрасывает соответствующий ей бит, если она выполнилась корректно, например:

Примечание: флаги можно заводить не только для тех функций, которые вызываются из основного цикла main(), но иногда и для вложенных функций и даже для обработчиков прерываний. Коду проверки важно знать, что ответственные участки кода были выполнены.

Для простых приложений такой подход можно считать очень удачным, т.к. он имеет очевидные преимущества:

Однако он имеет и свои недостатки:

Обнуление с контролем отдельных функций

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

Метод является комбинацией с одним из видов run-time проверок. Если мы случайно пропускаем выполнение какой-либо функции (например из-за сбоя PC), то run-time проверка сигнатуры функции вызовет обработчик soft_reset(). Вне комбинации с run-time проверками этот метод не только малоэффективен, но даже опасен, т.к. если убрать во всех условиях ветку else, то даже после обнаружения сбоя (т.е. сбой не только произошел, но уже замечен) мы позволим программе выполнить еще несколько функций, уже находясь во внештатном режиме.

Т.е. данный метод является дополнением к run-time проверкам. На мой взгляд, он не очень эффективен, т.к.:

Однако он имеет два преимущества:

Периодическое обнуление с контролем состояния

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

Метод хорош тем, что позволяет выполнять различные проверки для различных режимов работы, т.е. позволяет контролировать правильность работы программы в целом (например, для диктофона не могут быть одновременно активны режимы записи и воспроизведения; автосигнализация не может запоминать новые серийные номера брелоков, если она не в режиме программирования и т.п.). В зависимости от текущего режима работы и выпоняемых в данный момент действий, порядок и набор проверок может меняться. К примеру, электрическая плита может работать в 3х режимах: режим сна, режим готовки и режим настройки. В каждом из них выполняются разные наборы функций, которые было бы неудобно контролировать скопом, поэтому для контроля каждого набора создается своя ветвь проверок в зависимости от режима.

Этот метод лишен основных недостатков двух предыдущих методов обнуления (с контролем флагов и контролем функций), а именно:

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

Однако, при своей универсальности этот метод не лишен недостатков:

Комбинированный метод

Иногда бывает удобно выхватить из каждого метода что-нибудь одно и использовать в комбинации с другим. Например, может понадобится написать функцию (скажем, автомат состояний), для которой сам алгоритм проверки состояний превратится в сложный ветвящийся комплекс операторов ветвлений и циклов. В таком случае может оказаться целесообразным не учитывать эту функцию в проверках внутри прерывания, а воспользоваться для нее методом обнуления с контролем функций или обнулением в цикле, т.е. в критических узлах функции расставить вызовы wdt_clear() (обязательно с проверкой текущего состояния). Это может усложнить анализ причин сброса, но иногда намного упрощает проработку алгоритма контроля выполнения программы.

Выбор интервала

При проектировании алгоритма обнуления WDT перед прораммистом встает вопрос выбора интревала WDT. Диапазон временных интервалов, проедоставляемый сторожевыми таймерами разных производителей, а также внутренним WDT, довольно широк: от единиц миллисекунд до единиц секунд (для внешних) или до нескольких суток (для втутренних). Интревал следует выбирать исходя из возлагаемых на WDT задач. Например, если мы планируем использовать WDT только для вывода МК из зависания, то редко могут понадобиться интервалы длиннее секунды-двух. Если же WDT будет использован для периодической активации контроллера, работающего в режиме пониженного энергопотребления, то тут, в зависимости от конкретной задачи, могут быть уместны интервалы в несколько часов или даже суток. В некоторых случаях целесообразно изменять интервал в ходе работы: например, его можно делать короче при выполнении ответственных функций или, наоборот, делать длиннее при переходе в режим пониженного энергопотребления.

Максимальная скорость реакции

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

Время выполнения проверок

Если программа является многопоточным приложением, многие процессы в которой живут большей частью собственной жизнью, то код проверок правильности состояния программы может оказаться сложным и выполняться довольно длительное время (в худшем случае может достигать десятков и сотен микросекунд). Становится очевидным, что если делать эти проверки сравнительно часто, то снизится эффективность самой программы. И не только из-за того, что 1% или 10% времени будет уходить на проверки, а еще и из-за того, что проверка состояния программы нарушает время ее реакции на какое-либо событие (особенно, если проверка находится в обработчике прерывания высокого уровня).

Критические участки кода

Программа может содержать участки кода, критичные к выполнению с точностью до такта, где инструкции для обнуления счетчика сторожеваого таймера будет просто некуда втиснуть. Сами инструкции обнуления вставить, возможно, удастся, но на код проверки правильности состояния программы может уже не остаться места, а без этого кода WDT может сослужить плохую службу (мы уже говорили о зависании в цикле с безусловным обнулением WDT). Таким кодом может оказаться, например, обработка какого-то внешнего синала, требующая точной выборки по времени. Проблема может быть частично решена применением DMA-модуля, если он есть. Но в общем случае надо учитывать наличие таких фрагментов кода при выборе интервала обнуления WDT.

Также стоит отметить, что некоторые контроллеры имеют возможность переключаться на резервный генератор при срыве генерации основного. Обычно резервный генератор имеет частоту на два-три порядка ниже частоты основного генератора (часто 32768 Гц). Обычно при переходе на резервный генератор генерируется немаскируемое прерывание, которое позволяет нам выполнить код по переводу устройства в резервный режим перед выполнением сброса. Но следует учесть, что этот код будет выполняться в сотни или тысячи раз медленнее, чем при тактировании от основного генератора, а тактирование сторожевого таймера при этом останется без изменений. И при неправильном выборе интервала сторожевого таймера или при неучете особенностей выполнения кода при тактировании от резервного генератора может получиться ситуация, в которой счетчик WDT успеет переполниться до того, как будут выполнены все действия по подготовке к сбросу. Т.е. в обработчике немаскируемого прерывания, возникающего при срыве генерации основного генератора, следует применять обнуление WDT по особым правилам. Разумеется, в таком случае контролировать правильность программы уже не имеет смысла, но кое-какие проверки перед обнулением WDT выполнять, скорее всего, придется. В данном случае можно применять метод обнуления с контролем отдельных функций.

Работа с библиотечными функциями

Отдельно стоит вопрос порядка обнуления сторожевого таймера, когда в программе используются библиотеки сторонних производителей. Сами библиотечные функции никогда не производят обнуление WDT, с другой стороны в общем случае неизвестно, сколько времени может потребоваться на выполнение какой-либо библиотечной функции. Простая строка:

может выполняться многие тысячи тактов, и даже обрамление ее вызовами wdt_clear():

не всегда может спасти от переполнения WDT. Выхода здесь два:

Обнуление в прерывании с контролем состояния намного лучше подходит для решения этой задачи. Такой подход позволяет нам учесть длительное время выполнения быблиотечной функции, не увеличивая при этом интервал самого сторожевого таймера. Для этого нужно всего лишь завести глобальную переменную, в которую перед вызовом библиотечной функции можно записывать предполагаемое время ее выполнения с каким угодно запасом. А в обработчике прерывания к коду проверок состояния программы добавить обработку этой переменной.

Перед вызовом библиотечных функций, время выполнения которых вывает сомнения, переменная g_WDT_Library.nCounter устанавливается в соответствии с ожидаемым временем выполнения (это удобно организовать в виде функции, т.к. могут потребоваться действия для обеспечения атомарного доступа к счетчику):

Работа в программе под управлением RTOS

Ввиду этих сложностей обычно ограничиваются построением простых индивидуальных тестов с контролем состояний для каждой активной задачи и выполняют обнуление при успешном прохождении их всех. Т.е. своего рода надстройка над этими тестами в виде обнуления с проверкой флагов. Причем в случае с RTOS эти проверки можно делать только в прерывании высокого приоритета (выше системного). Все более детальные проверки лучше реализовывать в виде run-time тестов. Это, во-первых, очень разгрузит код проверки условий обнуления WDT, а во-вторых, как уже было сказано, что сбой всегда предпочтительнее заметить на программном уровне, чтобы иметь возможность попытаться восстановить работоспособность или, в крайнем случае, произвести сброс безопасно, предварительно переведя все внешнее оборудование в безопасный режим. А сторожевому таймеру оставить функцию сброса только в самых критических ситуациях.

Но, даже реализуя проверки по упрощенной схеме, не стоит забывать о некоторых особенностях, превносимых RTOS:

Тестирование WDT при включении питания

В особо ответственных системах WDT как контролирующий узел обязательно должен быть протестирован (иначе полагаться на него нельзя). Такие проверки предписывают делать европейский стандарт IEC 60730 (Annex H 11.12.7 п. 8) или американский стандарт UL1998 (A2.1 п.8). В зависимости от условий работы тестирование может производиться единожды при включении питания или с каким-то периодом, но не нарушая при этом целостность выполнения программы (т.е. в случае периодического тестирования перед проведением теста все внешнее оборудование должно быть переведено в безопасный режим, сохранены в энергонезависимую память данные, которые необходимо восстановить после перезагрузки.

Более детально тестирование WDT описано в «5.2 Самодиагностика», здесь повторю только основные принципы проверки:

Поведение программы при сбросе от WDT

Основной параграф, описывающий поведение программы при сбросе, это «5.5 Что делать при обнаружении сбоя». Здесь опишу только основные моменты, касающиеся сброса контроллера, вызванного переполнением WDT.

Все действия делятся на два этапа:

Протоколирование

Установить причины сброса, вызванного переполнением WDT, программными средствами довольно затруднительно. Даже если мы проанаизируем контрольные переменные в памяти (такие переменные должны быть размещены в сегментах RAM, не подвергающихся начальной инициализации или обнулению; для этого в разных компиляторах есть специальные директивы), то в лучшем случае получим только последствия сбоя, т.е. несоответствие значений этих переменных предполагаемым, а саму причину таким способом не установить. Кроме того, все эти переменные могут содержать достоверные значения, т.к. сбой мог произойти из-за срыва генерации, или из-за изменения значения программного счетчика, или из-за изменения триггеров самого WDT (об этом ниже).

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

Какие данные нужно сохранять:

Чем больше данных мы сохраним, тем больше возможностей установить причину сбоя и, если это возможно, устранить ее.

Источник

Добавить комментарий

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