如何调试看门狗超时问题

12

我在我的微控制器中有一个看门狗,如果不被“踢”,它会重置处理器。我的应用程序运行一段时间后会重置,因为看门狗没有被“踢”。如果我逐步执行程序,它就能正常工作。

有哪些调试方法?

编辑: 结论: 我找到错误的方法是使用看门狗面包屑。

我使用的是具有高和低ISR向量的PIC。高向量应该处理LED矩阵,而低向量应该处理定时器滴答声。但我把两个ISR处理程序都放在了高向量中。因此,当我禁用LED矩阵ISR且需要服务的定时器滴答声ISR时,处理器将卡在低ISR中处理定时器滴答声,但定时器滴答声处理程序不存在。

面包屑将我的搜索范围限制在处理LED矩阵的函数上,特别是禁用LED矩阵中断。

9个回答

12

在代码中添加一个未初始化的全局变量,并在主要函数调用之前和之后设置不同的值。

在 main 函数开头设置断点。

当处理器重置时,全局变量仍将保留其最后一个被设置的值。继续添加这些“面包屑”以缩小问题所在的函数范围。


1
只是为了帮助来这里的任何人而补充一下: “未初始化的全局变量”将需要C编译器的一些特殊语义。标准规定,即使未对未赋值的全局变量进行初始化,它们也必须被初始化为零。因此,通常需要这些变量的属性,例如avr-gcc的“.noinit”。 - FourtyTwo
非常好的答案和方法。我进一步保存了整个堆栈以进行分析,有关详细信息请参见下面的答案(https://dev59.com/onRB5IYBdhLWcg3wUFvB#73327611)。 - mvds

4
许多软件看门狗在连接调试器时会自动禁用(以防止调试器暂停应用程序时重新启动)。
那么,以下是一些基础知识: 这是一个多线程应用吗?您使用实时调度程序吗?如果是这样,请确认您的看门狗任务是否被饥饿状态。 确保您的看门狗任务不会被任何东西卡住(等待信号量,等待消息等)。有时,函数可能会以您意想不到的方式阻塞;例如,我目前正在处理一个 Linux 平台,在该平台上可以轻松地使 printf 阻塞。
如果它是单线程的,则分析器可能会帮助您识别时间问题。
如果这是一个新系统,请确保看门狗正常工作;测试简单的代码,只需触发 WD 然后在无限循环中休眠。

每当有新的仿真板用于调试时,我首先确保断开 WD 单元! - MS.

2
我使用基于状态的编程,一个我一直想要采用的技巧是为当前状态在二进制中保留一个输出端口。然后连接逻辑分析仪并查看状态更改的时间。你可以在这里做类似的事情:按照Robert所说创建一个全局变量,并在关键点更改其值 - 最好使用立即将端口值设置为当前状态的函数(即changeState(nextState);)。在进入踢狗函数的时候更改状态,然后在离开函数之前将其改回先前的状态。你应该能够从没有被踢的函数中看出来,然后你就可以解决这些问题了。
祝你好运,听起来像是一个时间问题,而这些问题很难解决。

2
通常看门狗任务/线程运行在低优先级上。如果看门狗没有被触发,原因可能是处理器正在忙于做其他事情,可能是不应该做的事情。
在处理器重置前,对每个任务/线程的执行上下文(本地堆栈、调度状态等)进行转储将非常有用。经过一些努力和运作,您将能够确定是什么阻止了看门狗任务触发计时器。

2

我会使用额外的输出引脚,在代码中适当的位置设置高电平然后低电平来限制我正在查找的范围。然后,我会在数字示波器或逻辑分析仪上跟踪它。这相当于另一个帖子提到的面包屑方法,但您将能够更好地与复位脉冲进行时间相关性。


1
你可以在代码中插入一个while循环,并在循环内切换LED。这是检查板子是否重置的有效方法。

0

在优秀的被接受答案(https://dev59.com/onRB5IYBdhLWcg3wUFvB#661900)的基础上,为了我的应用程序,我进一步研究了看门狗复位后检查RAM的方法。由于这段文字对于评论来说太长了,所以我将其作为一个额外的答案添加:

我们的应用程序是由自定义引导程序前缀的,该引导程序提供了一些功能,例如OTA固件更新。通过将此引导程序的初始堆栈指针设置为RAM末尾之前的1 kb,足够的堆栈仍然留在RAM中,以便在主固件被看门狗重置时重构回溯。然后,引导程序需要识别重启原因是看门狗,并将RAM的最后1 kb复制到某个指定的闪存区域,从中可以恢复它。

重构回溯有点麻烦,因为没有PC可以从中开始,因此实际上应该从底部向顶部手动展开堆栈,并且可能需要进行一些有教育意义的猜测,以确定应用程序停止的位置。(这不一定是看到过时数据并且展开失败的地方!)

这种方法帮助我系统地找出了一个非常零散的问题。要在堆栈上记录其他“面包屑”,只需插入诸如:

__attribute((unused)) volatile uint32_t _state[4];
_state[0] = 0x57a11ed; // magic value to aid manual unwinding
_state[1] = RCC->CSR;
_state[2] = count++; // maybe we're in a runaway loop?
// etc.

在没有单独引导加载程序的应用程序中,初始堆栈指针可以设置为 RAM 结束前的 1 kb,然后在正常启动后更改为 RAM 结束位置(这当然是非常复杂的!)。然后,在发生看门狗复位的情况下,应用程序可以简单地存储/传输 RAM 的最后 1 kb 以供离线分析。

嗨@mvds!很抱歉在这里留言(我不知道其他联系方式),但我看到了你在brainf ***中的回答,想知道是否有一种方法可以去除数字之间的额外空格,使它们更加紧密。谢谢!(一旦回复/阅读,消息将被删除) - DialFrost
嗨 @mvds!很抱歉在这里留言(我不知道其他联系方式),但我看到了你在这里的brainf***的回答,想知道是否有办法去掉数字之间的额外空格,让它们更靠近一些。谢谢!(一旦回复/阅读后,消息将被删除) - undefined
@DialFrost 我认为你是对的,如果不输出空格,你可能可以节省一些字符(但不多)。带有空格的格式是用于数字时钟代码高尔夫比赛的。 - mvds
我知道这是一个奇怪的请求,但你介意试着做一下吗?(如果你不想做也没关系) - DialFrost
@DialFrost 绝对是我所接到的最奇怪的请求。但是真的...为什么? - mvds
@DialFrost,我刚刚研究了一下,这是一个相当简单的修复,你为什么不自己试试呢? - mvds

0

反复质疑你所做出的每一个假设:

  • 确保看门狗已被触发(我不知道处理器上的日志记录设施)。
  • 确保看门狗在被触发时不会重置处理器。

同时,思考“逐步执行”和单独运行之间的差异;时间限制肯定很重要。


0
你可以将strace(选项-p)附加到正在运行的进程上,观察它何时停止向打开的文件描述符/dev/watchdog写入。
使用选项-e筛选strace的输出。
有关详细信息,请参阅手册页面。

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