不复位MCU直接调试运行程序,让bug闻风丧胆

大家周末好呀,文章转自bug菌的公众号,文章介绍步复位情况下调试bug,希望对大家有用。

1

调试窘境

经常有朋友在开发中遇到这样的窘境,当单片机程序运行异常以后,由于调试信息做得并不是很全面,导致相应的问题场景非常难分析。

当时的你肯定会叹息道:"要是我一直插着仿真器就好了,这个bug还不是分分钟的事~",每个人都想有颗“后悔药”可吃,然而遇到这种场景也并非绝路。

主要是因为大部分朋友插上仿真器以后,调试器在启动时会发出硬件重置信号,应用程序当前的状态都会丢失,包括内存变量、状态等等,对于一些长时间的偶发故障调试更不太友好。

此时此刻有一种调试需求是朋友们非常想要的:一旦程序出了问题,我只需要插上仿真器,目标硬件不会复位,而是与我当前所调试的程序同步,类似于仿真程序的时候的“全速运行”,然而通过添加断点,便可查看程序具体的运行状态,内存等等信息,让bug闻风丧胆。

很多朋友可能也只是想想,毕竟大家都比较专注程序中的应用逻辑,而忽略了调试器这块的功能研究,自己就定义这种调试方式比较难吧或者没有这种功能而不了了之。

大家调试的需求也是一种用户需求,相应工具的开发厂家会根据相应的需求进行开发,所以该功能在大部分主流的开发工具中都已具备,下面我们就验证一下这个功能的可行性:

2

配置过程

软硬件环境:

IDE版本: Keil V5.36.0.0  (IAR等主流IDE工具均可)

调试工具版本: jlinkV9  (目前主流调试器基本都已具备)

MCU型号:STM32F429

展示方法:

直接采用全局变量进行累加然后进行串口输出,如果重新连接目标平台,串口输出的全局变量还是顺着之前的计数进行累计,便可以证明MCU没有复位而是从程序运行处开始仿真。

代码实例如下:

1#include "led.h"
 2#include "delay.h"
 3#include "key.h"
 4#include "sys.h"
 5#include "usart.h"
 6
 7uint32_t Cnt = 0;
 8
 9/******************************
10*** Function:测试程序
11*** Author  :公众号:最后一个bug
12******************************/
13
14int main(void)
15{        
16
17    u16 times=0;
18    delay_init();            
19    NVIC_Configuration();   
20    uart_init(9600);     
21    while(1)
22    {
23        times++;
24        if(times%30==0)
25        {
26            printf("golobal data :\r\n",Cnt++);  
27        }
28        delay_ms(10);   
29    }    
30}

步骤如下:

1、首先编译好工程,把将要实验的程序完整的烧录一次,必须要保证MCU中正在运行的程序与所要仿真的工程同步,这样调试器通过调试接口获取的程序运行位置信息才能与工程代码中的位置一一对应。

2、去掉启动时加载应用程序,并加入Loader.ini文件,主要用于加载已经编译生成的.axf文件到Keil中,从而进行调试。

1ac775fc2202333f4b5bf4f5199429e0.png

c91d00625938943deea8a3865bb8c105.png

可能你该问了.axf文件是什么?

其实axf全称为:ARM Executable File,该文件包含bin代码和大量的调试信息,这些调试信息可以被调试器使用,从而定位到我们的C代码。

3、在调试器Setting选项中,去掉"Reset after Connect",为了调试器链接以后不进行复位动作,从而破坏现场。

b4caef29cc8fe1b76435bde886b79b9a.png

4、接下来Update Target Before Debugging选择需要去掉,直接调试运行目标不需要勾选,也就不会更新Flash。

a78b2f21940355cfed41ccf9fe69aeee.png

3

验证结果

直接在全局变量打印输出的地方放置断点,程序运行到断点处正常停止。

aa3fa630f4574287234299e9b0843465.png

然后我们看一下输出的串口信息数据是否连续,如果打印的数据连续说明程序没有复位,接着反正前正在运行的程序往下执行。

b5d1e3ea69d79e862f1e98f804bfd9f0.png

通过串口接收数据时间戳可以区分断点和调试运行数据,并且数据都是连续的,说明此调试过程在无需硬件重置即可连接到正在运行的目标。

4

思考

以前我了解到很多朋友觉得仿真程序是把运行程序通过加工调试信息,然后全部下载到MCU,然后进行仿真调试。

这种想法在目前的在线调试中是不太正确的,只需要知道程序运行到哪里,并且查看内部信息、控制程序的运行等,便可以反推定位程序当前所运行的位置和状态,这也是本文开头的前提条件,烧录到Flash上的固件与你即将要仿真的代码工程要保持同步,否则接下来的调试当然就是牛头不对马嘴。

仿真并不是什么神秘的东西,你可以认为就是与MCU内部仿真模块进行通信,从而完成调试信息的交互和控制。

最后

好了,今天就跟大家分享这么多了,如果你觉得有所收获,一定记得点个~

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MCU的sprintf重定向是指在嵌入式系统中使用sprintf函数时,将其输出重定向到其他设备或接口,而不是默认的标准输出设备。 在嵌入式系统中,通常没有显示器或终端用于输出信息,因此无法直接使用printf或sprintf函数来打印调试信息。为了解决这个问题,可以通过重定向将sprintf函数的输出发送到特定的设备或接口,以实现调试的目的。 重定向的实现方法会根据具体的嵌入式系统而有所不同。一种常见的方法是使用串口作为重定向的目标设备。在这种情况下,可以通过配置串口相关的寄存器和控制寄存器,将串口的发送功能与sprintf函数关联起来,以达到重定向的效果。这样,当调用sprintf函数时,生成的字符串将被发送到串口,并通过串口线路传输到其他设备或接口。 另一种常见的方法是使用操作系统提供的文件系统接口进行重定向。在这种情况下,可以将sprintf函数的输出写入特定的文件或管道中。通过操作文件系统接口能够将输出保存在文件中或者通过管道传输到其他进程或设备。 通过这种重定向的方式,我们可以在嵌入式系统中方便地使用sprintf函数进行调试和输出信息。不同的系统和场景可能会有不同的实现方法和配置方式,但基本的原理是将sprintf函数的输出重定向到特定的设备或接口,以实现信息的输出和调试的目的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值