硬汉嵌入式论坛

 找回密码
 立即注册
查看: 615|回复: 10
收起左侧

[客户分享] 记一次"死机"调试

[复制链接]

102

主题

573

回帖

894

积分

金牌会员

积分
894
QQ
发表于 2025-7-8 18:07:19 | 显示全部楼层 |阅读模式
老化测试反应电机运行500次后会卡死,基本上挂机一天不到就能复现。


我首先移植了一下cmbacktrace,让他在进入硬件错误后移植打印报文。

复现问题后,在保证供电的情况下,把电机外壳拆开,让jlink调试线暴露出来。
接上rttview发现没有任何打印,所以就可以排除是进入硬件错误导致的问题。

连上jlink,输入connect,再输入h可以打印当前pc指针:
微信图片_20250708175720.png

可以看到当前pc指针在0x08009e2e处。
同时用mem打印一下sp指针的栈。
截图之后回到工位上,拿一块板子进入仿真,用show code at address,找到这个pc指针地方的代码:
Snipaste_2025-07-08_17-59-15.png

阅读这部分掉电保护的代码,得知根本原因就是误触发进入了这个while(1)导致的。


这部分逻辑应该写的不太合理,需要重新写,不让它被误触发之后应该就可以解决这个疑似“死机”的bug
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-10 09:09:38 | 显示全部楼层
谢谢分享。
回复

使用道具 举报

6

主题

306

回帖

324

积分

高级会员

积分
324
发表于 2025-7-10 10:56:53 | 显示全部楼层
其实大家不知道的是,当你的MCU出现异常时,可以中途进行调试的,可以让IDE不复位芯片,此时能看到程序停在什么位置,大多数情况下十分好用,如果用KEIL要设置一番,比较麻烦,我之前用SEGGER的Q-ZONE软件,不需要特殊设置。非常好用。
回复

使用道具 举报

2

主题

29

回帖

35

积分

新手上路

积分
35
发表于 2025-7-10 13:41:48 | 显示全部楼层
好东西!!!感谢,感谢,之前调试问题使用栈回溯,都是自己利用仿真器然后手动分析,请问一下,你上面的“连上jlink,输入connect,再输入h可以打印当前pc指针“下面的图打印出来的东西,是要移植这个cmbacktrace库之后才能这样操作吗?
回复

使用道具 举报

7

主题

158

回帖

179

积分

初级会员

积分
179
发表于 2025-7-10 14:23:56 | 显示全部楼层
真好 异常了还能用调试,我解决异常都是靠联系上下文 ,猜想解决
回复

使用道具 举报

16

主题

76

回帖

124

积分

初级会员

积分
124
发表于 2025-7-10 14:48:48 | 显示全部楼层
fxyc87 发表于 2025-7-10 10:56
其实大家不知道的是,当你的MCU出现异常时,可以中途进行调试的,可以让IDE不复位芯片,此时能看到程序停在 ...

你是说 ozone 吗
回复

使用道具 举报

25

主题

232

回帖

307

积分

高级会员

积分
307
QQ
发表于 2025-7-10 16:16:52 | 显示全部楼层
死循环还是不要到处写比较好,我的错误处理统一引到两个函数,这样就算出错误也可以依据实际情况调整这两个函数进行排查

[C] 纯文本查看 复制代码
/**
 * @brief 软件产生错误的时候将跳转到这里,将错误信息存入存储介质,不进行循环
 * @param file 源代码文件名
 * @param line 代码行号
*/
uint32_t SoftErrorHandler(char *file, uint32_t line)
{
    /* TODO : 代码报告源代码文件名和代码行号存入存储介质 */

    uint8_t StrSend[30];
    uint8_t StrSendLen;
    UartWrite(&tUart1, (uint8_t *)"Wrong parameters value: file ", sizeof("Wrong parameters value: file"));
    UartWrite(&tUart1, (uint8_t *)file, String4Len((uint8_t *)file));
    UartWrite(&tUart1, (uint8_t *)" line", sizeof(" line"));
    StrSendLen = LIB_NumToAscii(line, 0, 0, StrSend);
    UartWrite(&tUart1, StrSend, StrSendLen);
    UartWrite(&tUart1, (uint8_t *)"\n", 1);

    return 0;
}

/**
 * @brief 硬件产生错误的时候将跳转到这里,将错误信息存入存储介质,并进行死循环
 * @param file 源代码文件名
 * @param line 代码行号
*/
void HardErrorHandler(char *file, uint32_t line)
{
    /* TODO : 代码报告源代码文件名和代码行号存入存储介质 */

    uint8_t StrSend[30];
    uint8_t StrSendLen;
    UartWrite(&tUart1, (uint8_t *)"Wrong parameters value: file ", sizeof("Wrong parameters value: file"));
    UartWrite(&tUart1, (uint8_t *)file, String4Len((uint8_t *)file));
    UartWrite(&tUart1, (uint8_t *)" line", sizeof(" line"));
    StrSendLen = LIB_NumToAscii(line, 0, 0, StrSend);
    UartWrite(&tUart1, StrSend, StrSendLen);
    UartWrite(&tUart1, (uint8_t *)"\n", 1);

    if(line == 0)
    {
        return;
    }

    while(1)
    {
    }
}
回复

使用道具 举报

102

主题

573

回帖

894

积分

金牌会员

积分
894
QQ
 楼主| 发表于 2025-7-11 08:54:54 | 显示全部楼层
老陈_cmm 发表于 2025-7-10 13:41
好东西!!!感谢,感谢,之前调试问题使用栈回溯,都是自己利用仿真器然后手动分析,请问一下,你上面的“ ...

不需要。
回复

使用道具 举报

102

主题

573

回帖

894

积分

金牌会员

积分
894
QQ
 楼主| 发表于 2025-7-11 08:58:31 | 显示全部楼层
yono 发表于 2025-7-10 16:16
死循环还是不要到处写比较好,我的错误处理统一引到两个函数,这样就算出错误也可以依据实际情况调整这两个 ...

回复

使用道具 举报

102

主题

573

回帖

894

积分

金牌会员

积分
894
QQ
 楼主| 发表于 2025-7-11 09:04:12 | 显示全部楼层
本帖最后由 会飞的猪_2020 于 2025-7-11 09:05 编辑
mygod 发表于 2025-7-10 14:23
真好 异常了还能用调试,我解决异常都是靠联系上下文 ,猜想解决

为了能调试连jlink付出了很大的努力。。

电机在高处,需要用梯子爬上爬下,然后不能断电,需要带着电拆外壳,拆完后,再小心翼翼的连上jlink生怕GND,3.3V接错复位了。
幸运的是,这是供电48V的电机,不是220V的电机。不然我就不敢拆壳了这样子调试了。
回复

使用道具 举报

1

主题

11

回帖

14

积分

新手上路

积分
14
发表于 2025-7-17 17:18:46 | 显示全部楼层
厉害,我一般也是用楼上说的,进入debug不要单片机复位,就可以看到停在那里了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 06:01 , Processed in 0.052728 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表