diff --git a/Software/Applications/VSCode/VSCode_ARM_CortexM_开发.md b/Software/Applications/VSCode/VSCode_ARM_CortexM_开发.md index 45ab0fd..168414e 100644 --- a/Software/Applications/VSCode/VSCode_ARM_CortexM_开发.md +++ b/Software/Applications/VSCode/VSCode_ARM_CortexM_开发.md @@ -19,6 +19,13 @@ published: true - [2.1. 基本调试](#21-基本调试) - [2.2. ARMCC 编译器的额外调试配置](#22-armcc-编译器的额外调试配置) - [2.3. 使用 RTT](#23-使用-rtt) + - [2.4. 调试断点](#24-调试断点) + - [2.4.1. 条件断点](#241-条件断点) + - [2.4.2. 记录点](#242-记录点) + - [2.4.3. 触发断点](#243-触发断点) + - [2.4.4. 数据断点](#244-数据断点) + - [2.4.5. 函数断点](#245-函数断点) + - [2.4.6. 计数断点](#246-计数断点) - [3. 国产芯片及 CMSIS-DAP 调试器的支持](#3-国产芯片及-cmsis-dap-调试器的支持) - [3.1. PyOCD 的安装](#31-pyocd-的安装) - [3.2. 关于 PyOCD 的扩展说明](#32-关于-pyocd-的扩展说明) @@ -202,6 +209,91 @@ pyocd.exe rtt --target --pack <"/Path/To/Nationstech.N32L40x_ 截止目前(2024年,版本 0.36.0),PyOCD 无法支持 GDB Server 和 RTT 功能的同时使用,官方有同时使能该功能的计划,并在 2022 年有所[讨论](https://github.com/pyocd/pyOCD/issues/1439),但尚未见该功能完成,讨论也仍处于 Open 状态。 +### 2.4. 调试断点 + +VSCode 下调试断点的基本使用方法与其他 IDE 差别不大,在源码中需要打断点的位置按 F9 即可,断点可以被禁能或移除。 + +除普通断点外 VSCode 还支持:**条件断点(Conditional Breakpoint)、记录点(Logpoint)、触发断点(Hit Breakpoint)、数据断点(Watchpoints)**和**函数断点(Function Breakpoint)**。另外,断点还支持计数触发功能。以上断点功能,实际上是由 Cortex-Debug 插件实现的。 + +以下针对各种类型的特殊断点进行说明。 + +#### 2.4.1. 条件断点 + +当程序执行到某行,且满足设定的条件表达式时,暂停程序的执行。 + +在需要打断点的源码行号前右击鼠标,选择“Add Conditional Breakpoint”;或按 F9 添加断点后,右击该断点,选择“Edit Breakpoint”,在下拉列表中选择“Expression”,将一个普通断点转换为 Conditional Breakpoint。 + +Expression 对话框中的键入条件表达式,然后回车确认。当程序执行到此行,且满足所设定的条件时,程序暂停。 + +#### 2.4.2. 记录点 + +记录点是一种特殊的断点,用于在不暂停程序执行的情况下记录日志信息。其功能首先在 Cortex-Debug V1.3.0 版本上实现。 + +在需要打断点的源码行号前右击鼠标,选择“Add Logpoint”;或按 F9 添加断点后,右击该断点,选择“Edit Breakpoint”,在下拉列表中选择“Log Message”,将一个普通断点转换为 Logpoint。 + +Log Message 对话框中的键入格式化字符串,与 printf 类似,比如需要打印变量 counter0 和 counter1 的值,其语法格式为: + +```bash +"Value of: counter0 is %d, counter1 is %d\n" counter0 counter1 +``` + +与 printf 的区别是参数间使用空格而非逗号做间隔。 + +当程序执行到带有记录点的代码行时,指定的日志信息将被输出到“Debug Console”,程序不会暂停,而是继续执行。 + +记录点对于在不中断程序流程的情况下记录变量值和调试信息非常有用。 + +#### 2.4.3. 触发断点 + +触发断点是一种在命中另一个断点后自动启用的断点。 + +在需要打断点的源码行号前右击鼠标,选择“Add Triggered Breakpoint”;或按 F9 添加断点后,右击该断点,选择“Edit Breakpoint”,在下拉列表中选择“Wait for Breakpoint”,将一个普通断点转换为 Hit Breakpoint。 + +Wait for Breakpoint 对话框中选择作为触发源的断点即可。当源断点被触发后,对应的 Hit Breakpoint 被激活。 + +#### 2.4.4. 数据断点 + +也可以叫监控断点,当监控到**数据/变量**被改变、读取或访问时,暂停程序的执行。数据断点只能监控全局变量,或在函数范围内监控局部变量。一旦程序执行超出变量作用范围,该断点失效。当前版本的 Cortex-Debug 下,为**数据断点**设置条件是不起作用的,若想实现谋数据变为特定值时暂停的功能,需要进行变通,比如统一由某个函数修改数据,然后在该函数中为其设置**条件断点**,或使用**带条件的函数断点**。 + +数据断点添加比较特别,需要在调试界面的 Variables 窗口中右击需要监控的全局变量,或当前作用域下的局部变量。然后选择:“Break on Value Read”、“Break on Value Change”或“Break on Value Access”。 + +数据断点将被添加到调试界面的 Breakpoints 窗口中,因此可以像操作其他断点那样对其禁能或移除。 + +#### 2.4.5. 函数断点 + +在调试界面的 Breakpoints 窗口中点击右上角的“+”按钮,输入函数名称,就可以添加函数断点。当程序执行到对应函数时,将暂停执行。 + +函数断点的功能比较强大,一方面,可以同时为多个同名函数设置函数断点,比如被 weak 关键字修饰的函数以及实际使用的函数,或 C++ 类继承中的重载函数、多态函数,对于这样的函数,一旦设置断点,便全部生效。有的时候,由于条件编译等原因不好确认多个同名函数到底使用了哪个时,也可以使用**函数断点**帮忙确认。 + +另一方面,函数断点可以设置计数或条件。这样可实现进入函数几次,或进入函数后还要满足什么条件才能暂停执行。 + +比如要监控数据变为谋特定值时暂停程序执行,可在每次修改数据的后调用一个测试函数,使被修改的数据作为参数传入该函数: + +```cpp +void test_value(int v) +{ + (void)v; +} +``` + +然后为该函数设定**函数断点**并为参数 v 设定条件。调试系统将在每次修改数据并进入 test_value() 函数后检查条件,一旦条件满足,将暂停执行。 + +**函数断点**支持使用内存地址,这样可以为某个具体对象的函数方法设定**函数断点**。只要在该对象生成后,从调试窗口获取该对象地址即可,后面设置方法与普通**函数断点**相同,即在调试界面的 Breakpoints 窗口中点击右上角的“+”按钮,输入 + +```bash +((my_class *) 0xcccccccc)->my_method +``` + +即可。 + +#### 2.4.6. 计数断点 + +VSCode 下,可以为**普通断点**和**函数断点**设置计数值,以达到满足命中次数要求时,再暂停执行的目的。需要注意的是,第一次命中计数值为 0,如果设定值为 3,将在第四次命中时触发断点,暂停程序。 + +按 F9 添加断点后,右击该断点,选择“Edit Breakpoint”,在下拉列表中选择“Hit Count”,将为一个普通断点设置计数值。 + +在调试界面的 Breakpoints 窗口中,点击**普通断点**或**函数断点**的“Edit Condition”按钮,选择“Edit Hit Count”可以为对应的断点设置计数值。 + ## 3. 国产芯片及 CMSIS-DAP 调试器的支持 通常国产芯片会提供 Keil 的 pack 文件,以及 JTAG 扩展支持该芯片的方法。因此如果使用 Keil+DAP 或者使用 EIDE+JTAG 均可下载和调试。但使用 EIDE+DAP 就需要变通一下,因为 EIDE 所支持的调试器中并没有 Keil 中的 CMSIS-DAP 选项,只有 OpenOCD 和 PyOCD。而想让 OpenOCD 支持某款芯片就要编写该芯片的 Flash 算法,这个方法有些复杂。