Keil 5实战:在线调试汇总及基本操作指南

STM32F407基础总结系列(二)


Keil5在线调试汇总及基本操作教程

  • STM32F407基础总结系列(二)
  • 前言
  • 一、在线调试基础介绍
  • 在线调试原理
  • 在线调试工具
  • Keil5调试窗口控件介绍
  • 基本调试操作
  • 二、调试具体操作
  • 代码运行时长检测(断点时间测量)
  • 寄存器查看与操作
  • 外设寄存器查看
  • 寄存器直接操作
  • 断点详解
  • 断点分类
  • 断点操作
  • 存取断点
  • 执行断点
  • 条件断点
  • 变量查看
  • 回调栈局部变量窗口
  • Command窗口操作
  • 自定义TOOLBOX按钮
  • ITM(指令跟踪单元)
  • 软件逻辑分析仪
  • 虚拟串口窗口
  • ini文件的使用
  • 不复位在线调试
  • Jlink的RTT打印
  • 常用调试软件
  • 串口抓包工具
  • 网络抓包工具
  • 按键精灵
  • Matlab
  • 总结

  • 前言

    STM32单片机在开发过程中很多大一部分时间在调试与修改程序上,尤其是对于一些异常问题的抓取与分析,因此Keil5的在线调试功能便完美的契合了STM32的调试需求,各种调试手段与方法也层出不穷。
    本文着重从基本的调试原理、功能构件及技巧上进行分析,系统性的帮助读者了解在线调试功能以及解决调试中的问题,也可为后期的调试提供一些参考。


    一、在线调试基础介绍

    在线调试原理

    内核调试框图 STM32F4xx 的内核是 Cortex™-M4F,该内核包含用于高级调试功能的硬件。利用这些调试 功能,可以在取指(指令断点)或取访问数据(数据断点)时停止内核。内核停止时,可以查询内核的内部状态和系统的外部状态。查询完成后,将恢复内核和系统并恢复程序执行。 当调试器与 STM32F4xx MCU 相连并进行调试时,将使用内核的硬件调试模块。 提供两个调试接口:

    1. 串行接口
    2. Jtag调试接口

    在线调试工具

    软件: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参数)

    Keil5调试窗口控件介绍

    打开keil仿真调试模式(记得使用前配置好并连接调试器)

    初始的默认串口布局如下

    1. 调试操作栏
      [复位|运行|停止|单步运行|单行运行|跳出函数体|运行到光标处|跳转PC指针]
      调试时代码的运行操作在此设置
    2. 主界面窗口设置
      [命令行|反汇编窗口|符号窗口|内核寄存器|回调栈及局部变量|变量显示|内存窗口|虚拟串口|系统分析窗口|TRACE窗口|外设寄存器]
      命令行:调试操作命令及返回等消息在这里显示,也可以直接在这里操作执行一些语法命令,如断点打开关闭显示等。
      反汇编窗口:C/C++编写的代码转换为汇编语言,此窗口与代码窗口同步滚动,但并不是代码执行时的顺序(可能是编译的顺序)
      符号窗口:编译后所有的函数变量及类型均在此,可通过这里查看有没有编译某些变量
      内核寄存器:显示内核先关的寄存器数值
      回调部变量:当调试时停留在断点时,这里会显示函数的调用关系,以及压进的变量值,这个一般和断点配合反推异常调用以及查看局部变量无需使用变量查看串口
      变量显示:用于查看单片机中某个变量的值,一般多用于查看全局变量以及外设寄存器数值、表达式显示变量,也可直接操作变量值。
      内存窗口:显示内存地址以及地址处内存的数据,一般可查看变量以及寄存器数据、函数地址等
      虚拟串口窗口:通过调试查看的串口,一些需要重定向才能使用。
      系统分析窗口:这里有一些代码分析的高级功能,用的最多的是软件逻辑分析仪的功能。
      trace窗口:可能与代码跟踪有关,高级功能还没试过。具体可参考keil5的帮助文档。
      外设寄存器窗口:比较常用,用来查看你打开的串口/spi/can/Tim/rcc等等寄存器的内容,当然也可直接修改操作寄存器。
    3. 在线调试启动/关闭
    4. 断点设置 设置、取消、关闭、删除所有断点等操作。
    5. 内核寄存器窗口
    6. C代码对应的汇编程序窗口 注意代码左侧灰色部分代码已编译部分,可设置断点(此部分可以查看代码是否编译或者是否被编辑器优化)
    7. C/C++代码窗口
    8. Command窗口 调试命令行,可通过设置命令执行所有调试操作,如断点设置、变量寄存器访问、数据转换、基本计算等功能
    9. 回调栈及局部变量窗口

    基本调试操作

    打断点查看变量值
    断点使用

    复位、停止程序

    停止复位

    单行/单步调试操作

    二、调试具体操作

    代码运行时长检测(断点时间测量)

    参照许多教程进行了stm32F1/F4的测试,发现通过以下步骤基本满足测量不发生异常。(测试工具为J-LINK/ST-LINK的sw接口连接)

    设置仿真参数

    image-20220505224545370

    打开Trace界面,勾选Enbale使能,设置时钟为单片机运行的主频(一般STM32F103为72Mhz,F407为168Mhz)

    image-20220505224757588

    1打开仿真界面,2打开内核寄存器窗口,3将寄存器窗口保持固定在如图所示界面时钟显示(计时的时钟就是此处的Sec),4鼠标右键弹出菜单,5复位t1/t2定时。

    image-20220505225341621

    断点测量代码运行时长。此处要先关闭固定窗口刷新(代码运行同时刷新变量窗口数据,会影响测量时间的准确性),设置断点后,开启代码运行,下一次测量时应复位测量计时器T1/T2.

    断点测量代码运行时长

    寄存器查看与操作

    外设寄存器查看

    通过下图中序号所示即可打开相应的外设寄存器窗口,图中示例了串口1的寄存器查看,同样的中断设置/时钟分频/定时器均可通过此查看。甚至可以通过数据的变动与否判断外设是否正常打开。

    外设寄存器查看

    寄存器直接操作

    输出IO控制

    io端口输出初始化完成后,可直接操作ODR寄存器中端口来控制输入输出,效果和标准库函数中的 GPIO_SetBits /GPIO_ResetBits一样。

    操作外设寄存器

    输入IO检测

    当某个单片机IO口设置为输入时,可直接通过输入寄存器查看电平状态即使代码处于断点停止状态也可以查看(断点停止有时需要手动点击toolbox中的更新窗口按钮),在项目中可用来检测外部开关信号等省去了万用表测电压。

    IO输入寄存器

    串口数据寄存器直接操作

    操作串口数据寄存器

    这里有一个有意思的现象,直接在外设寄存器上操作串口实际能发送两个字节,而通过变量WATCH窗口以变量形式操作能正确发送一个字节。

    直接操作数据寄存器

    中断控制

    中断控制进入

    断点详解

    断点分类

    Keil5软件帮助文档中指明了断点有三种类型:存取断点,执行断点,条件断点。

    存取断点:某一个变量度或者写操作时执行断点操作。

    执行断点:执行到代码某个位置时产生断点操作。一般直接在代码左侧打的断点就是此类断点,用的最多。

    条件断点:当满足某个表达式时,如某个变量==0x01时执行断点。

    image-20220505233316651

    官方示例说明

    image-20220505234154604

    断点操作

    除直接在代码左侧设置执行断点外,其余断点需要通过断点管理窗口来实现。

    image-20220505234846603

    仅操作1处表达式,表达式为某个函数地址时为执行断点,Count表示执行次数。

    1和3处同时操作时表示为存取断点,3中SIZE表示存取变量的字节大小,Bytes与Objects的区别在于单一变量与结构体的不同。当存取某个变量或者结构体中某个成员时使用Bytes,存取某个结构体时使用Objects。

    仅操作1和2为条件断点,如变量==、>=某个值时执行printf指令打印变量值。注意此处的printf仅输出到调试界面的Command窗口。command指令的执行并不会使程序中断停止,相当于此处为软件断点。

    image-20220505235747840

    断点管理窗口中的断点需要停止代码执行才能正确设置。

    存取断点

    建议在Watch中右键添加断点。

    image-20220506002350820

    字节写断点

    字节写断点

    结构体写断点

    当st_abc被写两次时中断程序执行。

    结构体写断点

    执行断点

    代码左侧直接红色断点与断点窗口表达式处直接填写函数名称效果一样。Count表示执行次数,可设置执行某个函数Count次后中断停止。

    执行断点

    条件断点

    此处用变量值作为条件判断演示一下条件断点(因为涉及到了变量存取,所以这里实际为存取断点)实现大概过程。

    image-20220506020845824

    条件打印输出过程,注意printf格式为printf("%d\n",a),后边的\n必须加,还有打印频率不要太快,条件断点的检测会极大的影响代码的执行效率。

    条件断点

    变量查看

    常规操作

    右键添加到变量观察窗口,或者直接选中后拖拉变量到窗口。观察的对象比较广泛,全局/局部变量、寄存器、函数地址、数组结构体等,对于局部变量只能在变量的有效局部内才能显示具体数值。

    变量查看常规操作

    表达式操作

    表达式可进行简单的数学运算,甚至可以当做一个简单的进制转换、计算器来使用。如下所示,动态显示random的值减去70000,0xf777转换为十进制。

    变量查看表达式操作

    回调栈局部变量窗口

    打断点后,通过回调栈窗口可以看到当前函数的调用情况以及内部变量的值。

    image-20220506235722783

    当程序封装太多层时可参照如下方式进行一层一层跳转分析。

    image-20220507000250807

    辅助用法

    当存在Hardfault等错误以及程序死循环时,可以通过断点或停止按钮停止程序运行,在回调栈窗口查看调用hardfault的位置,位置不是很准确,但是能反应大概位置,然后通过局部变量的值进行判断异常位置。下边演示了数组越界引起了异常,大概定位到了前后的位置,其它的错误定位可以再研究一下。(数组越界小好像啥事没有,越界很多才会跳转hardfault)

    堆栈窗口异常辅助查看

    这里插入别人的hardfault的查找操作。

    Cortex-M 处理器 hardfault 定位方法和步骤(基于Keil mdk)

    Command窗口操作

    command窗口可实现命令行的作用,通过执行命令函数或表达式直接实现查看与修改变量、对象、寄存器及内存。

    断点设置

    断点设置

    通用命令

    通用命令

    内存操作命令

    image-20220509021604687

    常用的数学函数

    image-20220508021849739

    使用示例

    查看函数地址范围

    将command窗口内容形成log文件(放在工程根目录下)

    自定义TOOLBOX按钮

    keil5在仿真界面可以自定义按钮执行command命令,并且按钮不会随着编译退出而删除,下次仿真可继续使用。

    toolbox菜单按钮

    默认系统会创建一个刷新界面窗口的按钮[Update Windows]

    定义按钮语法:

    DEFINE BUTTON "button_label", "command"//创建一个button_label的按钮,按钮执行command命令
    

    例:

    DEFINE BUTTON "显示random值", "printf (\"random=%04XH\\n\",random)"
    

    image-20220513013310797

    也可直接操作寄存器

    DEFINE BUTTON "置位", "GPIOF->ODR |= (1<<9)"

    DEFINE BUTTON "复位", "GPIOF->ODR &= ~(1<<9)"

    image-20220513014105285

    按钮的删除

    Kill Button 3 /* 移除第3个按钮 */
    

    image-20220513014437245

    在调试中虽然不能直接调用想要的程序函数,但可以设置一个标志位实现对函数的控制,函数放在主循环中个,通过按钮改变标位置从而控制函数的执行。

    image-20220513015932842

    ITM(指令跟踪单元)

    ITM的使用有两个条件:

    硬件仿真上使用SW模式,同时将SWO接口(STM32F4是PB3端口)与J-LINK的JTDO端口连接(注意一定要查一下你的J-LINK或者ST-LINK的SWO端口没被做硬件上的上下拉电压限制,还有板子上有没有做啥限制)。

    软件上配置如下

    image-20220513020659129

    软件逻辑分析仪

    ITM配置好后直接添加变量即可,注意得是全局变量且不能超过四个

    软件逻辑示波

    虚拟串口窗口

    ITM的另一大功能就是虚拟串口

    首先ITM软硬件配置完毕后,修改代码重定向printf函数,也可不重定向直接操作底层的ITM_SendChar (uint32_t ch)

    这里直接借用的原串口的重定向函数,直接将底层发送字节的函数放进去就好了(发现也可公用的样子,哈哈)

    image-20220513021650165

    仿真打开虚拟串口看看效果

    虚拟串口

    (printf可以重定向到debug viewer 和外部串口中,数据时同时更新的)

    image-20220513022229403

    还可以用来统计进入中断的次数及时间

    事件计数(总指令 异常 休眠 存储 折叠指令)

    ini文件的使用

    ini文件可解释为一个配置文件,相当于一个.C文件,这个文件的执行本质与仿真时的命令行执行一致(如果觉得不麻烦可以再命令行中敲所有的命令而不用加载ini文件).

    ini文件的加载主要在两个地方:

    1. 点击调试时会加载图片所示的ini文件。

    1. 调试时使用专用管理器调用

    调用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按钮。

    不复位在线调试

    1. 使用SWD4线连接目标板(Jtag接口会产生复位)
    2. 外部工程目录下创建一个noresetDBG.ini配置文件,内容为
    LOAD %L INCREMENTAL
    

    没有这个也可以不复位调试,但打不了断点

    https://gitee.com/jay_0/open_picture/raw/master/img/image-202205090257236451.png

    1. 取消勾选Load Application at Startup,加载调试初始化配置

    image-20220509025437380

    (2也可省略,直接在仿真后的command窗口输入效果是一样的)

    4. 取消调试器连接后的复位(这个建议不连接板子,只插烧写器进行设置,否则会造成复位一次)

    image-20220509030107531

    1. 调试时目标更新也取消勾选(这一步在F407上调试发现不操作也能实现,可有可无的样子)

    image-20220509030317967

    效果测试

    不复位调试

    Jlink的RTT打印

    rtt打印很方便,占用一部分内存空间来实现非在线调试时swd端口的数据输出,一般用在串口紧张时代替串口实现printf调试。具体教程参照网上已有教程就好了。

    JLink的RTT使用

    常用调试软件

    串口抓包工具

    串口精灵


    下载链接,使用免费功能即可。http://www.ceiwei.com/mt/download/showdownload.php?id=2

    网络抓包工具

    线鲨,网络抓包超级方便强大。

    wireshark

    下载链接 https://www.wireshark.org/#download

    使用教程https://www.cnblogs.com/mq0036/p/11187138.html

    按键精灵

    使用按键精灵模拟人去操作上位机,用来复现偶发通信异常及流程异常利器,也可用来进行上下位机的压力测试。


    下载链接http://www.anjian.com/download.shtml

    Matlab

    Matlab,不解释除了生孩子什么都可以干。常用来抓取大量数据然后绘图分析异常数据点。(推荐18版后边的版本,绘图操作直接拖拉即可一行源码都不需要写),MATLAB直接串口接收也可以试下也很方便。

    image-20220505025842781


    总结

    以上所有的使用教程最好直接看软件的帮助文档,最直接。避免网上一些多余设置的误导。多去看一看文档再大功能一共就那么多不会再增加了。

    调试是一种手段,在项目后期对异常抓取非常重要,所以平常要尽可能的去积累调试方法与工具,以便紧急情况下快速定位解决。

    东西有点多并且笼统,很多无法细讲,大家可以多多交流,有什么不足的及时指正。


    物联沃分享整理
    物联沃-IOTWORD物联网 » Keil 5实战:在线调试汇总及基本操作指南

    发表评论