Top.Mail.Ru

STM32CubeMx и watchdog. Настройка и использование IWDG.

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

Эксперименты я буду проводить на отладочной плате STM32F429Discovery. Давайте создадим новый пустой проект, но перед этим немного поговорим о работе watchdog-таймеров в целом. Итак, что же это за такой отдельный таймер?

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

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

void main()
{
	WatchdogInit(500);

	while(1)
	{
		WatchdogRefresh();
		Function();
	}
}

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

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

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

Пришло время перейти к практической деятельности. Открываем новый проект в STM32CubeMX и активируем таймер. Заодно давайте настроим выводы контроллера (PG13, PG14 на моей плате), подключенные к светодиодам, на работу в режиме выхода. Они понадобятся для тестирования:

Настройка IWDG в STM32CubeMx

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

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

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

HAL_IWDG_Refresh(&hiwdg);

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

/* Initialize all configured peripherals */
MX_IWDG_Init();
/* USER CODE BEGIN 2 */
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);

/* USER CODE END 2 */

Проведем анализ происходящего 👍

После запуска таймера он начинает считать от значения 1000 мс до 0. Зажигаем зеленый светодиод (PG13) и ждем 500 мс. Затем перезагружаем значение счетного регистра таймера, чтобы избежать перезапуска программы, и гасим зеленый. Далее снова следует команда задержки, по окончанию которой зажигаем красный. При таком значении задержки, как в данном примере, на момент включения красного светодиода сторожевой таймер досчитает до 400 мс (1000 - 600). В результате чего красный будет светиться 400 мс, после чего программа перезапустится.

Теперь попробуем увеличивать величину задержки (HAL_Delay(600)) и увидим, что красный светодиод находится во включенном состоянии все меньшее время. А если сделать величину задержки большей 1000, то диод не загорится вовсе (сторожевой таймер сработает раньше, чем программа дойдет до его включения). И в этом случае мы будем наблюдать только мигание зеленого светодиода, так как программа будет раз за разом перезапускаться.

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

Подписаться
Уведомить о
guest

10 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
vitaliy
vitaliy
8 лет назад

Спасибо за статью !!!! очень полезная инф..

Паша
8 лет назад

Новых статей давно чего то нету! Чем все таки отличаются IWDG от WWDG ?

Паша
8 лет назад

Спасибо, уже изучаю!

Паша
8 лет назад

C StandartPerefLibrary это будет выглядеть так?

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

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

Vitali
Vitali
7 лет назад

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

Игорь
Игорь
7 лет назад

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

Игорь
Игорь
7 лет назад

Вопрос решен.
Для того, чтобы понять что перезагрузка произошла по срабатыванию IWDG (да и WWDG) нужно следить за регистром Control/status register (RCC_CSR). Там есть биты IWDG RSTF (WWDG RSTF). Если он выставлен в 1, то перезагрузка произошла по нему. Чтобы его сбросить нужно в этом же регистре в бит RMVF записать 1 (как я понял, она обнуляет весь регистр).

Alex
Alex
4 лет назад

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

10
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x