我有一个嵌入式系统,它有多个(> 20)任务以不同的优先级运行。我也有运行看门狗任务来检查所有其他任务是否没有卡住。我的看门狗正在工作,因为每逢蓝月亮,它都会重新启动系统,因为任务没有签入。
如何确定哪个任务死亡?
我不能只责怪最旧的任务踢看门狗,因为它可能被没有让步的更高优先级任务推迟。
有什么建议么?
这是先发制人吗?我之所以这么认为,是因为如果其他任务中的一个卡住了,那么看门狗任务就不会运行。
您没有提及操作系统,但是,如果看门狗任务可以检查单个任务是否尚未签入,则每个任务和看门狗之间必须有单独的通信通道。
您可能必须修改看门狗以某种方式转储尚未签入的任务编号并转储任务控制块和内存,以便您可以进行事后分析。
根据操作系统,这可能容易或困难。
每个任务的看门狗要求较高优先级的任务产生足够的时间,以便所有人都可以踢看门狗。要确定哪个任务有问题,您必须找到使其他任务挨饿的任务。您需要测量看门狗检查之间的任务执行时间,以找出真正的罪魁祸首。
甚至我最近几周都在处理看门狗重置问题。但幸运的是,在 ramdump 文件中(在 ARM 开发环境中),它有一个中断处理程序跟踪缓冲区,在每个中断处都包含 PC 和 SLR。因此,从跟踪缓冲区中,我可以准确地找出在 WD 重置之前运行的代码部分。
我认为,如果您在每次中断时都有相同的存储 PC、SLR 的机制,那么您可以准确地找出罪魁祸首任务。
根据您的系统和操作系统,可能会有不同的方法。我使用的一种非常低级的方法是在每个任务运行时使 LED 闪烁。您可能需要在 LED 上放置一个示波器,以查看非常快速的任务切换。
对于中断驱动的看门狗,您只需让任务切换器在每次更改时更新当前正在运行的任务编号,以便您识别哪个没有产生。
但是,您建议您自己将看门狗写为任务,所以在重新启动之前,看门狗肯定可以识别饥饿的任务吗?您可以将其存储在热重启后仍然存在的内存中,或通过调试接口发送。这样做的问题是饥饿的任务可能不是有问题的任务:您可能想知道最后几个任务切换(和时间)以便确定原因。
一个简单的餐巾纸背面方法将是这样的:
int8_t wd_tickle[NUM_TASKS]
void taskA_main()
{
...
// main loop
while(1) {
...
wd_tickle[TASKA_NUM]++;
}
}
... tasks B, C, D... follow similar pattern
void watchdog_task()
{
for(int i= 0; i < NUM_TASKS; i++) {
if(0 == wd_tickle[i]) {
// Egads! The task didn't kick us! Reset and record the task number
}
}
}
你的系统是如何工作的?我总是结合使用软件和硬件看门狗。让我解释...
我的示例假设您正在使用抢占式实时内核,并且您的 cpu/微控制器中有看门狗支持。如果在一定时间内没有被踢,该看门狗将执行重置。你想检查两件事:
1) 周期性系统定时器(“RTOS 时钟”)正在运行(如果没有,“睡眠”之类的功能将不再起作用,您的系统将无法使用)。
2)所有线程都可以在合理的时间内运行。
我的 RTOS (www.lieron.be/micror2k) 提供了在 RTOS 时钟中断处理程序中运行代码的可能性。这是您刷新硬件看门狗的唯一地方,因此您确定时钟一直在运行(如果不是,看门狗将重置您的系统)。
在空闲线程(始终以最低优先级运行)中,刷新“软件看门狗”。这只是将变量设置为某个值(例如 1000)。在 RTOS 时钟中断(启动硬件看门狗的地方)中,递减并检查该值。如果它达到 0,则意味着空闲线程没有运行 1000 个时钟滴答并且您重新启动系统(可以通过在中断处理程序中无限循环以让硬件看门狗重新启动来完成)。
现在回答你原来的问题。我假设系统时钟一直在运行,所以是软件看门狗重置了系统。在 RTOS 时钟中断处理程序中,您可以进行一些“统计收集”,以防出现软件看门狗情况。无需重置系统,您可以查看每个时钟滴答(问题发生后)正在运行的线程,并尝试找出发生了什么。这并不理想,但会有所帮助。
另一种选择是添加多个不同优先级的软件看门狗。让空闲线程将变量 A 设置为 1000,并让(专用)中等优先级线程设置变量 B。在 RTOS 时钟中断处理程序中,检查这两个变量。有了这些信息,您就知道循环线程的优先级是高于“中”还是低于“中”。如果您愿意,可以添加第三个或第四个或您喜欢多少个软件看门狗。最坏的情况,为每个使用的优先级添加一个软件看门狗(尽管会花费你尽可能多的额外线程)。