STM32单片机在开发过程中很多大一部分时间在调试与修改程序上,尤其是对于一些异常问题的抓取与分析,因此Keil5的在线调试功能便完美的契合了STM32的调试需求,各种调试手段与方法也层出不穷。
本文着重从基本的调试原理、功能构件及技巧上进行分析,系统性的帮助读者了解在线调试功能以及解决调试中的问题,也可为后期的调试提供一些参考。
软件:keil5
调试器
keil5支持的调试器
常用调试器 J-LINK/ST-LINK/U-LINK/DAP-CMSIS
J-Link
J-Link是SEGGER公司为支持仿真ARM内核芯片推出的仿真器,支持SWD/JTAG.下载速度高达1 MByte/s,最高JTAG速度15 MHz,目标板电压范围1.2V –3.3V,5V兼容,自动速度识别功能,监测所有JTAG信号和目标板电压,完全即插即用。
ST-LINK
ST-LINK是ST(意法半导体)提供的STM8和STM32微控制器在线调试器和编程器。单线接口模块(SWIM)和JTAG/串行线调试(SWD)接口用于与位于应用板上的任何STM8或STM32微控制器进行通信,低速时为 9.7 KB/s,高速时为 12.8 KB/s。STM32应用使用USB全速接口与STM32CubeIDE软件工具或来自第三方的集成开发环境进行通信。
U-LINK
ULINK调试器由美国Keil Software公司(已属于RAM)提供的一种调试下载器,通过PC的 USB端口与目标系统连接(通过JTAG接口,Cortex调试器,或者Cortex调试器+ETM连接器)。使用ULINKpro独特的流跟踪技术,你可以下载、调试和分析应用程序。支持Cortex-M串行查看器(SWV)数据和时间跟踪,速度高达100Mbit/s(曼切斯特模式),支持Cortex-M3和Cortex-M4指令跟踪(ETM),速度高达800Mbit/s,独特的流跟踪直达PC机,提供无限制Trace缓存,高速USB2.0(480Mbits/s)即插即用,JTAG时钟速度达到50MHz,支持Cortex-M设备运行速率达200MHz,高速Flash下载器,速度达到1Mbytes/s,与Keil μVision IDE和Debugger无缝隙集成。
DAP-CMSIS
CMSIS-DAP是ARMmbed官方开源的一款下载调试器,但凡是支持CMSIS协议的单片机都可以通过该进行模块进行下载。下载速度450KB/s(野火DAP参数)
打开keil仿真调试模式(记得使用前配置好并连接调试器)
初始的默认串口布局如下
打断点查看变量值
复位、停止程序
单行/单步调试操作
参照许多教程进行了stm32F1/F4的测试,发现通过以下步骤基本满足测量不发生异常。(测试工具为J-LINK/ST-LINK的sw接口连接)
设置仿真参数
打开Trace界面,勾选Enbale使能,设置时钟为单片机运行的主频(一般STM32F103为72Mhz,F407为168Mhz)
1打开仿真界面,2打开内核寄存器窗口,3将寄存器窗口保持固定在如图所示界面时钟显示(计时的时钟就是此处的Sec),4鼠标右键弹出菜单,5复位t1/t2定时。
断点测量代码运行时长。此处要先关闭固定窗口刷新(代码运行同时刷新变量窗口数据,会影响测量时间的准确性),设置断点后,开启代码运行,下一次测量时应复位测量计时器T1/T2.
通过下图中序号所示即可打开相应的外设寄存器窗口,图中示例了串口1的寄存器查看,同样的中断设置/时钟分频/定时器均可通过此查看。甚至可以通过数据的变动与否判断外设是否正常打开。
输出IO控制
io端口输出初始化完成后,可直接操作ODR寄存器中端口来控制输入输出,效果和标准库函数中的 GPIO_SetBits
/GPIO_ResetBits
一样。
输入IO检测
当某个单片机IO口设置为输入时,可直接通过输入寄存器查看电平状态即使代码处于断点停止状态也可以查看(断点停止有时需要手动点击toolbox中的更新窗口按钮),在项目中可用来检测外部开关信号等省去了万用表测电压。
串口数据寄存器直接操作
这里有一个有意思的现象,直接在外设寄存器上操作串口实际能发送两个字节,而通过变量WATCH窗口以变量形式操作能正确发送一个字节。
中断控制
Keil5软件帮助文档中指明了断点有三种类型:存取断点,执行断点,条件断点。
存取断点:某一个变量度或者写操作时执行断点操作。
执行断点:执行到代码某个位置时产生断点操作。一般直接在代码左侧打的断点就是此类断点,用的最多。
条件断点:当满足某个表达式时,如某个变量==0x01时执行断点。
官方示例说明
除直接在代码左侧设置执行断点外,其余断点需要通过断点管理窗口来实现。
仅操作1处表达式,表达式为某个函数地址时为执行断点,Count表示执行次数。
1和3处同时操作时表示为存取断点,3中SIZE表示存取变量的字节大小,Bytes与Objects的区别在于单一变量与结构体的不同。当存取某个变量或者结构体中某个成员时使用Bytes,存取某个结构体时使用Objects。
仅操作1和2为条件断点,如变量==、>=某个值时执行printf指令打印变量值。注意此处的printf仅输出到调试界面的Command窗口。command指令的执行并不会使程序中断停止,相当于此处为软件断点。
断点管理窗口中的断点需要停止代码执行才能正确设置。
建议在Watch中右键添加断点。
字节写断点
结构体写断点
当st_abc被写两次时中断程序执行。
代码左侧直接红色断点与断点窗口表达式处直接填写函数名称效果一样。Count表示执行次数,可设置执行某个函数Count次后中断停止。
此处用变量值作为条件判断演示一下条件断点(因为涉及到了变量存取,所以这里实际为存取断点)实现大概过程。
条件打印输出过程,注意printf格式为printf("%d\n",a)
,后边的\n必须加,还有打印频率不要太快,条件断点的检测会极大的影响代码的执行效率。
常规操作
右键添加到变量观察窗口,或者直接选中后拖拉变量到窗口。观察的对象比较广泛,全局/局部变量、寄存器、函数地址、数组结构体等,对于局部变量只能在变量的有效局部内才能显示具体数值。
表达式操作
表达式可进行简单的数学运算,甚至可以当做一个简单的进制转换、计算器来使用。如下所示,动态显示random的值减去70000,0xf777转换为十进制。
打断点后,通过回调栈窗口可以看到当前函数的调用情况以及内部变量的值。
当程序封装太多层时可参照如下方式进行一层一层跳转分析。
辅助用法
当存在Hardfault等错误以及程序死循环时,可以通过断点或停止按钮停止程序运行,在回调栈窗口查看调用hardfault的位置,位置不是很准确,但是能反应大概位置,然后通过局部变量的值进行判断异常位置。下边演示了数组越界引起了异常,大概定位到了前后的位置,其它的错误定位可以再研究一下。(数组越界小好像啥事没有,越界很多才会跳转hardfault)
这里插入别人的hardfault的查找操作。
Cortex-M 处理器 hardfault 定位方法和步骤(基于Keil mdk)
command窗口可实现命令行的作用,通过执行命令函数或表达式直接实现查看与修改变量、对象、寄存器及内存。
断点设置
通用命令
内存操作命令
常用的数学函数
使用示例
查看函数地址范围
将command窗口内容形成log文件(放在工程根目录下)
keil5在仿真界面可以自定义按钮执行command命令,并且按钮不会随着编译退出而删除,下次仿真可继续使用。
默认系统会创建一个刷新界面窗口的按钮[Update Windows]
定义按钮语法:
DEFINE BUTTON "button_label", "command"//创建一个button_label的按钮,按钮执行command命令
例:
DEFINE BUTTON "显示random值", "printf (\"random=%04XH\\n\",random)"
也可直接操作寄存器
DEFINE BUTTON "置位", "GPIOF->ODR |= (1<<9)"
DEFINE BUTTON "复位", "GPIOF->ODR &= ~(1<<9)"
按钮的删除
Kill Button 3 /* 移除第3个按钮 */
在调试中虽然不能直接调用想要的程序函数,但可以设置一个标志位实现对函数的控制,函数放在主循环中个,通过按钮改变标位置从而控制函数的执行。
ITM的使用有两个条件:
硬件仿真上使用SW模式,同时将SWO接口(STM32F4是PB3端口)与J-LINK的JTDO端口连接(注意一定要查一下你的J-LINK或者ST-LINK的SWO端口没被做硬件上的上下拉电压限制,还有板子上有没有做啥限制)。
软件上配置如下
ITM配置好后直接添加变量即可,注意得是全局变量且不能超过四个
ITM的另一大功能就是虚拟串口
首先ITM软硬件配置完毕后,修改代码重定向printf函数,也可不重定向直接操作底层的ITM_SendChar (uint32_t ch)
这里直接借用的原串口的重定向函数,直接将底层发送字节的函数放进去就好了(发现也可公用的样子,哈哈)
仿真打开虚拟串口看看效果
(printf可以重定向到debug viewer 和外部串口中,数据时同时更新的)
还可以用来统计进入中断的次数及时间
事件计数(总指令 异常 休眠 存储 折叠指令)
ini文件可解释为一个配置文件,相当于一个.C文件,这个文件的执行本质与仿真时的命令行执行一致(如果觉得不麻烦可以再命令行中敲所有的命令而不用加载ini文件).
ini文件的加载主要在两个地方:
调用ini主要用来生成一些配置,如打开itm端口、生成log、设置断点等功能,下边介绍一下小功能。
按钮
使用任何编辑器新建后缀为.ini的文件,内容如下:
DEFINE BUTTON "显示random值", "printf (\"random=%04XH\\n\",random)"
DEFINE BUTTON "置位", "GPIOF->ODR |= (1<<9)"
DEFINE BUTTON "复位", "GPIOF->ODR &= ~(1<<9)"
这样即可实现按钮的多个定义。
功能函数
命令行不能直接调用函数,与之前讲过的一样,这里的功能函数仅用来调试使用,可以定义一些打印输出,修改变量、外设寄存器值等操作。
使用任何编辑器新建后缀为.ini的文件,内容如下:
FUNC void clearValue(void)
{
random =0;
}
FUNC void LEDON(void)
{
GPIOF->ODR |= (1<<9);
}
DEFINE BUTTON "CLEAR","clearValue();"
DEFINE BUTTON "LED","LEDON();"
以上内容为定义了两个函数清除变量clearValue和打开LED灯LEDON,然后将两个函数做成toolbox按钮。
LOAD %L INCREMENTAL
没有这个也可以不复位调试,但打不了断点
Load Application at Startup
,加载调试初始化配置(2也可省略,直接在仿真后的command窗口输入效果是一样的)
4. 取消调试器连接后的复位(这个建议不连接板子,只插烧写器进行设置,否则会造成复位一次)
效果测试
rtt打印很方便,占用一部分内存空间来实现非在线调试时swd端口的数据输出,一般用在串口紧张时代替串口实现printf调试。具体教程参照网上已有教程就好了。
JLink的RTT使用
串口精灵
下载链接,使用免费功能即可。http://www.ceiwei.com/mt/download/showdownload.php?id=2
线鲨,网络抓包超级方便强大。
下载链接 https://www.wireshark.org/#download
使用教程https://www.cnblogs.com/mq0036/p/11187138.html
使用按键精灵模拟人去操作上位机,用来复现偶发通信异常及流程异常利器,也可用来进行上下位机的压力测试。
下载链接http://www.anjian.com/download.shtml
Matlab,不解释除了生孩子什么都可以干。常用来抓取大量数据然后绘图分析异常数据点。(推荐18版后边的版本,绘图操作直接拖拉即可一行源码都不需要写),MATLAB直接串口接收也可以试下也很方便。
以上所有的使用教程最好直接看软件的帮助文档,最直接。避免网上一些多余设置的误导。多去看一看文档再大功能一共就那么多不会再增加了。
调试是一种手段,在项目后期对异常抓取非常重要,所以平常要尽可能的去积累调试方法与工具,以便紧急情况下快速定位解决。
东西有点多并且笼统,很多无法细讲,大家可以多多交流,有什么不足的及时指正。
版权说明:如非注明,本站文章均为 扬州驻场服务-网络设备调试-监控维修-南京泽同信息科技有限公司 原创,转载请注明出处和附带本文链接。
请在这里放置你的在线分享代码