在多任务环境中喂养看门狗的策略

20

将一些嵌入式代码移植到FreeRTOS后,我面临一个有趣的问题:看门狗。看门狗定时器对我们的应用程序至关重要。使用FreeRTOS对我们来说也是一个巨大的福音。当应用程序更多地单任务化时,它会在逻辑流程的适当时点喂养看门狗,以便我们确保任务能够按时进行逻辑进展。

然而,对于多个任务而言,这并不容易。一个任务可能因某种原因而被阻塞,没有进展,但另一个任务正在良好地运行并足够快地取得进展,从而让看门狗得到满足。

其中一个想法是启动一个单独的任务仅用于喂养看门狗,然后使用其他任务定期增加的一些计数器,当看门狗任务滴答作响时,它将确保所有计数器都显示出其他任务正在取得进展的迹象,如果是这样,那么就继续喂养看门狗。

我很好奇其他人在这种情况下所做的事情?


5
我们已经做了你所说的大部分事情。还有一个kicker,和一些已知时间段的任务会向kicker汇报。如果这些任务没有按时运行,那么kicker也不会运行。kicker应该是系统中优先级最低的线程,因此如果系统没有时间去处理kicker,那么设备将会重置。(这也给了kicker自身提供保护)。我现在很忙,但稍后会尝试提供一个更长的回答。 - Ross
我记得在最近一个月内有一个类似的问题,肯定带有嵌入标签。 - Dan
4个回答

13
一种监视所有其他任务状态的看门狗任务是一个不错的解决方案。但是,考虑使用每个任务的状态标志,而不是计数器。状态标志应该有三个可能的值:未知(UNKNOWN),活着(ALIVE)和睡眠(ASLEEP)。当周期性任务运行时,它将状态标志设置为ALIVE。在异步事件上阻止的任务应该在阻止之前将其标志设置为ASLEEP,然后在运行时将其标志设置为ALIVE。当看门狗监视任务运行时,如果每个任务都是ALIVE或ASLEEP,则应该踢动看门狗。然后,监视任务应将所有ALIVE标志设置为UNKNOWN。(ASLEEP标志应保持ASLEEP)。带有UNKNOWN标志的任务必须运行,并再次将其标志设置为ALIVE或ASLEEP,然后监视任务才会再次踢动看门狗。
有关更多详细信息,请参见本文的“多任务处理”部分:http://www.embedded.com/design/debug-and-optimization/4402288/Watchdog-Timers

2
不要忘记处理可能出现的任务删除或长时间休眠的情况。如果这些任务先前已经通过看门狗任务进行了检查,它们还需要具备“签出”机制。
换句话说,由看门狗任务负责的任务列表应该是动态的,并且应该组织得很好,以便一些未知代码不能轻易地从列表中删除任务。
我知道,说起来容易做起来难...

2

看门狗定时器确实是个大问题。

我的板子上有一个GPIO线上的LED灯,所以我在一个次低优先级线程中使用while/sleep循环来闪烁它(750ms亮,250ms灭)。我在LED闪烁线程中放置了看门狗喂狗。

这对于完全崩溃和CPU循环的高优先级线程有所帮助,但如果系统死锁则无济于事。幸运的是,我的消息传递设计不会死锁(好吧,至少不经常死锁:)。


0

我已经使用FreeRTOS定时器设计了解决方案:

  1. SystemSupervisor SW Timer,用于喂养HW WD。FreeRTOS故障会导致重置。
  2. 每个任务创建“自己的”SW定时器,并带有SystemReset函数。
  3. 每个任务负责在其计时器到期之前“手动”重新加载其计时器。
  4. SystemReset函数在提交自杀之前保存数据

以下是一些伪代码清单:

//---------------------------------
//
// 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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接