20

将一些嵌入式代码移至 FreeRTOS 后,我对看门狗有一个有趣的困境。看门狗定时器对于我们的应用来说是必须的。使用 FreeRTOS 对我们来说也是一个巨大的福音。当应用程序更多是单任务时,它会在其逻辑流程中的及时点向看门狗提供信息,以便我们可以确保任务及时进行逻辑进展。

但是,对于多项任务,这并不容易。一项任务可能由于某种原因被绑定,没有取得进展,但另一项任务做得很好并且取得了足够的进展,可以让看门狗开心地吃饱。

一个想法是单独启动一个单独的任务来喂养看门狗,然后使用一些其他任务定期递增的计数器,当看门狗任务滴答作响时,它将确保所有计数器看起来都在其他所有任务上都取得了进展任务,如果是这样,继续喂看门狗。

我很好奇其他人在这种情况下做了什么?

4

4 回答 4

13

监视所有其他任务状态的看门狗任务是一个很好的解决方案。但不要使用计数器,而是考虑为每个任务使用状态标志。状态标志应该具有三个可能的值:UNKNOWN、ALIVE 和 ASLEEP。当周期性任务运行时,它会将标志设置为 ALIVE。阻塞异步事件的任务应在阻塞前将其标志设置为 ASLEEP,并在运行时将其设置为 ALIVE。当看门狗监视器任务运行时,如果每个任务都处于活动状态或处于睡眠状态,它应该启动看门狗。然后看门狗监控任务应该将所有的 ALIVE 标志设置为 UNKNOWN。(ASLEEP 标志应保持 ASLEEP。)具有 UNKNOWN 标志的任务必须运行并将其标志再次设置为 ALIVE 或 ASLEEP,然后监视器任务将再次启动看门狗。

有关更多详细信息,请参阅本文的“多任务处理”部分: http ://www.embedded.com/design/debug-and-optimization/4402288/Watchdog-Timers

于 2013-02-08T20:19:03.550 回答
2

不要忘记处理任务被删除或休眠较长时间的可能情况。如果这些任务以前是通过看门狗任务签入的,那么它们还需要有一个“签出”机制。

换句话说,看门狗任务负责的任务列表应该是动态的,并且应该组织起来,使得一些野代码不能轻易地从列表中删除该任务。

我知道,说起来容易做起来难...

于 2013-03-19T21:42:09.423 回答
2

这确实是看门狗定时器的一大痛点。

我的电路板在 GPIO 线上有一个 LED,所以我在 while/sleep 循环中闪烁它,(750ms 开,250ms 关),在次低优先级线程中,(最低是空闲线程,它只是进入低功率循环模式)。我在 LED-flash 线程中放了一个 wdog 提要。

这有助于完全崩溃和 CPU 循环的更高优先级线程,但如果系统死锁则无济于事。幸运的是,我的消息传递设计没有陷入僵局,(嗯,不经常,反正:)。

于 2013-02-07T21:08:53.090 回答
0

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

  1. SystemSupervisor SW Timer为 HW WD 提供数据。FreeRTOS 故障导致重置。
  2. 每个任务使用 SystemReset 功能创建“自己的”软件计时器。
  3. 每个任务负责“手动”在它到期之前重新加载它的计时器。
  4. SystemReset 函数在提交 suside 之前保存数据

这是一些伪代码清单:

//---------------------------------
//
// 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);
}
于 2016-02-24T10:19:15.217 回答