来源:公众号【鱼鹰谈单片机】,ID :emOsprey
大家好,我是鱼鹰。
今天和大家聊聊 MCU APP 调试相关的话题。大家都知道,鱼鹰非常热衷于使用在线调试解决问题,很少使用串口日志去解决开发中的问题(售后问题就得看日志了),所以当同事问我借串口模块时,只能回复咱不用这个(傲娇脸)。
鱼鹰的仓库也记录了一堆的调试经验,包括但不限于:
1、linux下应用程序 VSCode + gdb 调试
2、MCU + Keil 调试(这些内容基本都在公众号免费分享了)
3、MCU + Openocd + VSCode 调试
4、容器下调试 MCU 一条龙服务。
多说一句,对于串口模块,实际上不管是 Jlink(需要开启该功能),STLink(老版可能没有),DAPLink,其实都有自带,只要是 TTL,都能用。
对于 Boot 而言,和普通的裸机调试没什么区别,因为它必定运行在 FLASH,也没有什么特别的。
但是 APP 不同,它有很多 Boot 没有的东西,比如需要对它进行 CRC 校验,需要加文件头,或者在 CRC 校验值,如果 CRC 未通过,根本没法运行到 APP,更不用说调试了。
特别搞笑的是,之前面试官还问鱼鹰,RTOS 也能使用在线调试吗?
我只能笑笑不说话。
其中最重要的是关于 CRC 校验,很多时候,就卡在这一步,导致下载的程序不被 Boot 接受,从而停留在 boot 阶段。
其实鱼鹰一开始给公司做的升级方案是,将 CRC 校验留给 APP,也就是自己校验自己(这是安规要求,而且 boot 早就开发好了的情况下)。这种情况下,调试 APP 也是比较简单的。
但后面遇到的升级方案,大多数是由 Boot 进行 CRC 校验。而这也是最合理的方案,也是很难进行 APP 调试的关键。
本文将重点讨论这一种。
关于 CRC 值存储的位置,一般有3种方案:
1、放置在 APP 固件最后
2、在APP 固件前面加个头,包含 CRC 和 设备 ID 之类的。这个头,可能并没有放在 APP 存储位置的前面,而可能是其他的地方。
3、升级完后,放在 FLASH 某个固定位置。
不管哪一种方案,一定要保证一点,CRC 的值是由发送方直接给的,而不是 boot 自身计算出来的。
所以调试 APP 的第一步是,找到 CRC 到底放在哪里。
在我们不熟悉代码的情况下,我们可以直接先擦除整个扇区,然后烧录boot,升级 APP,最终对比单独的 Boot 和升级APP后的区别即可找到存放的 CRC 位置。
另一个就是要搞定 CRC 校验的算法,这个只能到代码里面找答案了,这里可以让 AI 分析一下。
还有,如果是加头或者其他方式,可能对这块数据本身CRC校验,或者里面包含了 APP.bin 的长度信息,这些都要知道位置。
总之,先搞定存储位置,再搞定 CRC 算法,前期的调研就 OK 了。
事情也成功了一半。
接下来就是如何生成 boot 所需的数据了,这里可以用 srec (功能强大的 HEX 开源转换工具,你值得拥有)这个专用的文件操作工具,也可以借助强大的 Python 完成,这里鱼鹰建议 Python,更灵活,把需求提给 AI 就行。
存放 CRC 的地方可能含有其他的数据,因此直接拷贝你升级后的数据即可,然后通过 Python 修改和 APP 有关的数据,比如 CRC ,长度,设备 ID 等,而这些数据的改变,又会导致自身的 CRC 需要更新。
总之,处理完后,就可以得到一个纯二进制数据(这里建议使用同一个 APP 进行分析,这样很多值是固定的,最后使用不同 APP 进行测试与对比)。
但是这个二进制数据没有位置信息,因此需要转成 Hex。
最后,将App.hex 和前面的数据镜像合并,注意是 Hex 合并(Python也可以),而不是 bin,否则如果 CRC 存储的位置离 APP 很远,会导致生成的 bin 很大,最终导致下载很慢。下载的时候选择扇区擦除。
接下来的关键,就是配置 IDE 了,如 keil 或者 VSCode + CortexDebug,让它首先进行下载工作,然后 Attach 到这个运行的程序。
如果这一步没做好,前面的工作都是白费,可以说算是临门一脚的事。时间原因,下次有机会再分析喽。
鱼鹰该去做饭了。
180