STM32的keil debug调试(JTAG/SW)
目录
一、JTAG/SWD调试原理概述
二、配置JTAG/SWD引脚
三、基础执行控制按钮介绍
3.1调试与断点按钮
3.2 查看程序段/函数执行时间
3.3 结束仿真报错
四、工具栏常用窗口按钮介绍
五、仿真时需要注意的点
一、JTAG/SWD调试原理概述
Cortex-M内核含有硬件调试模块,该模块可在取指(指令断点)或访问数据(数据断点)时停止。
内核停止时,可以查询内核的内部状态和系统的外部状态。完成查询后,可恢复程序执行。
意思就是STM32里边包括外设和内核,内核里边有一个调试模块,有这个模块就可以仿真调试STM32,这个模块可以在指令断点或数据断电处停止,这里的停止指的是内核停止,内核停止就可以查看内核的内部状态和系统的外部状态。内核的内部状态就是内核那些R0、R1、PC这些,外部状态就是外设了,例如寄存器。
二、配置JTAG/SWD引脚
SWD:只需要两个引脚,一个是CLK时钟引脚,一个是SWDIO数据引脚。
JTAG:需要5个引脚,分别是JTMS、JTCK、JTDI、JTDO、JNTRST引脚。
由于SWD比JTAG少3个引脚,那么使用SWD模式,就可以将另外3个引脚释放。如何释放看下面表格。
1、在复位状态的时候,5个引脚都没有释放,图里边X表示没有释放。5个引脚都没有释放,那么也就是说在复位状态下两种模式都可以使用。
2、释放NJTRST引脚, 就可以把PB4当作普通的IO口,JATG和SWD都可以使用,但是JTAG不能复位了。
3、释放JTAG多余的三个引脚,只能使用SW模式了,不能使用JTAG模式。释放的三个引脚就可以当作普通IO口。
4、5个引脚全部释放,用于普通的IO口,只能使用串口下载程序。
F1系列可以通过AFIO_MAPR寄存器的SWJ_CFG[2:0位来释放部分或者全部SWJ-DP引脚。
F4/F7/H7系列默认全部SWJ-DP引脚为复用功能并映射到复用功能0(AF0)。这三个系列多了一个复用功能选择器。复位以后都是选择AF0。
三、基础执行控制按钮介绍
3.1调试与断点按钮
1、开始/停止仿真按钮:刚工程编译后,需要仿真就点击这个按钮,退出仿真也点击这个按钮。如果程序已经下载进开发板,直接进入调试模式。如果没有下载进开发板,会先下载程序再进入调试模式。
黄色箭头为程序下一步执行位置,蓝色箭头为光标位置。 一般点完调试按钮,黄色箭头一般直接来到main函数的第一行,因为再魔法棒的debug里边选择了Run to main选项。
2、断点相关按钮:
第一个为插入和删除断点,第二个为使能和失能断电,第三个为失能全部断点,第四个为删除全部断点。MDK最多支持6个断点,失能断点就是不起作用了,变成白色圆圈,表示之前在这块设置过断点。
1、复位按钮:这个跟硬件复位功能是一样的。
2、全速运行:执行到断点处才会停止。
3、停止运行:按一下程序停止循行,和全速运行按钮配合使用。
4、执行进去:大括号代表一个函数执行进去,会跳转到这个函数里开始执行。
5、执行过去:直接运行这个函数,不跳转过去。
6、执行出去:从函数里边出来
7、执行到光标处:有一个蓝色箭头,代表执行到光标处。
8、黄色箭头:展示下一步要执行的程序。
3.2 查看程序段/函数执行时间
使用这个功能需要在魔法棒里边选择debug,再选择setting里边的Trace。需要追踪程序执行时间时设置,根据系统时钟频率的实际值设置。
点击调试按钮,开始调试,运行时间可以在左边的内核寄存器窗口查看,也可以在窗口下面的t1查看。
3.3 结束仿真报错
如果报这个错误是因为在结束仿真之前没有清除断点。必须通过任务管理器里直接关闭keil。
解决办法:在结束调试之前将所有断点全部清除,可以使用清除所有断点按钮。
四、工具栏常用窗口按钮介绍
1、窗口可以通过工具栏快捷按钮打开,或者在菜单栏的View下拉框中打开
2、下面介绍一下工具栏常用创建按钮
(1)第一个是command命令窗口, 可以在这个窗口打印一下信息,还可以输入一些命令,这个窗口几乎不用。
(2)第二个是汇编窗口,可以查看汇编程序,几乎也用不到。
(3)第三个窗口为Symbols窗口,在这个窗口中会列举出一些函数名、变量名、还有变量类型一下符号。
(4)第四个是Registers窗口,里边都是内核寄存器、堆栈、堆栈指针等。
(5)第五个是Call Stack Window窗口,可以查看函数调用关系&局部变量。其中,name表示调用的函数名字,Location/Value对于函数就是函数的首地址,Type为函数类型。
在main函数里边调用一下delay_ms函数,可以看到delay_ms函数在main函数,Call Stack Window窗口窗口显示的函数调用顺序是从下往上调用的,也就是说是main函数调用了delay_ms函数。
可以看到delay_ms函数的首地址是0X08001088,函数类型为void f(ushort),对于局部变量nms,它的Value(值)是0X01F4,类型为parame-ushort,表示这个是变量是函数的参数,l类型为ushort。
图中repeat变量对应的值为Not in scope,表示不在范围内是因为我程序还没有运行这个变量的赋值那行。运行完之后变量就会有值。
(6)第六个Watch 窗口:查看函数首地址&变量值 有watch1和watch2,随便打开一个就可以了。通过选中变量右键add to watch1,全局变量不给初始值默认为0;右键添加函数的话对应的值就是函数的地址。对于数组也是一个地址。
watch窗口可以设置全局变量在被读或写后自动停止运行。
操作步骤:在watch窗口,右键需要调试的变量,选择set Access BreakPoint,然后在弹框里可以选择是在被读时设置断点,还是在被写的时候设置断点。最后点击define,完成设置。 程序会在被写的下一步停止运行。
(7)第七个Memory 窗口:查看内存窗口。
在Address里边输入地址,即可查看对应位置地址,默认是16进制的,也就是里边两个数表示一个字节8位。
注意Memory里边是小端模式,数据值要倒着读。上面那个例子是8位的数据,看不出来。下面定义一个16位的数据,观察一下。
可以看到,在Memoy窗口里观察到的显示顺序为0F00,实际是0X000F表示第一个数,所以需要倒着读。外设寄存器的地址也是一样,下面以RCC的APB2ENR寄存器为例子,RCC的基地址从手册可以查到为0X40021000,同时APB2ENR寄存器的偏移地址为0X18,则直接搜索0X40021018,可以看到显示值为48000000,看寄存器的实际值为0X00000048,那么倒过来读就对了。
总之就是8位的数据没有区别,16位的数据就是两个字节代表一个数,32位的就是4个字节代表一个数,外设寄存器基本都是32位的,都是4个字节一个数。都需要倒过来读。
(8)第八个Peripheral 窗口 :查看寄存器的值
直接在菜单栏里的Peripheral里边选择或者直接在工具栏里边选择也可以。
在这个窗口除了查看外设相关寄存器,还可以查看内核相关寄存器,例如NVIC(Nested Vector interrupt controller),系统嘀嗒定时器等。
五、仿真时需要注意的点
1、需要在魔法棒的C/C++里边将优化等级设置为level0,不然会出现一些奇怪的问题,例如在call stack window里边的函数调用不显示顺序。
2、 调试停止在断点处时,只是内核停止,外设会继续运行。例如内核停止了,但是DMA属于外设,没有停止,数据流任然在搬运。
3、断点的设置要有时间观念,考虑是否会打断正常通信。例如在通信过程中有1s内返回响应的,就会受影响。
作者:猿~~~