STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试

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 软件

  1. 从 Keil 网站上下载 MDK 5.10 或更新的版本:www.keil.com/mdk5/install Download MDK-Core

  2. 将 MDK 安装到默认路径。安装到其他路径也是可以的,本教程会以默认路径为例:C:\Keil_v5

  3. 本教程使用C:\MDK\做为例程目录,建议同样使用这个默认路径。

  4. 如果 MDK 安装在其他路径,实验中需要做对应的路径修改。

  5. (译者注:原文没有5,P.S. 上面这一段真贫)

  6. Keil 网站上可以找到 DSP5 例程。

  7. 这个实验可以用评估版本(MDK-Lite)来完成,不需要购买授权。

  8. 不需要额外的调试器,只需准备 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)来做。

(译者注:由于软件版本和板卡的区别,这一部分和原文略有不同。)

  1. 将电脑连接到外网上,下载 Software Pack 需要外网连接。

  2. 点击桌面上的图标 Keil图标 启动 μVision。

  3. 点击工具栏上的按钮 Pack Installer 按钮 打开 Pack Installer。如果出现 Pack Installer 欢迎界面,阅读之后关闭它。

  4. 这里应该出现下面这个窗口。在 Board 选项卡中,选择 NUCLEO-F401RE,右侧 Packs 选项卡中的列表会自动筛选。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第1张图片

  5. 也可以在 Search 栏输入 NUCLEO 进行筛选。

  6. 注意:窗口右下角应该显示“ONLINE”。如果显示的是“OFFLINE”,请检查外网连接之后再继续下面的步骤。

  7. 如果在 Pack Installer 启动的时候没有连接到外网,列表中将不会显示内容。这时候需要在连接到网络后,点击菜单 Packs/Check for Updates 或者工具栏中的 Check for Updates 刷新一下。

2) 安装 STM32F4 Software Pack

  1. 点击 Packs 选项卡,可以看到 ARM::CMSIS Software Pack 是默认安装好的。

  2. 选择 Keil::STM32F4xx_DFP 和 Keil::STM32NUCLEO_BSP 并点击 Install,这两个 Software Pack 会下载并安装在默认文件夹 C:\Keil_v5\ARM\Pack\Keil 中。下载估计需要两三分钟的时间。

  3. 下载完成后,应显示“Up to date”状态:Up to Date

3) 安装 Blinky MDK 例程

  1. 选择 Examples 选项卡,出现如下窗口: 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第2张图片

  2. 选择 Blinky (NUCLEO-F401RE)。

  3. 点击 Copy Copy

  4. Copy Example 窗口如图所示。选择 Use Pack Folder Structure,取消选择 Launch μVision。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第3张图片

  5. 输入 C:\MDK,点击 OK 完成 Blinky 工程的复制。

  6. Blinky 工程已经复制到 C:\MDK\Boards\ST\NUCLEO-F401RE 了。

  7. 不需要复制 CMSIS-RTOS Blinky 程序,我们会有一个更有意思的4线程版本。

    提示:复制例程时,一开始的默认路径是 C:\Users\< user >\Documents,这篇教程使用C:\MDK\ 做为默认路径。实际上可以选择任意路径。

  8. 关闭 Pack Installer。以后随时可以通过点击图标 Pack Installer 按钮 来打开。

提示:Update 按钮说明 Software Pack 有更新可以下载 Update

提示:如果找到目录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 例程

  1. 从 http://www.keil.com/appnotes/docs/apnt_230.asp 上获得例程的 zip 文件。

  2. 解压缩到 C:\MDK\Boards\ST\STM32F4-Discovery\。(译者注:这个程序是对 Discovery 开发板的。)

7) 测试 ST-Link V2 的连接

  1. 用 USB 线将 NUCLEO 开发板连接到电脑上。

  2. 如果 ST-Link USB 驱动程序安装正确,应该可以听到正常的 USB 设备连接的系统声音。否则需要根据下一章的指示,手动安装驱动程序。

  3. 两个红色 LED 应该点亮:LD1 (COM)和 LD3(PWR)。

  4. 启动 μVision Keil图标 并选择 Project/Open Project。

  5. 选择 Blinky 工程 C:\MDK\Boards\ST\NUCLEO-F401RE\Blinky\Blinky.uvprojx

  6. 在这个地方选择 STM32F401 Flash:Project Option

  7. 点击 Target Options Target Options 或者按 ALT+F7,并选择 Debug 选项卡: 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第4张图片

  8. 点击 Settings,会出现下面所示的窗口。如果显示出了 IDCODE 和 Device Name,说明 ST-Link 工作良好,可以继续下面的教程。点击两次 OK 返回 μVision 主界面。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第5张图片

  9. 上图中 Serial Number 框里出现一串数字说明 ST-Link 调试器已经连接到了 μVision。

  10. 如果 SW Device 框中没有显示,或者显示 error,这个问题在继续本教程之前必须要解决。请参照下一节内容:安装 ST-Link USB 驱动程序。

  11. 如果已经显示正常,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 驱动程序:(当上面的测试没有通过时)

  1. 先断开 NUCLEO 开发板和电脑之间的 USB 连接。

  2. 需要手动运行 stlink_winusb_install.bat 来安装 USB 驱动,这个文件存放在C:\Keil_v5\ARM\STLink\USBDriver 中。找到这个文件并双击来安装驱动程序。

  3. 连接 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 开发平台和真实的目标硬件。

  1. 点击桌面图标 Keil图标 启动 μVision,用 USB 线将 NUCLEO 开发板的 CN1 连接到电脑上。

  2. 选择 Project/Open Project,打开文件 C:\MDK\Boards\ST\NUCLEO-F401RE\Blinky\Blinky.uvprojx

  3. ST-Link 会默认被选择。第一次运行 μVision 和 NUCLEO 开发板的时候,可能需要安装 USB 驱动程序,详见上面章节。

  4. 点击 Rebuild 图标 Rebuild 编译源文件。也可以用旁边的 Build 图标 Build

  5. 点击 Load 图标 Load 对 STM32 的 flash 进行编程。Output 窗口中会显示这个过程。

  6. 点击 Debug 图标 Debug 进入 Debug 模式,如果出现 Evaluation Mode 对话框,点击 OK。 
    注意: 当下载到 flash 时才需要使用 Load 图标,如果选择的是 RAM 运行则不需要。

  7. 点击 RUN 图标 RUN。注意:点击 STOP 图标 STOP 可以停止程序运行。

NUCLEO 开发板上的绿色 LED 会开始闪烁。 
按下开发板上蓝色的 USER 按键会暂停闪烁。

至此你已经了解如何编译工程、下载到 STM32 处理器的 flash 中、运行并停止程序!

注意: Blinky 程序已经永久的烧写到 flash 中了,开发板可以独立运行这个程序,直到下一次被烧写。

10) 硬件断点

STM32F4 共有六个硬件断点,可以在程序运行过程中随时设置或取消。

  1. 在 Blinky 程序运行过程中,打开 Blinky.c 文件,点击 main() 函数中 for 循环里的某一行左侧边缘深灰色区域。

  2. 会出现一个红色的圆形标志,程序会停止运行。

  3. 请注意断点同时显示在源代码窗口和反汇编窗口,如下图。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第6张图片

  4. 不论是反汇编窗口还是源代码窗口,左侧边缘显示深灰色方形的区域表示这些代码行存在汇编指令,可以在这里设置断点。

  5. 每次点击 RUN 图标 RUN,程序会运行到下一次遇到断点。

  6. 可以尝试点击 Single Step(Step In)Step In 、Step OverStep Over 和 Step OutStep 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 窗口显示或隐藏。

  1. 运行并停止 Blinky,点击 Call Stack + Locals 选项卡。

  2. 下图展示了Call Stack + Locals 窗口。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第7张图片 
    窗口中显示了当前活动函数的名称和局部变量列表。随同每个函数的名字会显示它被哪个函数或中断/异常调用。 
    当函数退出时,会从列表上移除。 
    最早调用的函数会出现在列表的底端。 
    这个列表只有在程序停止运行时有效。

  3. 点击 Step In 图标 Step In 或按 F11 键。

  4. 当单步运行到不同的函数时,观察它们在窗口上显示的变化。如果陷入到 Delay 函数的循环当中,可以用 Step Out Step Out 或 Ctrl+F11 键快速退出。

  5. 点击几次 Step In,观察其他函数。

  6. 右键点击一个函数名,尝试 Show Callee Code 和 Show Caller Code 选项。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第8张图片

  7. 点击 Step Out 图标 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 窗口不能观察局部变量。

  1. 停止运行处理器 STOP 并退出 Debug 模式 Debug

  2. 在 Blinky.c 的第24行左右,声明一个全局变量(这里变量名叫做value):unsigned int value = 0;

  3. 在第104行左右添加语句 value++; 和 if (value > 0x10) value = 0;,如图: 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第9张图片

  4. 选择菜单 File/Save All 或点击 Save All 。

  5. 点击 Rebuild Rebuild ,点击 Load Load 下载到 flash。

  6. 进入 Debug 模式 Debug ,点击 RUN RUN ,提示:可以在程序运行中设置 Watch 和 Memory 窗口。

  7. 在 Blinky.c 中,右键点击变量 value 并选择 Add value to … 及 Watch 1,Watch 1 窗口会打开并显示value 如下图。

  8. value会实时增加到0x10。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第10张图片 
    提示: 也可以框选 value,单击并拖拽到 Watch 或 Memory 窗口。 
    提示: 请确认菜单 View/Periodic Window Update 在选中状态。

  9. 也可以在 Name 下面区域双击或按 F2,再手动输入或复制粘贴变量名。或是打开菜单 View/Symbols Window 来输入变量。 
    提示: 如果要拖拽到一个非活动的选项卡,选中变量按住鼠标并移动至希望打开的选项卡名字上,等待其打开并拖拽鼠标到窗口内释放。

Memory 窗口

  1. 右键点击 value 并选择添加到 Memory 1,或手动添加 value 到 Memory 1。如果需要的话,选择菜单 View/Memory 来打开 Memory 1 窗口。

  2. 注意 value 被当作了一个指针,其值做为地址显示在了 Memory 1 上。这个操作在想要看一个指针指向的地址的时候很有用,但不是我们现在想看到的。

  3. 在变量名前面加一个“&”符号并按回车键,改为显示变量的物理地址(0x2000000C)。

  4. 右键点击 Memory 1 窗口并选择 Unsigned/Int。

  5. value 的值现在以32位的形式显示了。

  6. Watch 和 Memory 窗口都是实时更新的。

  7. 在 Memory 窗口中,鼠标移动到数据区域右键点击,选择 Modify Memory,可以修改对应地址的值。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第11张图片

提示: 这些操作通常不会占用 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 窗口中观察局部变量

(译者注:由于板卡的区别,这一部分和原文略有不同。)

  1. 运行 Blinky.c 程序。我们将使用 main() 中的局部变量 num

  2. 在 Blinky.c 的第87行附近,main 函数的开头,找到声明这个局部变量的地方。

  3. 右键点击这个变量,把它输入到 Watch 1 窗口中。注意由于局部变量的值可能存放在 CPU 寄存器内,μVision 不能在程序运行时访问,因此会显示 < not in scope >。如果 μVision 显示无法添加变量,请尝试停止再开始 Blinky 程序。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第12张图片

  4. 在 Blinky.c 的主循环里添加一个断点,会使程序停止,这时会出现当前变量的值。

  5. 删除这个断点。

  6. 局部变量或自动变量可能存放在 CPU 寄存器内,μVision 不能在程序运行时访问。局部变量 num 只有在main 函数运行时才会存在,在其他函数或中断/异常处理程序中是不存在的,因此 μVision 无法确定这个变量的值。

  7. 停止运行处理器 STOP 并退出 Debug 模式 Debug 。

如何实时更新局部变量:

只需把 num 改为全局变量定义在 Blinky.c 中。

  1. 把 num 的声明移动到 main() 的外面、Blinky.c 的最前面,把它改为全局变量:
unsigned int value = 0;
int32_t num = 0;
  • 1
  • 2

提示: 也可以定义成静态变量,如: static int32_t num = 0; 。 
提示: 在编辑模式和 Debug 模式都可以编辑文件,但编译只能在编辑模式进行。

  1. 点击 Rebuild 按钮编译源文件,确认没有 error 和 warning。

  2. 点击 Load 按钮 Load 下载到 flash,窗口的左下角会显示进度条。

  3. 进入 Debug Debug 模式并点击 RUN RUN 。

  4. 这时 num 变量已经可以实时更新了。

  5. 可以读(写)全局或静态的变量、结构体,以及其他以变量形式放在函数与函数之间的东西,包括外设的读写。(译者注:这一句我没翻好: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.)

  6. 停止运行处理器 STOP 并退出 Debug 模式 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):

  1. 停止运行处理器 STOP 并退出 Debug 模式 Debug 。

  2. 点击 Target Options Target Options 或者按 ALT+F7,并选择 Debug 选项卡,点击窗口右侧的 Settings,确认选择的是 SW 模式。ST-Link中,SWV 强制使用 SW 模式。

  3. 选择 Trace 选项卡,选择 Trace Enable,取消选择 Periodic 和 EXCTRC,设置 Core Clock 为 48 MHz。其他选项如图所示。

    译者注:CPU 时钟频率很重要,请务必按照实际值设置。Blinky 工程的时钟频率在 Abstract.txt中可以找到。如果使用的是其他板卡,请自行检查时钟频率。

  4. 点击 OK 返回 Target Options。

  5. 再次点击 OK 返回主界面。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第13张图片

配置 Logic Analyzer:

  1. 进入 Debug 模式 Debug。打开菜单 View/Analysis Windows 并选择 Logic Analyzer,或者选择工具栏上的 LA 按钮 LA 按钮 。 
    提示: 可以在程序运行中配置LA。

  2. 点击 Blinky.c 选项卡,右键点击 value 变量并选择 Add value to… 及 Logic Analyzer。也可以手动拖拽来添加。

  3. 点击 LA 左上角的 Setup… 按钮进入 LA 设置窗口。

  4. 选择 value,设置 Display Range Max 为 0x15。

  5. 点击 Close。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第14张图片

运行程序: 注意: 可以在程序运行中配置LA。

  1. 点击 RUN RUN。点击 Zoom Out 使图形中网格大小是5秒左右。

  2. 变量 value 的值将增加到 0x10(十进制16)再重新设为 0。 
    提示: 如果没有看到波形,请退出并重新进入 Debug 模式以刷新 LA。可能还需要重新上电 NUCLEO 板卡。请确认 Core Clock 的数值正确。 
    提示: Logic Analyzer 中最多可以显示4个变量,必须是全局变量、静态变量或原始地址如*((unsigned long*)0x20000000)

  3. 请注意当 USER 按钮按下时,变量的值会随之停止增加。当然也请注意观察这个现象是如此直观。

  4. 选择 Signal Info、Show Cycles、Amplitude 及 Cursor,观察 LA 的测量功能。点击 Update Screen 栏的 Stop 按钮可以停止 LA。

  5. 停止运行处理器 STOP 。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第15张图片

15) 观察点:条件断点

不需要使用 Serial Wire Viewer

STM32 处理器有6个硬件断点,可以不停止 CPU 运行而在线设置。STM32 还有四个观察点。观察点可以认为是有条件的断点。观察点和逻辑分析仪共用比较器,因此要使用观察点,需要在逻辑分析仪中保证至少两个变量空位置。观察点也被称作 Access Breakpoint。

  1. 使用与前一练习相同的 Blinky 设置,停止程序运行,保持在 Debug 模式。

  2. 在 Blinky.c 中创建的全局变量 value 将用于观察点的探究。

  3. 配置观察点不需要 SWV Trace,但在这个练习中我们会用到逻辑分析仪。

  4. 延续上一个联系,变量 value 应保持在逻辑分析仪中。

  5. 在 μVision 菜单中选择 Debug 并点击 Breakpoints,或者按 Ctrl+B 键。

  6. 将 Read 和 Write 两个 Access 都选中,在 Expression 框中输入“value == 0x5”,不含引号。

  7. 点击 Define,应出现图中所示的一行。点击 Close。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第16张图片

  8. 如果 Watch 1 中没有 value 变量,添加一个进去。

  9. 打开菜单 Debug/Debug Settings 并选择 Trace 选项卡,选择“on Data R/W sample”,并保持 EXCTRC 不选中。

  10. 点击两次 OK 回到主界面。打开 Trace Records 窗口。 
    Trace Records 按钮

  11. 点击 RUN RUN 。

  12. 在逻辑分析仪和 Watch 窗口中可以看到 value 在变化。

  13. 当 value 等于 0x5 时,Watchpoint 会停止运行程序。

  14. 注意如下图所示的 Trace Records 窗口中的 data write 记录:0x5 在 Data 列的最后一行,另外还有写入数据的地址和写入指令对应的 PC 指针。当前使用的是 ST-Link,如果用 ULINK2 会显示相同的窗口,但如果是 ULINK pro 或 J-Link(黑盒子)显示的窗口会略有区别。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第17张图片

  15. 查看 Breakpoints 窗口中的 Help 按钮可以了解另一种可用的表达式格式,有些目前没有在 μVision 中实现。

  16. 点击 RUN 可以重复本次练习。

  17. 练习结束后,停止程序运行,点击 Debug 并选择 Breakpoints(或按 Ctrl+B),删除所有断点。

  18. 退出 Debug 模式。

提示: 观察点不能像硬件断点那样在程序运行中设置。

提示: 在 Breakpoints 窗口中双击观察点,它的信息会放在下面的配置区域供编辑。点击 Define 会创建另一个观察点。如要删除旧的观察点,需要选中它并点击 Kill Selected,或者尝试下一条提示:

提示: 表达式旁边的选框可以用来临时屏蔽观察点。

提示: 逻辑分析仪中也可以输入原始地址,如:*((unsigned long*)0x20000000)

图中显示了变量 value 的触发点为 0x5 时,逻辑分析仪的显示情况。这里运行了三次。

STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第18张图片

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\

  1. 在 μVision 的编辑模式(非 debug 模式)中选择 Project/Open Project。

  2. 打开文件 C:\MDK\Boards\ST\NUCLEO-F401RE\RTX_Blinky\RTX_Blinky.uvprojx

  3. 如果出现 Update Configuration Files 窗口,选择 Cancel。

  4. 这个工程已经为 ST-Link V2 调试器设置好了。

  5. 点击 Rebuild 图标 Rebuild 编译源文件,应该不会出现 error 或 warning。

  6. 点击 Load 图标 Load 手动编程 flash。左下角的进度条会显示这个过程。

  7. 点击 Debug 图标 Debug 进入 Debug 模式。点击 RUN 图标 RUN

  8. NUCLEO 开发板上的绿色 LED 会开始闪烁。

  9. 点击 STOP 图标 STOP 。

我们将借助 Kernel Awareness 窗口来探索 RTX 的运行。

17) 使用 Serial Wire Viewer (SWV)的 RTX Kernel Awareness

用户经常需要了解当前执行的任务的编号和其他任务的状态,这些信息一般被 RTOS 存储在一个结构体或内存空间中。Keil 为 RTX 提供了 Task Aware 窗口,其他 RTOS 公司同样也提供 μVision 中的对应的 awareness 插件。

  1. 点击 RUN 图标 RUN 运行 RTX_Blinky。

  2. 打开菜单 Debug/OS Support 并选择 System and Thread Viewer,图中所示的窗口将打开。可以拖住这个窗口并移动至屏幕中间。窗口中的数值是实时更新的,使用的读写技术与 Watch 和 Memory 窗口相同。 
    重要提示: 需要选中菜单中的 View/Periodic Window Update。

  3. 打开菜单 Debug/OS Support 并选择 Event Viewer。由于还没有配置 SWV,估计不会有数据显示。

STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第19张图片

**RTX Viewer:配置 Serial Wire Viewer (SWV):

需要激活 Serial Wire Viewer 来使 Event Viewer 运行。

  1. 停止运行处理器 STOP 并退出 Debug 模式 Debug 。

  2. 点击 Target 选择框旁边的 Target Options Target Options ,选择 Debug 选项卡。

  3. 选择 ST-Link Debugger 旁边的 Settings。

  4. 在 Debug 窗口中,确认选择的是 SW 模式而不是 JTAG。SWV 只能运行在 SW 模式。

  5. 点击 Trace 选项卡。

  6. 设置 Core Clock 为 48 MHz,并选中 Trace Enable。

  7. 取消选择 Periodic 和 EXCTRC,如图所示。

    译者注:CPU 时钟频率很重要,请务必按照实际值设置。Blinky 工程的时钟频率在 Abstract.txt中可以找到。如果使用的是其他板卡,请自行检查时钟频率。

  8. 需要选中 ITM Stimulus Port 31,RTX Viewer 使用这个方法获得内核 awareness 信息并显示在 Event Viewer 中。这个功能有轻微的侵入性。

  9. 点击两个 OK 返回主界面。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第20张图片 
    Serial Wire Viewer 配置完成!

  10. 进入 Debug 模式并点击 RUN。

  11. 选择 Task and System 选项卡,显示应该在更新。

  12. 点击 Event Viewer 选项卡。

  13. 如图所示,窗口中以图形的形式显示任务事件。可以尝试点击 Zoom 栏的 ALL、+ 和 - 来调整 Grid 到 1 秒左右,或调整到 20us 左右查看每次 LED 状态变化时的任务切换细节。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第21张图片
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第22张图片

提示: 如果 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 的闪烁,我们可以画出这个波形的图像。

  1. 关闭 RTX Viewer 窗口,停止运行处理器 STOP 并退出 Debug 模式 Debug 。

  2. 如图,在 RTX_Blinky.c 中添加一个全局变量 unsigned int led_status

  3. 如图,在 RTX_Blinky.c 的 blinkLED 任务中添加 2 行:led_status = 1;led_status = 0;,大约在第 70 行左右的位置(在 LED_On 和 LED_Off 函数调用的前面)。 
    STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第23张图片

  4. 选择菜单 File/Save All 或点击 Save All 。

  5. Rebuild 工程 Rebuild ,烧写 flash Load 。

  6. 进入 Debug 模式 Debug 。

  7. 现在可以运行程序了 RUN 。

  8. 打开菜单 View/Analysis Windows 并选择 Logic Analyzer,或者选择工具栏上的 LA 按钮 LA 按钮 。

  9. 点击 RTX_Blinky.c 选项卡,右键点击 led_status 变量并选择 Add value to… 及 Logic Analyzer,led_status 变量将添加到 LA。 
    提示: 如果不能添加变量到 LA,请确认 Trace Config 设置正确。要添加变量到 LA 必须开启 Serial Wire Viewer。 
    Logic Analyzer 可以显示静态或全局的变量、结构体和数组。 
    不能显示局部变量:请转换为静态或全局变量。如果要观察外设寄存器,请使用变量读取或写入,然后把变量添加进 LA。

  10. 点击 LA 左上角的 Setup… 按钮,设置 Display Range Max 为 0x3。

  11. 点击 Close 回到 LA 窗口。

  12. 使用 All、Out 和 In 按钮使图形中网格大小是 0.5 秒左右。如果需要的话,移动滚动条到最右边。

  13. 选择 Signal Info 和 Show Cycles,点击以标记一个位置,移动光标得到时序信息。在波形上放置光标以获得时序和其他信息,如图。

  14. 点击 Update Screen 栏的 Stop 按钮可以停止数据采集。

STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第24张图片

提示: 也可以在 Watch 和 Memory 窗口中添加变量,实时显示或修改。

提示: 可以显示表示变量的数学运算的信号,这在物理世界中是无法测量的。

21) Serial Wire Viewer(SWV)配置窗口(供参考)

跟踪功能的配置主要是在图中所示的 Trace 选项卡中完成的。μVision 中没有全局的 SWV 选项,对每个工程、以及工程中的每个 target 设置,都需要单独配置 SWV,配置信息存储在工程中。这个窗口有两种方法进入:

A. 在编辑模式中: 选择 Target Options Target Options 或者按 ALT+F7,并选择 Debug 选项卡。点击窗口右侧的 Settings,再选择 Trace 选项卡。启动 μVision 时默认是编辑模式。 
B. 在 Debug 模式中: 选择菜单中的 Debug/Debug Settings,再选择 Trace 选项卡。Debug 模式用 Debug 按钮进入。

STM32 使用 Keil MDK 中的软件逻辑分析仪参与硬件调试_第25张图片

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 窗口中异常的显示。这个功能通常在调试中使用,用来显示异常。

提示: 计数器在单步执行是也会累加,这提供了很有用的信息。计数器是映射在存储器上的,可以在程序中读取。

你可能感兴趣的:(嵌入式)