Стратегия для питания сторожевого пса в многозадачной среде
Переместив некоторый встроенный код в FreeRTOS, у меня осталась интересная дилемма о сторожевом плеере. Таймер сторожевого таймера является обязательным для нашего приложения. Использование FreeRTOS стало для нас огромным благом. Когда приложение было более однозадачным, оно своевременно подавало сторожевой таймер в своем логическом потоке, чтобы мы могли своевременно выполнить логический ход.
С несколькими задачами, хотя это и нелегко. Одна задача может быть связана по какой-то причине, а не с прогрессом, но другая делает все хорошо и добивается достаточного прогресса, чтобы держать сторожевого пса счастливым.
Одна мысль заключалась в том, чтобы запустить отдельную задачу только для того, чтобы накормить сторожевого пса, а затем использовать некоторые счетчики, чтобы другие задачи увеличивались регулярно, когда задача сторожевого таймера гаснет, она будет следить за тем, чтобы все счетчики выглядели так, как будто прогресс все остальные задачи, и если да, продолжайте и кормите сторожевого пса.
Мне любопытно, что сделали другие в таких ситуациях?
Ответы
Ответ 1
Задача сторожевого таймера, которая контролирует состояние всех других задач, является хорошим решением. Но вместо счетчика рассмотрите возможность использования флага состояния для каждой задачи. Флаг состояния должен иметь три возможных значения: UNKNOWN, ALIVE и ASLEEP. Когда выполняется периодическая задача, он устанавливает флаг в ALIVE. Задачи, которые блокируются на асинхронном событии, должны установить свой флаг в ASLEEP до того, как они будут заблокированы, а ALIVE - при запуске. Когда запускается контрольная задача сторожевого таймера, она должна ударять сторожевого таймера, если каждая задача является либо ЖИВОМ, либо ASLEEP. Затем задача сторожевого монитора должна установить все флаги ALIVE в UNKNOWN. (Флаги ASLEEP должны оставаться ASLEEP.) Задачи с флагом UNKNOWN должны выполняться и устанавливать свои флаги в ALIVE или ASLEEP еще раз, прежде чем задача монитора снова запустит сторожевой таймер.
Дополнительную информацию см. в разделе "Многозадачность" этой статьи: http://www.embedded.com/design/debug-and-optimization/4402288/Watchdog-Timers
Ответ 2
Это действительно большая боль с таймерами сторожевого таймера.
Мои платы имеют светодиод на линии GPIO, поэтому я запускаю его в течение короткого промежутка времени/спящего цикла (750 мс вкл., 250 мс) в потоке с самым низким приоритетом (самый низкий - это незанятый поток, который просто идет в режим низкой мощности в петле). Я поставил wdog-канал в поток светодиодной вспышки.
Это помогает с полными сбоями и высокоприоритетными потоками в цикле процессора, но не помогает, если система блокируется. К счастью, мои проекты передачи сообщений не зашли в тупик (ну, не часто, так или иначе:).
Ответ 3
Не забывайте обрабатывать возможную ситуацию, когда задачи удаляются или спящие в течение более длительных периодов времени. Если эти задачи были предварительно проверены с помощью функции сторожевого таймера, у них также должен быть механизм "проверить".
Другими словами, список задач, для которых ответственна задача watchdog, должен быть динамическим, и он должен быть организован таким образом, чтобы какой-то дикий код не мог легко удалить задачу из списка.
Я знаю, проще сказать, потом сделать...
Ответ 4
Я разработал решение, используя таймеры FreeRTOS:
- Таймер SystemSupervisor SW, который передает HW WD. Ошибка FreeRTOS
вызывает reset.
- Каждая задача создает "свой" таймер SW с функцией SystemReset.
- Каждая задача, ответственная за "вручную", перезагружает свой таймер до истечения срока его действия.
- Функция SystemReset сохраняет данные, прежде чем совершать suiside
Вот список псевдокодов:
//---------------------------------
//
// System WD
//
void WD_init(void)
{
HW_WD_Init();
// Read Saved Failure data, Send to Monitor
// Create Monitor timer
xTimerCreate( "System WD", // Name
HW_WD_INTERVAL/2, // Reload value
TRUE, // Auto Reload
0, // Timed ID (Data per timer)
SYS_WD_Feed);
}
void SYS_WD_Feed(void)
{
HW_WD_Feed();
}
//-------------------------
// Tasks WD
//
WD_Handler WD_Create()
{
return xTimerCreate( "", // Name
100, // Dummy Reload value
FALSE, // Auto Reload
pxCurrentTCB, // Timed ID (Data per timer)
Task_WD_Reset);
}
Task_WD_Reset(pxTimer)
{
TaskHandler_t th = pvTimerGetTimerID(pxTimer)
// Save Task Name and Status
// Reset
}
Task_WD_Feed(WD_Handler, ms)
{
xTimerChangePeriod(WD_Handler, ms / portTICK_PERIOD_MS, 100);
}