如何在RTOS中使用看门狗定时器?

假设我在嵌入式环境中有一个合作调度程序。 我有很多进程在运行。 我想利用看门狗定时器,这样我就可以检测到某个进程因任何原因而停止运行并重置处理器。

在没有实时操作系统的简单应用程序中,我会始终触摸主循环中的看门狗,这样总是足够的。 但是,在这里,有很多可能会挂起的进程。 定期触摸看门狗定时器,同时确保每个进程处于良好状态的干净方法是什么?

我在想,我可以为每个进程提供一个回调函数,以便它可以让另一个监督所有进程的函数知道它仍然存在。 回调会传递一个参数,这个参数是任务唯一ID,因此监督员可以确定谁在回叫。


一种常见的方法是将看门狗踢到一个特定的任务上(通常是最高优先级或最低优先级,每种方法的折衷/动机),然后让所有其他任务“检入”这项任务。

这条路:

  • 如果中断挂起(100%的CPU),kicker任务将不会运行,您重置

  • 如果kicker任务已挂起,则重置

  • 如果另一项任务挂起,踢球任务看不到签入,踢球任务不踢WDG,你重置

  • 现在当然有实施细节需要考虑。 有些人每个任务都在全局变量中设置自己的专用位(自动); kicker任务以特定速率检查这组比特标志,并在每个人签入时清除/重置(当然还有踢WDG)。我避开了像鼠疫这样的全局变量,并避免了这种方法。 RTOS事件标志提供了一个更加优雅的有点类似的机制。

    我通常将我的嵌入式系统设计为事件驱动系统。 在这种情况下,每个任务都在一个特定的地方阻塞 - 在一个消息队列中。 所有任务(和ISR)通过发送事件/消息相互通信。 这样,你就不必担心没有检入的任务,因为它在信号量的“下路”上被阻塞(如果这样做没有意义,对不起,没有写更多的东西,我不能更好地解释它)。

    还有一点需要考虑 - 任务是否“自动”检查,或者他们是否回复/响应踢球任务的请求。 自主 - 例如每秒一次,每个任务都会在队列中收到一个事件“告诉踢球者你还活着”。 回复请求 - 每秒一次(或其他),踢球任务告诉每个人(通过队列)“检查时间” - 最终每个任务都运行其队列,获取请求并回复。 考虑任务优先级,排队理论等适用。

    这种猫有100种方法,但是单个任务的基本原则是负责踢WDG,并让其他任务能够完成踢球任务,这非常标准。

    至少还有一个方面需要考虑 - 这个问题的范围之外 - 这就是处理中断。 如果一个ISR占用CPU(好),我上面描述的方法将触发WDG重置,但是相反的情况呢 - 一个ISR(可悲地)意外地和不经意地被禁用。 在很多情况下,这不会被捕获,并且您的系统仍然会启动WDG,但系统的一部分已经损坏。 有趣的东西,这就是为什么我喜欢嵌入式开发。


    一种解决模式:

  • 希望被检查的每个线程都显式地向看门狗线程注册它的回调,该线程维护着这样的回调列表。
  • 当安排看门狗时,它可以迭代已注册任务的列表
  • 每个回调本身都被迭代调用,直到它返回一个健康的状态。
  • 在列表的最后,硬件看门狗被踢出。
  • 这样,任何永远不会返回健康状态的线程都会停止看门狗任务,直到发生硬件看门狗超时。

    在抢先式操作系统中,看门狗线程将是最低优先级或空闲线程。 在合作调度程序中,它应该在回叫调用之间产生。

    回调函数本身的设计取决于具体的任务及其行为和周期性。 每个功能都可以根据任务的需求和特点进行量身定制。 高周期性的任务可能只是增加一个计数器,当调用回调时该计数器设置为零。 如果计数器在输入时为零,则自上次看门狗检查以来该任务没有安排。 具有低或非周期性行为的任务可能会为其调度添加时间戳,如果该任务尚未在某个特定时间段内进行调度,则回调可能会返回失败。 这两种任务和中断处理程序都可以用这种方式进行监视。 此外,因为线程有责任向看门狗注册,所以可能有一些线程根本不会注册。


    传统的方法是使用最低优先级的看门狗进程

    PROCESS(watchdog, PRIORITY_LOWEST) { while(1){reset_timer(); sleep(1);} }
    

    而实际的硬件定时器可能每3或5秒重新设置一次。

    跟踪单个进程可以通过反向逻辑来实现:每个进程都会设置一个定时器,该定时器的回调会向看门狗发送'停止'消息。 然后,每个进程需要取消先前的定时器事件,并在“接收来自队列的事件/消息”循环中的某处设置一个新事件。

    PROCESS(watchdog, PRIORITY_LOWEST) {
        while(1) { 
           if (!messages_in_queue()) reset_timer();
           sleep(1);
        }
    }
    void wdg_callback(int event) { 
        msg = new Message();
        send(&msg, watchdog);
    };
    PROCESS(foo, PRIORITY_HIGH) {
         timer event=new Timer(1000, wdg_callback);
         while (1) {
            if (receive(msg, TIMEOUT)) {
               // handle msg       
            } else { // TIMEOUT expired 
               cancel_event(event);
               event = new Timer(1000,wdg_callback);
            }
         }
    }
    
    链接地址: http://www.djcxy.com/p/43617.html

    上一篇: How to use the watchdog timer in a RTOS?

    下一篇: difference between Preemption and context switch