心得小结,关于注重加强MCU下调试能力的意识

 

这两个月没有怎么更新博文,最近换工作了,根据新工作安排,大半年内都做MCU开发(就不要叫单片机了,太老土了)。

入职新工作了,需重构拳头产品的软件,所以每天加班加点。

 

单片机与linux应用开发,开发过程中有什么区别之近日个人感悟:

第一点,单片机往往配合仿真器调试,linux应用开发往往使用串口打印,或者经由以太网的gdb调试、生成coredump文件来定位常见的段错误。

linux应用开发调试手段,可以参考我的博文: 

嵌入式交叉编译GDB,结合vscode图形化调试C和C++代码 coredump定位段错误

第二点,单片机开发会涉及中断,而linux应用开发不会涉及中断的概念。

(linux驱动开发会涉及中断,但是一般驱动开发工作量少,某个SPI或IIC外设的驱动开发好了以后就可以一直被使用)

 

近日遇到问题,迷糊了挺久,最后得以解决,在此总结心得。

我的硬件环境:        MDK-ARM下调试stm32

我的软件环境:        RT-Thread          PS:以前也常在业余时间了解RT-Thread,这次终于有机会用它做项目了,跃跃欲试。

我遇到的问题: 

翻车在一个GPIO上 开启pin中断 导致程序卡死

具体描述:开启pin中断,就会导致程序卡死,rt_pin_mode()参数配置调整了几次也没用。 翻车在一个GPIO上了。

     硬件触发的信号是正常的高低变化的信号,示波器看过。 同时,我当前使用的是gitee-master版本,不是发布版。

 

1. 仿真后运行程序,外界给入高低电平的信后,这时程序就会卡死,之后停止运行程序,MDK下并没有箭头指示当前C代码运行到哪里去了。

但是这里显示PC是0x08004EE4.  

我不知道是否可以根据此PC值定位出当前运行到哪里,以及如何根据此PC值定位出当前运行到了哪里。

需要补充一个技能:根据当前的汇编代码定位出当前运行的C代码。

 

2. RT-Thread版本,当前是 gitee-master版本,不是发布版。这个有点疑虑,不排除怀疑gitee-master版本的可靠性。但是基本认为gitee-master版本是可靠的。如果实在不行,可以换成release版本去试试。

 

由于能力有限,目前这个仿真效果对我来说,没什么参考意义,所以我就只能想其他办法了。

图省事,我直接在原工程上屏蔽了其他也操作了该PIN操作相关的地方,然后再次测试,还是卡死。《== 假设这是我改的一个测试程序,称呼其为测试程序1吧。

 

问题解决后,回顾该调试过程,重现了下该测试过程

这里我犯错了,因为总共就涉及到三四句代码而已,我图省事,直接在原工程上屏蔽一些代码然而当时我确实没有屏蔽完全!那么这样,造成的最终效果还是卡死!

即我在修改出测试程序1的过程中又犯下了低级错误, 所以导致我又加深了对这个难点O的疑惑。

展示下我的低级错误:

我的外部中断是配合一个人感传感器使用的,由于manager_initialization()函数内没有屏蔽掉人感相关代码,间接导致device_human_sensor_init函数被调用,如下图所示,
这里又再次配置了该外部中断脚。 

编译程序并烧录,由于没有进行规范的外部中断脚的配置,造成的最终效果还是卡死!

 

 

接着说当时的调试,偶然又发现如果烧录该工程到0x08000000的flash起始地址上,我的中断可以正常跑。

我的项目是使用了OTA的,我当前所编写的是APP代码,所以我就开始怀疑是我的OTA或者称为IAP导致的这个问题。

Q群讨论,知道了如何查看当前的异常向量表的地址,如下图

 

重新实操了下,回顾再次回顾该步骤调试过程: 

我当时肯定又进行了一些代码的修改,假设这是测试程序2 ,测试程序2直接烧录到0x08000000后外部中断正常,之前测试程序1是个有问题的程序,当时这个测试程序2恰好又被我改对了而已!

我认为当时这个测试程序2作为APP,烧录到我的APP的0X08020000这个地址肯定也是可以正常运行和响应外部中断的。

 

所以当时,我又没能调试好我的这个中断响应后卡死的问题。

 

后来是怎么调试好的呢?接着说

因为我使用的外部中断脚是PD11,那么它的中断服务函数归属于EXTI15_10_IRQHandler

我一看,是个弱定义,又没搜索到函数定义,虽然我以前还阅读分析过RT-Thread的GPIO驱动框架的源码,但那都是一年半之前的一点兴趣爱好而已,早就忘干净了。

于是又没继续下去了,现在回顾之前在MDK下的搜索方式,正确的方式应该是这样:

全都勾选上。

我当时只勾选了左侧两个,所以没有搜索到RT-Thread的drv_gpio.c内的 EXTI15_10_IRQHandler()函数定义。

 

后来我在此处打上断点,然后外界给入高低电平,发现可以进入到这里!一步步运行, 能进入我的中断服务程序,在中断服务程序内打断点,发现一直在里面打转出不来。

 终于定位问题了。

 

最后的问题原因在于:

中断服务程序内一个链表头忘记初始化了,导致ISR内没出来,双向循环链表没初始化,for循环出不来了。

 

 

总结: 

1. 习惯要好。 如果要编写测试程序,哪怕只是三四句代码,最好也重新搞一个工程,或者,假设我要修改main函数,就屏蔽掉原来的main函数,重新搞一个main函数,而不是直接在main函数内部去修改。

并且最好做到屏蔽掉无关的代码,即使自己以为很有把握,但是一句话说得好:难得糊涂。一糊涂可就完事了,完蛋了。难得糊涂是不被允许的。

 

2. 要注重加强打断点调试,遇到相关的问题,从源头开始打断点,一步步仿真执行下去。仿真不是点击一个开始允许,和一个停止运行。

  例如我遇到的问题是STM32的基于HAL库的中断问题,那么就从对应引脚的HAL库中断服务函数处开始设置第一个断电,然后一步步进去。

  MDK的各个调试按钮、各类观察窗口要熟悉。

 

3. 单片机上也会遇到段错误,没有coredump咋搞? RT-Thread官网介绍的CmBacktrace可以了解一下。

 

 

 

 

.

posted @ 2021-07-03 08:53  一匹夫  阅读(278)  评论(0编辑  收藏  举报