Одна из предыдущих статей была посвящена знакомству с модулем сторожевого таймера IWDG, и вот пришло время обсудить и второй вид watchdog-таймеров, а именно WWDG. Задачи, которые призван решать WWDG, в целом, аналогичны тем задачам, которые решает IWDG, поэтому давайте сразу же сосредоточимся на отличиях. А отличия есть, и не одно:
- Во-первых, в отличие от IWDG, который тактируется от низкочастотного генератора, WWDG тактируется, как и большинство остальных модулей микроконтроллера, от высокочастотного генератора. Частота тактирования таймера получается делением частоты PCLK1 (частота шины APB1) на постоянный делитель 4096. Кроме того, в настройках таймера мы можем добавить еще и дополнительный предделитель. Его возможные значения равны 1, 2, 4 и 8.
- Во-вторых, отличие есть и в самом принципе работы. Если IWDG перезапускал контроллер в том случае, если он досчитал до 0, то WWDG работает иначе.
Собственно, на втором пункте остановимся подробнее...
Значение счетчика WWDG мы можем установить равным величине, которая лежит в пределах от 64 до 127. Таким образом, таймер начинает считать вниз от того значения, которое мы в него записали, до 63. А, досчитав до 63, перезапустит контроллер.
Еще одним существенным отличием является то, что при работе с IWDG, мы могли перезагрузить счетный регистр таймера в любой момент времени, а WWDG же мы можем обновить только в определенный временной промежуток, который задается параметром window value. Этот параметр мы также можем установить равным любому числу от 64 до 127.
Сейчас рассмотрим небольшой пример для лучшего понимания протекающих процессов.
Пусть значение счетчика таймера равно 100, а значение окна - 80. Включаем сторожевой таймер и он начинает считать от 100 до 63. Обновить значение WWDG мы сможем только после того, как таймер досчитает до 80. Если мы сделаем это раньше установленного срока, то произойдет перезапуск контроллера. Также контроллер будет перезапущен и в том случае, если таймер досчитает до 63. При таких настройках мы можем обновить его счетный регистр в те моменты, когда его значение лежит в интервале от 63 до 80.
Вот как все это выглядит:
И еще одним отличием WWDG от IWDG является то, что у WWDG есть свое собственное прерывание. Оно вызывается непосредственно перед перезапуском контроллера, когда таймер уже досчитал до 64. Нужно это для того, чтобы сохранить какие-либо важные данные, которые могут быть утеряны при перезапуске, либо осуществить требуемые дополнительные действия.
Давайте теперь перейдем в STM32CubeMx и создадим небольшой пример для демонстрации того, что обсудили. Активируем WWDG и внешний кварцевый резонатор:
Настройки тактирования в STM32CubeMx мы уже обсуждали, поэтому не буду приводить скриншот - у меня на APB1 приходит 24 МГц. Для WWDG настраиваем в порядке очередности:
- предделитель частоты - 1
- window value - 80
- значение счетного регистра - 120
- также включаем прерывание
На вкладке NVIC Settings:
Произведем расчетную деятельность, частота таймера по итогу будет равна:
f = \frac{24 \medspace МГц}{4096 \medspace \cdot \medspace 1} = 5.859 \medspace КГц
Данной частоте, в свою очередь, соответствует период, то есть время, за которое таймер уменьшит значение своего счетного регистра на единицу:
T = \frac{1}{f} = 0.17 \medspace мс
В результате WWDG досчитает от 120 до 63 за время:
t = (120 \medspace - \medspace 63) T = 9.73 \medspace мс
Полностью аналогично можно рассчитать, по истечению какого интервала времени мы сможем обновлять значение счетного регистра:
t_w = (120 \medspace - \medspace 80) \medspace T = 6.82 \medspace мс
Таким образом, если мы запустим таймер, но не будем обновлять значение счетчика, то контроллер перезапустится через 9.73 мс. А обновить значение счетного регистра сможем в том случае, если с момента запуска/обновления регистра прошло как минимум 6.82 мс.
С функциональностью разобрались 👍 Программно данные действия могут быть осуществлены следующим образом. Запуск, как и в случае с IWDG, происходит автоматически в функции инициализации таймера, а для обновления в HAL есть функция:
HAL_WWDG_Refresh(&hwwdg);
Для того, чтобы отловить прерывание можно переопределить callback:
/* USER CODE BEGIN 4 */ void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg) { // Добавляем действия сюда } /* USER CODE END 4 */
Данная функция будет вызвана из библиотеки автоматически при наступлении соответствующего события.
В общем-то все реализовано довольно просто, чуть сложнее оказался сам принцип работы WWDG. Думаю на этом можно и закончить сегодняшнюю статью. Оставайтесь с нами и следите за обновлениями!
зачем же все эти сложности нужны? каков реальный сценарий использования этих наворотов с окнами и счетчиком до 63 вместо 0?