http://blog.youkuaiyun.com/k_o_carnivist/article/details/50322069
1) Keil 评估软件:MDK 4.7x 和 MDK 5
MDK 5 以 Software Pack 的形式分发特定于处理器的软件、例程和中间件(middleware)。安装 MDK 5 之后,需要从网络上下载这些 Pack。这些 Pack 也可以手动导入。
MDK 4.7x 目前也是可用的。这个版本的 MDK 会包含程序运行所需要的所有文件,不使用 MDK 5 的 Software Pack。这篇文档的 MDK 4 版本可以在这个链接找到:http://www.keil.com/appnotes/docs/apnt_261.asp。
Keil 网站上有 MDK 5 的 Legacy 支持软件,安装之后可以在 MDK 5 中使用 MDK 4 的工程,而不需要任何的 Software Pack。
我们建议使用 MDK 5.10 Software Pack,本文会持续跟进新的版本(译者注:并没有>_<,我在用5.17,如有区别会注明)。
Keil 针对各种 STM32 处理器有许多类似的实验手册,比如 CAN 的使用。详见www.keil.com/st。
这篇文档针对 MDK 5.10 及更新版本。
2) 下载和安装 Keil 软件
-
从 Keil 网站上下载 MDK 5.10 或更新的版本:www.keil.com/mdk5/install
-
将 MDK 安装到默认路径。安装到其他路径也是可以的,本教程会以默认路径为例:
C:\Keil_v5
。 -
本教程使用
C:\MDK\
做为例程目录,建议同样使用这个默认路径。 -
如果 MDK 安装在其他路径,实验中需要做对应的路径修改。
-
(译者注:原文没有5,P.S. 上面这一段真贫)
-
Keil 网站上可以找到 DSP5 例程。
-
这个实验可以用评估版本(MDK-Lite)来完成,不需要购买授权。
-
不需要额外的调试器,只需准备 NUCLEO-F401RE 开发板、USB 线,以及在电脑上安装 MDK 5.10 就可以了(译者注:原文使用的是 STM32F4-Discovery 开发板)。
3) 板载 ST-Link V2 调试器
这篇教程仅适用于板载的 ST-Link V2 调试器,后文将给出 ST-Link V2 的配置说明,及 ST-Link V2 驱动程序的测试。
4) 例程
MDK 5 Software Pack 里面有 Blinky 和 RTX_Blinky 例程,我们会用到其中的 Blinky。另外在本文最新版的网站上可以找到增强版的 RTX_Blinky5 和 DSP 例程(DSP5):http://www.keil.com/appnotes/docs/apnt_230.asp。
5) MDK 5 入门
《Getting Started MDK 5》是一部很有用的手册,可以在 Keil 网站上找到:http://www.keil.com/mdk5/。
6) μVision Software Pack 的下载和安装步骤
1) 启动 μVision 并打开 Pack Installer
在 MDK 刚安装完成的时候,如果电脑连接到了外网上,μVision 和 Software Pack 会自动启动。其他情况下,需要按照这里的步骤1)和2)来做。
(译者注:由于软件版本和板卡的区别,这一部分和原文略有不同。)
-
将电脑连接到外网上,下载 Software Pack 需要外网连接。
-
点击桌面上的图标
启动 μVision。
-
点击工具栏上的按钮
打开 Pack Installer。如果出现 Pack Installer 欢迎界面,阅读之后关闭它。
-
这里应该出现下面这个窗口。在 Board 选项卡中,选择 NUCLEO-F401RE,右侧 Packs 选项卡中的列表会自动筛选。
-
也可以在 Search 栏输入 NUCLEO 进行筛选。
-
注意:窗口右下角应该显示“ONLINE”。如果显示的是“OFFLINE”,请检查外网连接之后再继续下面的步骤。
-
如果在 Pack Installer 启动的时候没有连接到外网,列表中将不会显示内容。这时候需要在连接到网络后,点击菜单 Packs/Check for Updates 或者工具栏中的
刷新一下。
2) 安装 STM32F4 Software Pack
-
点击 Packs 选项卡,可以看到 ARM::CMSIS Software Pack 是默认安装好的。
-
选择 Keil::STM32F4xx_DFP 和 Keil::STM32NUCLEO_BSP 并点击 Install,这两个 Software Pack 会下载并安装在默认文件夹
C:\Keil_v5\ARM\Pack\Keil
中。下载估计需要两三分钟的时间。 -
下载完成后,应显示“Up to date”状态:
。
3) 安装 Blinky MDK 例程
-
选择 Examples 选项卡,出现如下窗口:
-
选择 Blinky (NUCLEO-F401RE)。
-
点击 Copy
。
-
Copy Example 窗口如图所示。选择 Use Pack Folder Structure,取消选择 Launch μVision。
-
输入
C:\MDK
,点击 OK 完成 Blinky 工程的复制。 -
Blinky 工程已经复制到
C:\MDK\Boards\ST\NUCLEO-F401RE
了。 -
不需要复制 CMSIS-RTOS Blinky 程序,我们会有一个更有意思的4线程版本。
提示:复制例程时,一开始的默认路径是
C:\Users\< user >\Documents
,这篇教程使用C:\MDK\
做为默认路径。实际上可以选择任意路径。 -
关闭 Pack Installer。以后随时可以通过点击图标
来打开。
提示:Update 按钮说明 Software Pack 有更新可以下载
。
提示:如果找到目录
C:\Keil_v5\ARM\Pack\Keil\STM32NUCLEO_BSP\1.4.0\Boards\ST\NUCLEO-F401RE
,可以发现里面也有一个 Blinky。这个版本是只读的,做为备份用。请使用从 Pack Installer 的 Examples 选项卡复制出来的工程,本教程中存放在C:\MDK
。
4) 从 Keil.com 上安装 RTX_Blinky5 和 DSP5 例程
-
从 http://www.keil.com/appnotes/docs/apnt_230.asp 上获得例程的 zip 文件。
-
解压缩到
C:\MDK\Boards\ST\STM32F4-Discovery\
。(译者注:这个程序是对 Discovery 开发板的。)
7) 测试 ST-Link V2 的连接
-
用 USB 线将 NUCLEO 开发板连接到电脑上。
-
如果 ST-Link USB 驱动程序安装正确,应该可以听到正常的 USB 设备连接的系统声音。否则需要根据下一章的指示,手动安装驱动程序。
-
两个红色 LED 应该点亮:LD1 (COM)和 LD3(PWR)。
-
启动 μVision
并选择 Project/Open Project。
-
选择 Blinky 工程
C:\MDK\Boards\ST\NUCLEO-F401RE\Blinky\Blinky.uvprojx
。 -
在这个地方选择 STM32F401 Flash:
。
-
点击 Target Options
或者按 ALT+F7,并选择 Debug 选项卡:
-
点击 Settings,会出现下面所示的窗口。如果显示出了 IDCODE 和 Device Name,说明 ST-Link 工作良好,可以继续下面的教程。点击两次 OK 返回 μVision 主界面。
-
上图中 Serial Number 框里出现一串数字说明 ST-Link 调试器已经连接到了 μVision。
-
如果 SW Device 框中没有显示,或者显示 error,这个问题在继续本教程之前必须要解决。请参照下一节内容:安装 ST-Link USB 驱动程序。
-
如果已经显示正常,ST-Link USB 驱动程序安装良好。点击两次 OK 退出 Target Options 窗口并从第9章继续。
提示:在上图 Port 框中选择 JTAG,然后在选回 SW,可以刷新 SW Device 框的显示。也可以关闭再重新打开这个窗口。
提示:ST-Link V2 和 ST-Link 的主要区别是添加了 Serial Wire Viewer (SWV) 跟踪功能。
8) 安装 ST-Link USB 驱动程序
如果上面的测试没有问题,则不需要进行这一步。
安装 ST-Link USB 驱动程序:(当上面的测试没有通过时)
-
先断开 NUCLEO 开发板和电脑之间的 USB 连接。
-
需要手动运行
stlink_winusb_install.bat
来安装 USB 驱动,这个文件存放在C:\Keil_v5\ARM\STLink\USBDriver
中。找到这个文件并双击来安装驱动程序。 -
连接 NUCLEO 的 USB,USB 驱动程序应该会以正常的方式安装完毕。
重要提示:ST-Link V2 固件升级程序 ST-LinkUpgrade.exe 存放在
C:\Keil_v5\ARM\STLink
。如果要更新 ST-Link 固件,找到并双击这个程序,操作还是比较简单的,程序会检查并报告当前的固件版本。请注意我们需要使用 V2.J16.S0 或更高的版本来支持 SWV 操作。另外不要使用 V2.J19.S0,这一版本与最新版驱动程序不兼容。
(译者注:V2.J19.S0 不兼容估计是个历史问题,我已经在用 MDK 5.17 和 V2.J24.M11 版本了。)
COM LED LD1 的含义:
LED 红色闪烁:电脑开始 USB 枚举,但还未完成。
LED 红色:电脑和 ST-LINK/V2 之间已经建立连接(枚举结束),但 μVision 还没有连接到 ST-Link (比如 Debug 模式)。
LED 绿色:μVision 以 Debug 模式连接到 ST-Link,上一个通信是成功的。
LED 红色、绿色间隔闪烁:μVision 和目标之间正在交换数据。
LED 熄灭,但当进入 Debug 模式或点击 RUN 时闪烁一下:μVision 的 SWV 跟踪已启动。
LED 熄灭:ST-LINK/V2 与目标 MCU 或 μVision 之间的连接失败,需要重新连接电源以重启开发板。
9) 使用 NUCLEO 开发板运行 Blinky 例程
我们将使用板载 ST-Link V2 调试器连接 Keil MDK 开发平台和真实的目标硬件。
-
点击桌面图标
启动 μVision,用 USB 线将 NUCLEO 开发板的 CN1 连接到电脑上。
-
选择 Project/Open Project,打开文件
C:\MDK\Boards\ST\NUCLEO-F401RE\Blinky\Blinky.uvprojx
。 -
ST-Link 会默认被选择。第一次运行 μVision 和 NUCLEO 开发板的时候,可能需要安装 USB 驱动程序,详见上面章节。
-
点击 Rebuild 图标
编译源文件。也可以用旁边的 Build 图标
。
-
点击 Load 图标
对 STM32 的 flash 进行编程。Output 窗口中会显示这个过程。
-
点击 Debug 图标
进入 Debug 模式,如果出现 Evaluation Mode 对话框,点击 OK。
注意: 当下载到 flash 时才需要使用 Load 图标,如果选择的是 RAM 运行则不需要。 -
点击 RUN 图标
。注意:点击 STOP 图标
可以停止程序运行。
NUCLEO 开发板上的绿色 LED 会开始闪烁。
按下开发板上蓝色的 USER 按键会暂停闪烁。
至此你已经了解如何编译工程、下载到 STM32 处理器的 flash 中、运行并停止程序!
注意: Blinky 程序已经永久的烧写到 flash 中了,开发板可以独立运行这个程序,直到下一次被烧写。
10) 硬件断点
STM32F4 共有六个硬件断点,可以在程序运行过程中随时设置或取消。
-
在 Blinky 程序运行过程中,打开 Blinky.c 文件,点击 main() 函数中 for 循环里的某一行左侧边缘深灰色区域。
-
会出现一个红色的圆形标志,程序会停止运行。
-
请注意断点同时显示在源代码窗口和反汇编窗口,如下图。
-
不论是反汇编窗口还是源代码窗口,左侧边缘显示深灰色方形的区域表示这些代码行存在汇编指令,可以在这里设置断点。
-
每次点击 RUN 图标
,程序会运行到下一次遇到断点。
-
可以尝试点击 Single Step(Step In)
、Step Over
和 Step Out
。
提示: 如果单步调试(Step In)不工作,点击 Disassembly 窗口使它成为焦点,可能需要点击一行反汇编代码。这样操作表示想要汇编级别的单步运行,而不是 C 语言代码级别。
提示: ARM CoreSight 的断点是 no-skid 的,硬件断点发生在被设置断点的指令执行之前(译者注:有 skid 的断点的意思是,程序停止在断点设置的指令甚至后面几个指令执行之后)。另外 flash 中烧写的指令不会被替代或修改,这的特性对于高效率软件开发有重要意义。
完成这个实验后,再次点击这些断点以删除它们,为后面的实验做准备。
提示: 可以通过点击断点,或者选择 Debug/Breakpoints(或按 Ctrl+B)并选择 Kill All 来删除。
提示: 可以通过选择 Debug/Breakpoints 或按 Ctrl+B 来查看所有断点的设置。
11) Call Stack + Locals 窗口
局部变量
Call Stack + Locals 窗口被合并在一个集成窗口中,每当程序停止时会显示调用栈和当前函数的所有局部变量。
如果可能,局部变量的值会显示,否则显示 < not in scope >。菜单中的 View/Call Stack Window 用来切换 Call Stack + Locals 窗口显示或隐藏。
-
运行并停止 Blinky,点击 Call Stack + Locals 选项卡。
-
下图展示了Call Stack + Locals 窗口。
窗口中显示了当前活动函数的名称和局部变量列表。随同每个函数的名字会显示它被哪个函数或中断/异常调用。
当函数退出时,会从列表上移除。
最早调用的函数会出现在列表的底端。
这个列表只有在程序停止运行时有效。 -
点击 Step In 图标
或按 F11 键。
-
当单步运行到不同的函数时,观察它们在窗口上显示的变化。如果陷入到 Delay 函数的循环当中,可以用 Step Out
或 Ctrl+F11 键快速退出。
-
点击几次 Step In,观察其他函数。
-
右键点击一个函数名,尝试 Show Callee Code 和 Show Caller Code 选项。
-
点击 Step Out 图标
退出所有函数,返回 main()。
提示: 如果单步调试(Step In)不工作,点击 Disassembly 窗口使它成为焦点,可能需要点击一行反汇编代码来执行汇编级别的单步运行。如果焦点在源代码窗口上,则是执行 C 语言代码级别的单步运行。
提示: 可以在程序停止运行时,通过 Call Stack + Locals 窗口来修改变量的值。
提示: 上述是标准的“Stop and Go”调试过程。ARM Coresight 调试技术还可以做很多更强大的事情,比如在程序运行中显示并实时更新全局或静态变量,而不需要修改程序。由于局部变量通常存储在 CPU 寄存器中,不能在程序运行时实时显示,需要转换成全局或静态变量使得作用域不会消失。
如果借助 ULINK pro 和 ETM 跟踪,可以记录所有指令的执行情况。Disassambly 和 Source 窗口是按编写的顺序显示代码的,而 ETM 跟踪可以按执行的顺序显示。另外 ETM 还提供 Code Coverage、Performance Analysis 及 Execution Profiling 等功能。
把局部变量转换成全局或静态变量通常意味着把它从 CPU 寄存器移动到 RAM 上,CoreSight 在程序运行中可以观察 RAM,但不能观察 CPU 寄存器。
调用栈
如上面可以看到的,当程序停止运行时,函数按栈的方式显示在列表中。当想要了解栈中有哪些函数被调用、存储的返回值是什么的时候,这个功能就很有用。
提示: 可以在程序停止运行时,通修改局部变量的值。
提示: 点击菜单 Debug/Breakpoints 或按 Ctrl+B 键可以查看 Hardware Breakpoint 列表,同时这也是配置 Watchpoint (观察点,也叫 Access Point)的地方。在这个列表里可以临时屏蔽某些项目。点击 Debug/Kill All Breakpoints 会删除断点,但不会删除观察点。
12) Watch 和 Memory 窗口及其使用方法
Watch 和 Memory 窗口实时显示变量的值,这是通过 ARM CoreSight 调试技术实现的,这项技术是包含在 Cortex-M 处理器中的一部分。同时,也可以在这些存储器地址上实时地“put”或插入数值。这两个窗口都可以通过拖拽变量名,或者手动输入来添加变量。
Watch 窗口
添加全局变量: 除非程序停止在局部变量所在的函数,否则 Watch 和 Memory 窗口不能观察局部变量。
-
停止运行处理器
并退出 Debug 模式
。
-
在
Blinky.c
的第24行左右,声明一个全局变量(这里变量名叫做value
):unsigned int value = 0;
。 -
在第104行左右添加语句
value++;
和if (value > 0x10) value = 0;
,如图:
-
选择菜单 File/Save All 或点击
。
-
点击 Rebuild
,点击 Load
下载到 flash。
-
进入 Debug 模式
,点击 RUN
,提示:可以在程序运行中设置 Watch 和 Memory 窗口。
-
在 Blinky.c 中,右键点击变量
value
并选择 Add value to … 及 Watch 1,Watch 1 窗口会打开并显示value
如下图。 -
value
会实时增加到0x10
。
提示: 也可以框选value
,单击并拖拽到 Watch 或 Memory 窗口。
提示: 请确认菜单 View/Periodic Window Update 在选中状态。 -
也可以在 Name 下面区域双击或按 F2,再手动输入或复制粘贴变量名。或是打开菜单 View/Symbols Window 来输入变量。
提示: 如果要拖拽到一个非活动的选项卡,选中变量按住鼠标并移动至希望打开的选项卡名字上,等待其打开并拖拽鼠标到窗口内释放。
Memory 窗口
-
右键点击
value
并选择添加到 Memory 1,或手动添加value
到 Memory 1。如果需要的话,选择菜单 View/Memory 来打开 Memory 1 窗口。 -
注意
value
被当作了一个指针,其值做为地址显示在了 Memory 1 上。这个操作在想要看一个指针指向的地址的时候很有用,但不是我们现在想看到的。 -
在变量名前面加一个“&”符号并按回车键,改为显示变量的物理地址(0x2000000C)。
-
右键点击 Memory 1 窗口并选择 Unsigned/Int。
-
value
的值现在以32位的形式显示了。 -
Watch 和 Memory 窗口都是实时更新的。
-
在 Memory 窗口中,鼠标移动到数据区域右键点击,选择 Modify Memory,可以修改对应地址的值。
提示: 这些操作通常不会占用 CPU 周期。关于 DAP 是如何运行的,详见下一章“原理”。
提示: 在 Debug 模式中选择菜单 View/Symbol Window,可以打开 Symbol 窗口查看变量和各自的位置。
上面展示的 Memory 和 Watch 窗口的操作并不需要配置 Serial Wire Viewer (SWV),这些机制使用的是 SWV 之外的另一个 CoreSight 特性。CoreSight Debug Access Port (DAP)通过 Serial Wire Debug (SWD)或 JTAG 连接来处理读写操作,从而实现实时在线的存储器访问。
13) 如何在 Watch 和 Memory 窗口中观察局部变量
(译者注:由于板卡的区别,这一部分和原文略有不同。)
-
运行
Blinky.c
程序。我们将使用main()
中的局部变量num
。 -
在
Blinky.c
的第87行附近,main
函数的开头,找到声明这个局部变量的地方。 -
右键点击这个变量,把它输入到 Watch 1 窗口中。注意由于局部变量的值可能存放在 CPU 寄存器内,μVision 不能在程序运行时访问,因此会显示 < not in scope >。如果 μVision 显示无法添加变量,请尝试停止再开始 Blinky 程序。
-
在
Blinky.c
的主循环里添加一个断点,会使程序停止,这时会出现当前变量的值。 -
删除这个断点。
-
局部变量或自动变量可能存放在 CPU 寄存器内,μVision 不能在程序运行时访问。局部变量
num
只有在main
函数运行时才会存在,在其他函数或中断/异常处理程序中是不存在的,因此 μVision 无法确定这个变量的值。 -
停止运行处理器
并退出 Debug 模式
。
如何实时更新局部变量:
只需把 num
改为全局变量定义在 Blinky.c
中。
- 把
num
的声明移动到main()
的外面、Blinky.c
的最前面,把它改为全局变量:
提示: 也可以定义成静态变量,如: static int32_t num = 0;
。
提示: 在编辑模式和 Debug 模式都可以编辑文件,但编译只能在编辑模式进行。
-
点击 Rebuild 按钮编译源文件,确认没有 error 和 warning。
-
点击 Load 按钮
下载到 flash,窗口的左下角会显示进度条。
-
进入 Debug
模式并点击 RUN
。
-
这时
num
变量已经可以实时更新了。 -
可以读(写)全局或静态的变量、结构体,以及其他以变量形式放在函数与函数之间的东西,包括外设的读写。(译者注:这一句我没翻好:You can read (and write) global, static variables and structures. Anything that stays around in a variable from function to function. This include reads and writes to peripherals.)
-
停止运行处理器
并退出 Debug 模式
,准备下一个练习。
提示: 菜单中的 View/Periodic Window Update 需要选中,否则变量只在程序停止时更新。
原理
μVision 使用 ARM CoreSight 技术实现不窃取 CPU 周期的情况下对存储器位置进行读写。这种操作几乎是完全非侵入的,不影响程序本身运行时序。我们知道 Cortex-M4 是哈弗架构的,具有分离的指令总线和数据总线。当 CPU 以最大速度取指令时,CoreSight 调试模块有大量的时间读写数值,并不影响 CPU 周期。
有一种罕见情况,当 CPU 和 μVision 恰好同时读写相同的内存地址时,CPU 会暂停一个时钟周期,表现出轻微的侵入性。实际上可以认为这种窃取周期的情况不会发生。
14) 使用 Logic Analyzer 图形化观察变量
这一章将在 Logic Analyzer 中显示全局变量的值。这个功能使用 Serial Wire Viewer,因此不会窃取 CPU 周期,用户代码中也不需要加入任何代码片段。
配置 Serial Wire Viewer (SWV):
-
停止运行处理器
并退出 Debug 模式
。
-
点击 Target Options
或者按 ALT+F7,并选择 Debug 选项卡,点击窗口右侧的 Settings,确认选择的是 SW 模式。ST-Link中,SWV 强制使用 SW 模式。
-
选择 Trace 选项卡,选择 Trace Enable,取消选择 Periodic 和 EXCTRC,设置 Core Clock 为 48 MHz。其他选项如图所示。
译者注:CPU 时钟频率很重要,请务必按照实际值设置。Blinky 工程的时钟频率在
Abstract.txt
中可以找到。如果使用的是其他板卡,请自行检查时钟频率。 -
点击 OK 返回 Target Options。
-
再次点击 OK 返回主界面。
配置 Logic Analyzer:
-
进入 Debug 模式
。打开菜单 View/Analysis Windows 并选择 Logic Analyzer,或者选择工具栏上的 LA 按钮
。
提示: 可以在程序运行中配置LA。 -
点击 Blinky.c 选项卡,右键点击
value
变量并选择 Add value to… 及 Logic Analyzer。也可以手动拖拽来添加。 -
点击 LA 左上角的 Setup… 按钮进入 LA 设置窗口。
-
选择 value,设置 Display Range Max 为 0x15。
-
点击 Close。
运行程序: 注意: 可以在程序运行中配置LA。
-
点击 RUN
。点击 Zoom Out 使图形中网格大小是5秒左右。
-
变量
value
的值将增加到 0x10(十进制16)再重新设为 0。
提示: 如果没有看到波形,请退出并重新进入 Debug 模式以刷新 LA。可能还需要重新上电 NUCLEO 板卡。请确认 Core Clock 的数值正确。
提示: Logic Analyzer 中最多可以显示4个变量,必须是全局变量、静态变量或原始地址如*((unsigned long*)0x20000000)
。 -
请注意当 USER 按钮按下时,变量的值会随之停止增加。当然也请注意观察这个现象是如此直观。
-
选择 Signal Info、Show Cycles、Amplitude 及 Cursor,观察 LA 的测量功能。点击 Update Screen 栏的 Stop 按钮可以停止 LA。
-
停止运行处理器
。
15) 观察点:条件断点
不需要使用 Serial Wire Viewer
STM32 处理器有6个硬件断点,可以不停止 CPU 运行而在线设置。STM32 还有四个观察点。观察点可以认为是有条件的断点。观察点和逻辑分析仪共用比较器,因此要使用观察点,需要在逻辑分析仪中保证至少两个变量空位置。观察点也被称作 Access Breakpoint。
-
使用与前一练习相同的 Blinky 设置,停止程序运行,保持在 Debug 模式。
-
在 Blinky.c 中创建的全局变量
value
将用于观察点的探究。 -
配置观察点不需要 SWV Trace,但在这个练习中我们会用到逻辑分析仪。
-
延续上一个联系,变量
value
应保持在逻辑分析仪中。 -
在 μVision 菜单中选择 Debug 并点击 Breakpoints,或者按 Ctrl+B 键。
-
将 Read 和 Write 两个 Access 都选中,在 Expression 框中输入“
value == 0x5
”,不含引号。 -
点击 Define,应出现图中所示的一行。点击 Close。
-
如果 Watch 1 中没有
value
变量,添加一个进去。 -
打开菜单 Debug/Debug Settings 并选择 Trace 选项卡,选择“on Data R/W sample”,并保持 EXCTRC 不选中。
-
点击两次 OK 回到主界面。打开 Trace Records 窗口。
-
点击 RUN
。
-
在逻辑分析仪和 Watch 窗口中可以看到
value
在变化。 -
当
value
等于 0x5 时,Watchpoint 会停止运行程序。 -
注意如下图所示的 Trace Records 窗口中的 data write 记录:0x5 在 Data 列的最后一行,另外还有写入数据的地址和写入指令对应的 PC 指针。当前使用的是 ST-Link,如果用 ULINK2 会显示相同的窗口,但如果是 ULINK pro 或 J-Link(黑盒子)显示的窗口会略有区别。
-
查看 Breakpoints 窗口中的 Help 按钮可以了解另一种可用的表达式格式,有些目前没有在 μVision 中实现。
-
点击 RUN 可以重复本次练习。
-
练习结束后,停止程序运行,点击 Debug 并选择 Breakpoints(或按 Ctrl+B),删除所有断点。
-
退出 Debug 模式。
提示: 观察点不能像硬件断点那样在程序运行中设置。
提示: 在 Breakpoints 窗口中双击观察点,它的信息会放在下面的配置区域供编辑。点击 Define 会创建另一个观察点。如要删除旧的观察点,需要选中它并点击 Kill Selected,或者尝试下一条提示:
提示: 表达式旁边的选框可以用来临时屏蔽观察点。
提示: 逻辑分析仪中也可以输入原始地址,如:*((unsigned long*)0x20000000)
。
图中显示了变量 value
的触发点为 0x5 时,逻辑分析仪的显示情况。这里运行了三次。
16) 基于 Keil RTX RTOS 的 RTX_Blinky 例程
Keil 提供了一个全功能的 RTOS —— RTX,做为 Keil MDK including 源代码的一部分。本章的例子将探索 RTX RTOS 工程。MDK 可以和任何 RTOS 配合使用,实际上 RTOS 只是和你的工程一同编译的一组 C 语言函数。RTX 包含在所有版本的 MDK 中,以 BSD 开源协议的形式提供。
译者注:原文附带提供了一个专门的 RTX_Blinky 程序,是四个任务控制 Discovery 开发板上的四个 LED。这个工程使用了 STM32F4xx_DFP 2.1.0 软件包,在新版本的 Keil MDK 中是不提供的(Keil 网站上也没有这个版本的下载链接),难以完成这个实验。
这一章翻译版中,将用新版本的 pack 中包含的 RTX_Blinky 程序替代。其他操作与原文相同。
原文的四任务程序确实更能够体现 Keil MDK 调试模式在观察 RTX 工程上的便利性,有兴趣的话可以参考阅读。
RTX 及其所有组件放在:C:\Keil_v5\ARM\Pack\ARM\CMSIS\3.20.4\CMSIS_RTX
。
按照第6章的指示,安装并复制 RTX_Blinky 工程到 C:\MDK\Boards\ST\NUCLEO-F401RE\
。
-
在 μVision 的编辑模式(非 debug 模式)中选择 Project/Open Project。
-
打开文件
C:\MDK\Boards\ST\NUCLEO-F401RE\RTX_Blinky\RTX_Blinky.uvprojx
。 -
如果出现 Update Configuration Files 窗口,选择 Cancel。
-
这个工程已经为 ST-Link V2 调试器设置好了。
-
点击 Rebuild 图标
编译源文件,应该不会出现 error 或 warning。
-
点击 Load 图标
手动编程 flash。左下角的进度条会显示这个过程。
-
点击 Debug 图标
进入 Debug 模式。点击 RUN 图标
。
-
NUCLEO 开发板上的绿色 LED 会开始闪烁。
-
点击 STOP 图标
。
我们将借助 Kernel Awareness 窗口来探索 RTX 的运行。
17) 使用 Serial Wire Viewer (SWV)的 RTX Kernel Awareness
用户经常需要了解当前执行的任务的编号和其他任务的状态,这些信息一般被 RTOS 存储在一个结构体或内存空间中。Keil 为 RTX 提供了 Task Aware 窗口,其他 RTOS 公司同样也提供 μVision 中的对应的 awareness 插件。
-
点击 RUN 图标
运行 RTX_Blinky。
-
打开菜单 Debug/OS Support 并选择 System and Thread Viewer,图中所示的窗口将打开。可以拖住这个窗口并移动至屏幕中间。窗口中的数值是实时更新的,使用的读写技术与 Watch 和 Memory 窗口相同。
重要提示: 需要选中菜单中的 View/Periodic Window Update。 -
打开菜单 Debug/OS Support 并选择 Event Viewer。由于还没有配置 SWV,估计不会有数据显示。
**RTX Viewer:配置 Serial Wire Viewer (SWV):
需要激活 Serial Wire Viewer 来使 Event Viewer 运行。
-
停止运行处理器
并退出 Debug 模式
。
-
点击 Target 选择框旁边的 Target Options
,选择 Debug 选项卡。
-
选择 ST-Link Debugger 旁边的 Settings。
-
在 Debug 窗口中,确认选择的是 SW 模式而不是 JTAG。SWV 只能运行在 SW 模式。
-
点击 Trace 选项卡。
-
设置 Core Clock 为 48 MHz,并选中 Trace Enable。
-
取消选择 Periodic 和 EXCTRC,如图所示。
译者注:CPU 时钟频率很重要,请务必按照实际值设置。Blinky 工程的时钟频率在
Abstract.txt
中可以找到。如果使用的是其他板卡,请自行检查时钟频率。 -
需要选中 ITM Stimulus Port 31,RTX Viewer 使用这个方法获得内核 awareness 信息并显示在 Event Viewer 中。这个功能有轻微的侵入性。
-
点击两个 OK 返回主界面。
Serial Wire Viewer 配置完成! -
进入 Debug 模式并点击 RUN。
-
选择 Task and System 选项卡,显示应该在更新。
-
点击 Event Viewer 选项卡。
-
如图所示,窗口中以图形的形式显示任务事件。可以尝试点击 Zoom 栏的 ALL、+ 和 - 来调整 Grid 到 1 秒左右,或调整到 20us 左右查看每次 LED 状态变化时的任务切换细节。
提示: 如果 Event Viewer 不工作,打开 Trace Records 并确认 ITM 31 帧显示正常。Core Clock 是否正确?这个工程运行在 48 MHz(NUCLEO-F401RE)。
Cortex-M3 警告: 利用上面提到的读、写方式,μVision 会实时更新目标板卡的所有 RTX 信息。Event Viewer 使用 ITM,有轻微的侵入性。
数据在程序运行的时候更新,并不需要在源代码中插入专门的观察代码。你会发现这个特点非常好!记住,所有版本的 MDK 中都提供 RTX 的源代码。
提示: 这些 RTX Kernel Awareness 窗口中的功能可以使用 ULINK2、ULINK-ME、ULINK pro、ST-Link V2 及 J-Link。
18) Logic Analyzer 窗口:图形化地实时观察变量
μVision 包含图形化 Logic Analyzer 窗口,在 STM32 中可以利用 Serial Wire Viewer 实时显示多达四个变量。RTX_Blinky 使用一个任务来生成 LED 的闪烁,我们可以画出这个波形的图像。
-
关闭 RTX Viewer 窗口,停止运行处理器
并退出 Debug 模式
。
-
如图,在
RTX_Blinky.c
中添加一个全局变量unsigned int led_status
。 -
如图,在
RTX_Blinky.c
的blinkLED
任务中添加 2 行:led_status = 1;
和led_status = 0;
,大约在第 70 行左右的位置(在LED_On
和LED_Off
函数调用的前面)。
-
选择菜单 File/Save All 或点击
。
-
Rebuild 工程
,烧写 flash
。
-
进入 Debug 模式
。
-
现在可以运行程序了
。
-
打开菜单 View/Analysis Windows 并选择 Logic Analyzer,或者选择工具栏上的 LA 按钮
。
-
点击 RTX_Blinky.c 选项卡,右键点击
led_status
变量并选择 Add value to… 及 Logic Analyzer,led_status
变量将添加到 LA。
提示: 如果不能添加变量到 LA,请确认 Trace Config 设置正确。要添加变量到 LA 必须开启 Serial Wire Viewer。
Logic Analyzer 可以显示静态或全局的变量、结构体和数组。
不能显示局部变量:请转换为静态或全局变量。如果要观察外设寄存器,请使用变量读取或写入,然后把变量添加进 LA。 -
点击 LA 左上角的 Setup… 按钮,设置 Display Range Max 为 0x3。
-
点击 Close 回到 LA 窗口。
-
使用 All、Out 和 In 按钮使图形中网格大小是 0.5 秒左右。如果需要的话,移动滚动条到最右边。
-
选择 Signal Info 和 Show Cycles,点击以标记一个位置,移动光标得到时序信息。在波形上放置光标以获得时序和其他信息,如图。
-
点击 Update Screen 栏的 Stop 按钮可以停止数据采集。
提示: 也可以在 Watch 和 Memory 窗口中添加变量,实时显示或修改。
提示: 可以显示表示变量的数学运算的信号,这在物理世界中是无法测量的。
21) Serial Wire Viewer(SWV)配置窗口(供参考)
跟踪功能的配置主要是在图中所示的 Trace 选项卡中完成的。μVision 中没有全局的 SWV 选项,对每个工程、以及工程中的每个 target 设置,都需要单独配置 SWV,配置信息存储在工程中。这个窗口有两种方法进入:
A. 在编辑模式中: 选择 Target Options 或者按 ALT+F7,并选择 Debug 选项卡。点击窗口右侧的 Settings,再选择 Trace 选项卡。启动 μVision 时默认是编辑模式。
B. 在 Debug 模式中: 选择菜单中的 Debug/Debug Settings,再选择 Trace 选项卡。Debug 模式用 按钮进入。
1) Core Clock: SWV 的 CPU 时钟频率。在工程的启动代码或者 Abstract.txt 中可以找到 CPU 时钟频率,通常叫 SYSCLK 或主时钟频率。除非使用的是 ULINK pro 调试器,否则这个选项必须填写正确。
2) Trace Enable: 使能 SWV 和 ITM。这个选项只能在编辑模式修改。不会影响 Watch 和 Memory 窗口的更新。
3) Trace Port: 使用 ST-Link 时,这个选项是不可更改的。
4) Timestamps: 使能时间戳,选择预分频器。预分频器默认是1。
5) PC Sampling: 对 PC 指针的采样:
a. Prescaler: 1024*16(默认值)指的是每 16,384 个 PC 指针会显示 1 个,其他的不会采集。
b. Periodic: 使能 PC 指针采样。
c. On Data R/W Sample: 显示造成逻辑分析仪中所列的变量的读写对应的指令地址。这个功能与数据跟踪有关,但与 PC 采样无关。
6) ITM Stimulus Ports: 使能用于在 μVision 中输出数据的类似 printf 的语句的 32 位寄存器。端口 31(a)用于 Keil RTX Viewer,实时内核识别(awareness)窗口;端口 0(b)用于 Debug (printf) Viewer;其他位在 μVision 中没有使用。
Enable: 显示 32 位十六进制数,代表哪些端口是使能的。
Privilege: Privilege 用于 RTOS 指定哪些 ITM 端口可以在用户程序中使用。
7) Trace Events: 使能各种 CPU 计数器。除了 EXCTRC 之外,其他的都是 8 位计数器。每个计数器是累积的,每 256 周期产生计数器溢出事件。Counter 窗口显示计数器的值,Instruction Trace 窗口显示计数器溢出并重新计数产生的事件。
a. CPI: 从第一个指令到每个指令所用的额外周期数,其中包括指令取指拖延(instruction fetch stall)。
b. EXC: CPU 的异常(exception)开销的累积周期数,包括入栈和返回操作,不包括花费在异常处理程序的时间。
c. Sleep: CPU 在睡眠模式的累积周期数,使用 FCLK 时钟。
d. LSU: 从第一个周期开始,花费在 load/store 上的累积周期数。
e. Fold: Folded 指令的累积数量。这个结果来自那些已经从流水线上移除(flush)了无用指令,从而导致零执行周期的预测分支指令。(译者注:我架构学的烂,这句不太会翻:These results from a predicted branch instruction where usused instructions are removed (flushed) from the pipeline giving a zero cycle execution time.)
f. EXCTRC: 异常跟踪。这一项与上面其他项有所不同,不是一个计数器。这个选项使能 Trace Exceptions 窗口中异常的显示。这个功能通常在调试中使用,用来显示异常。
提示: 计数器在单步执行是也会累加,这提供了很有用的信息。计数器是映射在存储器上的,可以在程序中读取。