Подтвердить что ты не робот

Стратегия для питания сторожевого пса в многозадачной среде

Переместив некоторый встроенный код в FreeRTOS, у меня осталась интересная дилемма о сторожевом плеере. Таймер сторожевого таймера является обязательным для нашего приложения. Использование FreeRTOS стало для нас огромным благом. Когда приложение было более однозадачным, оно своевременно подавало сторожевой таймер в своем логическом потоке, чтобы мы могли своевременно выполнить логический ход.

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

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

Мне любопытно, что сделали другие в таких ситуациях?

4b9b3361

Ответ 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);
}