RTOS下看门狗的使用策略

什么是看门狗

看门狗定时器是一种电子定时器,用于检测嵌入式系统中的错误并从中恢复。 看门狗定时器的基本原理很简单但很有效。 在特定时间段内,系统必须通知(喂狗)看门狗它仍在运行。 如果看门狗未收到此通知,则它假定存在故障并将系统置于已知状态。 通常,看门狗将重置(复位)处理器。 但是,对于更复杂的系统,看门狗可能必须触发一系列操作才能将系统置于已知的安全状态,例如电梯,检测到系统故障就不能简单的复位,不然后果很严重,而是在看门狗中断触发后让系统处于一个安全的状态,比如停止运动,并打开安全保护装置。

基本的看门狗保护

平时常用的一种方式是创建一个任务,在任务里周期性的喂狗。这种方式在这个喂狗任务故障或者系统完全崩溃(如hardfault)导致喂狗任务无法正常执行时,可以发挥作用。
现在我们处于RTOS下,情况就有点复杂了,某个或多个任务失效了,并不会导致整个系统崩溃。这些情况可能是:

  • 某个任务里进入了死循环,但是仍能正常调度其它任务;
  • 两个或多个任务因资源问题进入了死锁的状态;
  • 某个低优先级任务因为高优先级任务一直抢占了CPU而得不到运行;

可见,这种方式在RTOS环境下能发挥的效果有限!!!

提高鲁棒性

前面提到的失效原因,都是因为看门狗没能检测到每一个任务的运行状态。所以,优化的办法的就是让它能检测到每个任务的运行。一个方法就是其它任务周期性的给喂狗任务发送通知,喂狗任务如果收到所有任务的通知就进行一次喂狗。这样,如果某个任务故障了,那将无法正常的发送喂狗通知,喂狗条件无法得到满足,因此一段时间后看门狗定时器将会超时。
下面是FreeRTOS下的简单实现方式:

#define TASK_1_BIT  (1UL << 0UL)
#define TASK_2_BIT  (1UL << 1UL)

/* 看门狗任务设为最高优先级,这样在收到低优先级的任务发来喂狗通知后能及时喂狗 */
void task_watchdog(void * pvParameters)
{
    uint32_t ulNotifiedValue;

    while (1)
    {
        /* 等待喂狗通知 */
        xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, portMAX_DELAY );

        /* 判断是否收到了所有其他任务的通知 */
        if( (ulNotifiedValue & (TASK_1_BIT | TASK_2_BIT)) == (TASK_1_BIT | TASK_2_BIT) )
        {
            /* 收到则喂狗 */
            feed_dog();
            /* 清除通知,等待一下次喂狗 */
            ulTaskNotifyValueClear(NULL, UINT_MAX);
        }
    }
}

void task_1(void * pvParameters)
{
    while (1)
    {
        /* 通知喂狗 */
        xTaskNotify( xTaskWatchdogHandle, TASK_1_BIT, eSetBits );

        /* 努力干活 */

        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void task_2(void * pvParameters)
{
    uint32_t ulNotifiedValue;
    BaseType_t result;

    while (1)
    {
        /* 类似这种等待不能永久等待,而是有个超时时间,后面根据判断是否收到消息再做处理 */
        /* 官方文档有句话是这么说的:NOTE!  Real applications should not block indefinitely,
        but instead time out occasionally in order to handle error conditions
        that may prevent the interrupt from sending any more notifications. */
        result = xTaskNotifyWait( 0x00, ULONG_MAX, &ulNotifiedValue, 2000 / portTICK_PERIOD_MS );

        if (pdTRUE == result)
        {
            /* 努力干活 */
        }

        /* 通知喂狗 */
        xTaskNotify( xTaskWatchdogHandle, TASK_2_BIT, eSetBits );
    }
}

更高级的使用策略


本人没看懂,下面是一个现成的解决方案,有条件的可以研究

你可能感兴趣的:(RTOS下看门狗的使用策略)