Watchdog timer что это

AVR Урок 53. Watchdog Timer (WDT). Часть 1

Уже более года мною не публиковалось уроков по контроллерам AVR. На это были различного рода причины.

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

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

В-третьих, с выходом более современных контроллеров интерес к данным контроллерам упал, хоть и незначительно, но всё же это есть.

Несмотря на это, я всё же, взвесив все «за» и «против», всё же решил ещё раз попытать счастья и выложить пару уроков (пока пару, а там посмотрим, как дело пойдёт) по данным микроконтроллерам.

Что же всё-таки сподвигло меня на данный шаг?

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

Во-вторых, новый хозяин данного семейства контроллеров Microchip, включил эти контроллеры в свою среду разработки MPLAB X, что позволит нам теперь обойтись сразу на два семейства одной средой разработки.

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

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

Вот и настало время наконец-то восполнить данный пробел.

Watchdog Timer (WDT) – это сторожевой таймер (а если перевести дословно, «сторожевой пёс»), который представляет собой аппаратно-реализованную схему контроля над зависанием системы. Это таймер, который периодически сбрасывается контролируемой системой. Если вдруг сброса не произошло за определённый интервал времени после предыдущего сброса данного таймера, то происходит принудительная перезагрузка системы (в нашем случае микроконтроллера).

В каких конкретных случаях мы можем применить данный таймер?

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

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

При работе с таймером в нашем коде мы не будем напрямую работать с его регистрами, так как там ещё надо проделывать очень много различных подготовительных мероприятий. Для этого существует отличная библиотека wdt.h, которая находится в стандартном комплекте для AVR и не требует дополнительного подключения откуда-то. Но тем не менее о том, как именно устроен сторожевой таймер в контроллере ATMega328, которым мы и будем сегодня пользоваться, мы всё же поговорим.

Таймер питается от отдельного генератора, который вместе с ним входит в логику перезагрузки контроллера

Watchdog timer что это. avr053img00. Watchdog timer что это фото. Watchdog timer что это-avr053img00. картинка Watchdog timer что это. картинка avr053img00

А вот это диаграмма сброса контроллера по истечении интервала времени

Watchdog timer что это. avr053img01. Watchdog timer что это фото. Watchdog timer что это-avr053img01. картинка Watchdog timer что это. картинка avr053img01

Кроме того, что мы можем сбросить сторожевой таймер где-то в коде, мы можем также и отследить окончание интервала времени по прерыванию, которое надо включить отдельно.

WDT, как и было указано выше, работает от отдельного генератора.

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

Давайте посмотрим блок-схему WDT

Watchdog timer что это. avr053img02. Watchdog timer что это фото. Watchdog timer что это-avr053img02. картинка Watchdog timer что это. картинка avr053img02

На рисунке мы видим, что после генератора на 128 килогерц, сигнал проходит на предделитель, который содержит 10 различных выходов с различным коэффициентом деления. Предделитель настраивается с помощью битов WDP3:WDP0 регистра WDTCSR. Таким образом, интервал времени работы WDT лежит в диапазоне от 15 милисекунд до 8 секунд.

Также мы видим, что с помощью бита WDIE мы можем разрешить прерывания от сторожевого таймера и затем попасть в обработчик, отслеживая состояние бита WDIF. Включается таймер с помощью бита WDE.

Вот он – управляющий регистр сторожевого таймера

Watchdog timer что это. avr053img03. Watchdog timer что это фото. Watchdog timer что это-avr053img03. картинка Watchdog timer что это. картинка avr053img03

Хоть мы уже и говорили о битах данного регистра выше, но всё же давайте все их рассмотрим подробно, их не так и много, так как у таймера всего один регистр

WDIF (Watchdog Interrupt Flag): флаг прерывания. Устанавливается в 1 в случае истечения интервала времени таймера. Сбрасывается аппаратно.

WDIE (Watchdog Interrupt Enable): бит разрешения прерываний от таймера. если установлен в 1, то прерывания разрешены, если в 0 – запрещены.

Существует таблица зависимости от состояния бетов WDE, WDIE, а также фьюза WDTON

Watchdog timer что это. avr053img04. Watchdog timer что это фото. Watchdog timer что это-avr053img04. картинка Watchdog timer что это. картинка avr053img04

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

WDP2:WDP0 (Watchdog Timer Prescaler): биты, устанавливающие коэффициент деления предделителя сторожевого таймера.

Вот таблица возможных комбинаций данных битов

Watchdog timer что это. avr053img05. Watchdog timer что это фото. Watchdog timer что это-avr053img05. картинка Watchdog timer что это. картинка avr053img05

Здесь также даны сами интервалы в единицах времени.

WDCE (Watchdog Change Enable): бит изменения, который должен быть предварительно включен перед тем, как мы соберёмся внести изменения в предделитель с целью изменения коэффициента деления либо для отключения таймера путём занесения в бит WDE значения 0. Сбрасывается аппаратно после четырех тактов.

WDE (Watchdog System Reset Enable): бит включения таймера, а вернее бит включения режима перезагрузки системы по истечению интервала времени таймера WDT.

Ну вот, я думаю и всё насчёт теории по сторожевому таймеру. Если что-то пропустил, то исправим это в процессе сочинения кода.

Код наш выполнять будет следующие задачи.

У нас, помимо WDT, будет также работать ещё таймер TIM1, данный таймер будет работать по совпадению, следовательно в обработчик прерываний от него мы будем попадать через определённое время периодично. В обработчике таймера мы будем периодично включать 10 ножек различных портов, а состояние их на какой-то момент мы будем определять по светодиодам, которые мы к ним подключим. Вернее, мы подключим светодиодную планку с 10-ю светодиодами, не забывая конечно о токоограничивающих резисторах, которые я на всякий случай подключил на 680 Ом, при этом светодиоды светятся вполне ярко. В начале программы мы запустим наш сторожевой таймер WDT и зададим ему определённый интервал времени срабатывания. В процедуре обработки прерываний от таймера 1 мы будем своевременно сбрасывать сторожевой таймер, поэтому, если всё у нас будет нормально с ходом программы, то система у нас будет работать и не перезагрузится.

А для того, чтобы проверить, перезагрузится ли наш WDT по истечению интервала, мы сэмулируем ситуацию, что наш таймер перестанет работать. Для этого мы подключим кнопку к контакту INT0 и обработаем от неё внешнее прерывание, в обработчике которого мы запретим прерывания от нашего таймера. Светодиоды, соответственно перестанут бежать, тем самым сигнализируя нам о том, что наш таймер 1 «сломался». Поэтому сторожевой таймер не перезагрузится, тем самым перезагрузит нашу систему и весь процесс у нас начнётся заново.

В качестве контроллера для урока мы возьмём контролер ATMega328P, расположенный на плате Arduino Nano, к которой подключим обычный USB-программатор через разъём ISP. Вставим нашу плату в макетную плату, подведём к ножке PD2 (INT0) кнопку, а также от ножек D3-D12 (ножки портов PD3:PD7, PB0:PB4) подключим аноды светодиодов планки, а катоды через токоограничивающие резисторы подключим к общему проводу

Watchdog timer что это. avr053img06. Watchdog timer что это фото. Watchdog timer что это-avr053img06. картинка Watchdog timer что это. картинка avr053img06

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

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

Запустим среду программирования MPLAB X и запустим создание проекта с помощью следующей кнопки

Watchdog timer что это. avr053img07. Watchdog timer что это фото. Watchdog timer что это-avr053img07. картинка Watchdog timer что это. картинка avr053img07

Выберем «Standalone Project» и идём далее

Watchdog timer что это. avr053img08. Watchdog timer что это фото. Watchdog timer что это-avr053img08. картинка Watchdog timer что это. картинка avr053img08

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

Watchdog timer что это. avr053img09. Watchdog timer что это фото. Watchdog timer что это-avr053img09. картинка Watchdog timer что это. картинка avr053img09

На следующем шаге в качестве программатора выберем Simulator и идём далее

Watchdog timer что это. avr053img10. Watchdog timer что это фото. Watchdog timer что это-avr053img10. картинка Watchdog timer что это. картинка avr053img10

На следующем шаге выберем компилятор и идём дальше

Watchdog timer что это. avr053img11. Watchdog timer что это фото. Watchdog timer что это-avr053img11. картинка Watchdog timer что это. картинка avr053img11

Дадим имя нашему проекту и жмём «Finish»

Watchdog timer что это. avr053img12. Watchdog timer что это фото. Watchdog timer что это-avr053img12. картинка Watchdog timer что это. картинка avr053img12

В дереве проекта в ветке Source Files добавим новый файл main.c с помощью контекстного меню на данной ветке

Watchdog timer что это. avr053img13. Watchdog timer что это фото. Watchdog timer что это-avr053img13. картинка Watchdog timer что это. картинка avr053img13

Исправим имя файла и нажмём «Finish»

Watchdog timer что это. avr053img14. Watchdog timer что это фото. Watchdog timer что это-avr053img14. картинка Watchdog timer что это. картинка avr053img14

Файл main.c создан, чуть позже мы его исправим немного.

А пока создадим ещё заголовочный файл main.h аналогичным образом, только выбрав в контекстном меню на ветке «Header Files» и затем выбрав соответствующий пункт

Watchdog timer что это. avr053img15. Watchdog timer что это фото. Watchdog timer что это-avr053img15. картинка Watchdog timer что это. картинка avr053img15

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

Watchdog timer что это. avr053img18. Watchdog timer что это фото. Watchdog timer что это-avr053img18. картинка Watchdog timer что это. картинка avr053img18

Оставим уровень оптимизации 0 и установим чекбокс на пункте Debug

Источник

Watchdog Timer

Watchdog timer что это. Watchdog Timer. Watchdog timer что это фото. Watchdog timer что это-Watchdog Timer. картинка Watchdog timer что это. картинка Watchdog Timer

Доступные параметрыEnabled
Disabled(по умолчанию)

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

В большинстве случаев контрольный таймер доступен прямо в BIOS-е. Впрочем, некоторые производители материнских плат страдают недоверием к пользователям и оснащают свои платы только самыми безопасными и «пользовательскими» функциями. Если вам так не повезло – увы, доступ к настройкам WDT вам закрыт. К счастью, таких производителей немного.

Как работает контрольный таймер

WDT запускается вместе со стартом системы и тут же начинает отслеживание её действий. Впрочем, некоторые модели плат имеют технологическую особенность: первый шаг WDT в них является холостым, а значит, по-настоящему работу таймер начнет только по прохождении 0,6 секунды. Стандартное значение WDT– 4h, что означает 4 шага. Если программа не успевает выполнить операцию за четыре шага (1,8 – 2,4 секунды) система принудительно останавливает её и производит корректировку программы. Ну или перезагружает/выключает компьютер, если эта программа системная. При этом вы получите BSoD (Blue Screenof Death) с описанием произошедшей ошибки, например DPC_WATCHDOG_VIOLATION.

Максимальное значение WDT– 3Fh, то есть 62 шага или 37,5 секунд, но устанавливать его не стоит: в случае какого-либо сбоя вы потеряете доступ к ПК не на жалкие две секунды, а почти на полминуты. К тому же любой современный ПК способен выполнить стандартную операцию меньше чем за секунду, а значит, даже двухсекундная задержка уже сбой.

Стоит ли включать эту опцию?

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

Источник

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 не будет опубликован. Обязательные поля помечены *