STM32Cube. Watchdog. Использование IWDG.

Зачастую возникают ситуации, в которых программа зависает на какой-то точке, и в этом случае единственными решениями являются либо сброс питания микроконтроллера, либо нажатие на кнопку Reset. Но порой у пользователя просто нет доступа непосредственно к электронике, установленной внутри какого-либо корпуса. Да и даже если этот  доступ есть, нет ничего хорошего в том, чтобы вынуждать покупателя вашего устройства ковыряться в микросхемах и платах =) Именно для этих целей и придуман периферийный модуль микроконтроллера под названием Watchdog, и именно этим инструментом мы сегодня и научимся пользоваться при помощи STM32Cube.

Использование WatchDog таймера

Эксперименты я буду проводить на отладочной плате STM32F429-Discovery и при помощи STM32Cube (как уже понятно из названия статьи 😉 ). Так что давайте создадим новый пустой проект, но перед этим немного поговорим о работе watchdog таймеров в целом.

Итак, что же это за такой отдельный таймер?

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

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

void main()
{
  WatchdogInit();
 
  while(1)
  {
    WatchdogRefresh();
    Function();
  }
}

Давайте разберемся, как будет работать эта маленькая программа. Сразу же после входа в функцию main() мы инициализируем watchdog — пусть период составляет 500 мс.

В цикле while(1) основную полезную работу нашей программы выполняет функция Function(). В этой функции может быть все, что угодно — расчеты, отправка данных, работа с файлами и т. д. Но мы точно знаем, что в нормальном режиме работы время выполнения этой функции всегда составляет величину, меньшую 500 мс (пусть к примеру это время равно 100 мс). Таким образом, сторожевой таймер никак не повлияет на работу программы в нормальном режиме. Но если вдруг внутри функции Function() случится какая-то неприятность, и программа зависнет (например, во вложенном цикле while() или на ожидании какого-либо флага), то watchdog перезапустит контроллер по истечению 500 мс. Получается, что он предотвратит глобальное зависание МК и запустит программу заново. Вот в этом то и состоит задача этого таймера =)

У микроконтроллеров STM32 есть даже не один, а два модуля — IWDG и WWDG. Во многом они похожи, но есть и отличия. Сегодня мы сосредоточим наше внимание на IWDG, ну а в одной из следующих статей мы проведем аналогичные сегодняшним тесты и для WWDG.

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

Настройка сторожевого таймера

На этой вкладке нам больше ничего предпринимать не потребуется, переходим на Configuration и заходим в настройки таймера:

Настройка IWDG

Здесь мы настраиваем предделитель и период. IWDG в нашем примере тактируется от внутреннего низкочастотного генератора 32 КГц. Разделим частоту на 32 и получим 1 КГц. Таким образом, при величине периода, равной 1000, сторожевой таймер будет обнуляться и перезапускать контроллер по истечению 1 секунды.

Генерируем программный код и открываем создавшийся проект.
В самом начале функции main() видим вызов функций инициализации:

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_IWDG_Init();

Кроме того, необходимо запустить сторожевой таймер:

HAL_IWDG_Start(&hiwdg);

Для того, чтобы перезагрузить значение счетного регистра IWDG необходимо вызвать функцию:

HAL_IWDG_Refresh(&hiwdg);

Теперь давайте создадим следующий тестовый алгоритм:

HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET);
HAL_Delay(500);
 
HAL_IWDG_Refresh(&hiwdg);
 
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_Delay(600);
 
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET);

Давайте посмотрим, что у нас тут происходит. После запуска таймера он у нас начинает считать от значения 1000 мс до 0. Зажигаем зеленый светодиод (G13) и ждем 500 мс. После этого перезагружаем значение счетного регистра таймера, чтобы избежать перезапуска программы. После этого мы гасим зеленый светодиод. Далее у нас следуют команда задержки и команда включения красного светодиода. При таком значении задержки, как в данном примере, на момент включения красного светодиода сторожевой таймер досчитает до 400 мс (1000 — 600). И красный диод будет светиться 400 мс, после чего программа перезапустится. Теперь попробуем увеличивать величину задержки в функции HAL_Delay(600) и увидим, что красный диод находится во включенном состоянии все меньшее время. А если сделать величину задержки большей 1000, то диод не загорится вовсе (сторожевой таймер сработает раньше, чем программа дойдет до включения диода красного цвета). И в этом случае мы будем наблюдать только мигание зеленого светодиода, так как программа будет раз за разом перезапускаться.

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

Понравилась статья? Поделись с друзьями!

STM32Cube. Watchdog. Использование IWDG.: 8 комментариев
  1. C StandartPerefLibrary это будет выглядеть так?

    // настройка
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    IWDG_SetPrescaler(IWDG_Prescaler_32); //делитель на 32 =1кгц
    IWDG_SetReload(1000); // период
    IWDG_ReloadCounter(); // сброс счетчика
    IWDG_Enable(); //вкл WatchDog

    //сброс счетчика в программе
    IWDG_ReloadCounter();

    • Я инициализацию так делаю:

      IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
      IWDG_SetPrescaler(IWDG_Prescaler_32);
      IWDG_SetReload(8000);
      IWDG_WriteAccessCmd(IWDG_WriteAccess_Disable);
      IWDG_Enable();

      А так все верно.

  2. Как из обычного таймера сделать сторожевой? Я работаю с USART, через какой то промежуток времени должны приходить байты, если байт не пришел таймер до тикает до прерывания, если пришел то обновляется счет таймера. Заранее благодарю.

    • Полноценный функционал сторожевого таймера на обычном не реализовать. Можно в прерывании обычного таймера выполнять перезапуск контроллера через NVIC_SystemReset().

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

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