STM32内核精讲 | 第十二章:调试与跟踪组件
💡 本文是《STM32内核精讲》栏目的第十二篇。前十一篇我们学习了寄存器模型、异常处理、AAPCS、复位序列以及低功耗模式。从本篇开始,我们将进入内核的调试与跟踪世界——这是理解内核“运行时行为”的关键工具集。掌握调试与跟踪组件,你将能实现无侵入的printf调试、精准的性能计数、代码覆盖率分析,以及内核状态的实时监控。
📌 一、引言:调试不只是打断点
很多嵌入式开发者认为,调试就是“打断点、单步执行、看变量”。当程序停止时,这些手段确实有效。但当问题发生在程序全速运行时——例如偶发的中断延迟、罕见的竞争条件、或者系统进入低功耗模式后的异常唤醒——传统的断点调试往往无能为力。
Cortex‑M 处理器内置了一套名为 CoreSight 的调试与跟踪架构。通过这套架构,我们可以在程序全速运行时,实时收集指令流、数据访问、性能计数以及软件打印信息,而不干扰程序的正常执行。
本章将系统性地介绍 CoreSight 的核心组件:ITM、DWT、ETM、TPIU、SWO,以及它们在 STM32CubeIDE、Keil 等环境中的具体应用。读完本章,你将彻底理解:
- 如何用 SWO 引脚实现无外设的
printf调试。 - 如何使用 DWT 的 CYCCNT 进行微秒级高精度计时和 CPU 负载统计。
- 指令跟踪(ETM)和数据跟踪(DWT)的区别与适用场景。
- 如何通过 SWV 实时监控异常统计和睡眠深度。
📌 二、CoreSight 架构概览:一个完整的片上调试系统
2.1 什么是 CoreSight?
CoreSight 是 ARM 推出的系统级调试与追踪架构,它为 SoC 提供了统一的调试和跟踪解决方案。其核心设计理念是:
- 非干预性(Non‑invasive) :调试和跟踪操作不影响 CPU 的正常执行。即使程序全速运行,跟踪数据也能实时输出,这对于调试低功耗模式下的唤醒时序、高频外设中断等“必须全速运行才能复现”的问题至关重要。
- 模块化与可扩展:CoreSight 的组件可以按需集成,不同厂商的组件遵循统一规范,保证了互操作性。
- 自动拓扑发现:通过 ROM Table 自动识别所有调试组件,调试器无需预存硬件信息即可连接。
2.2 CoreSight 核心组件架构
CoreSight 遵循“源→链路→接收端”的数据流逻辑。
调试通路(Debug Path) 负责外部调试器对 SoC 的访问。外部调试器通过 JTAG 或 SWD 接口连接调试访问端口(DAP,Debug Access Port),DAP 将请求转换为片上总线访问,进而操作 CoreSight 组件或 SoC 外设/内存。DAP 内部又分为多个访问端口(AP,Access Port),包括 AHB‑AP、APB‑AP、AXI‑AP 等,用于连接不同的总线。
跟踪源(Trace Source) 是生成调试/跟踪数据的源头。主要包括:
- ITM(Instrumentation Trace Macrocell) :软件跟踪宏单元,支持 printf 类调试输出和软件事件标记。
- DWT(Data Watchpoint and Trace) :数据观察点与跟踪单元,提供数据访问跟踪、性能计数和 PC 采样。
- ETM(Embedded Trace Macrocell) :嵌入式跟踪宏单元,跟踪 CPU 指令/数据执行流,支持完整的历史序列回放。
链路组件(Link) 负责转发和整合多源跟踪数据。主要包括:
- Trace Funnel:将多个 ATB(Advanced Trace Bus)数据流合并为一路。
- Replicator:将一路跟踪数据分发到多个接收端,实现“一源多收”。
接收端(Sink) 负责存储或输出跟踪数据到片外。主要包括:
- TPIU(Trace Port Interface Unit):跟踪端口接口单元,支持两种输出模式:
- 并行时钟模式(Clocked Mode):使用最多 4 条数据线,用于 ETM 指令跟踪等大数据量场景。
- 串行线输出模式(SWO,Serial Wire Output):使用单引脚(在 STM32 中通常为 PB3)异步串行输出,是 SWV 功能的硬件基础,可同时输出 ITM 和 DWT 的跟踪数据。
- ETB(Embedded Trace Buffer) :片上 RAM 存储跟踪数据,可通过 DAP 读取。
- ETR(Embedded Trace Router) :通过 AXI 接口将跟踪数据转发到系统内存,适合大数据量跟踪。
2.3 跟踪数据流的工作过程
ITM、DWT 和 ETM 生成的跟踪数据以数据包的形式通过 ATB 总线传输给 TPIU。TPIU 根据配置将数据格式化后,通过并行跟踪端口或 SWO 串行线输出。ETM 的指令跟踪必须使用并行跟踪端口,而数据跟踪和软件跟踪可以复用并行端口,也可以使用 SWO。
SWO 是 TPIU 串行输出模式下的物理引脚,可以同时输出 ITM 的软件跟踪数据(printf 调试)和 DWT 的硬件事件跟踪数据(PC 采样、数据访问、异常统计等)。这两类数据在 TPIU 中合并、格式化后,通过 SWO 引脚串行发送到调试器。
2.4 JTAG 与 SWD 的关系
JTAG 是行业标准的 5 引脚接口(TDI、TDO、TCK、TMS、可选 TRST),用于下载和调试程序。SWD 是 JTAG 的替代方案,仅使用两个引脚(SWCLK 和 SWDIO)即可提供相同的调试功能,并通过 SWO 引脚引入了数据跟踪功能。SWO 引脚在 JTAG 接口中与 TDO 复用,这意味着 SWO 跟踪只能在 SWD 接口模式下使用,JTAG 模式下无法访问 SWO。
📌 三、ITM:无侵入的 printf 调试
3.1 ITM 的原理与端口
ITM(Instrumentation Trace Macrocell,仪器跟踪宏单元)是 Cortex‑M 内核中的一个硬件模块,它的核心用途是支持调试信息的输出(例如 printf 格式输出)。ITM 包含 32 个刺激端口,允许不同的软件模块把数据输出到不同的端口,从而让调试主机可以把它们的信息分离开。每个端口都可以独立地使能/禁止。
ITM 的核心价值在于:
- 非侵入性:printf 输出不占用 UART 等外设资源,也不依赖芯片厂商的外设驱动。
- 实时性:即使程序全速运行,ITM 也可以通过 SWO 引脚将调试数据实时传输到调试器,不打断 CPU 执行。
- 简单易用:CMSIS 提供了
ITM_SendChar()函数(位于 core_cm3.h/core_cm4.h/core_cm7.h 中),只需重定向__io_putchar即可完成 printf 输出。
3.2 支持的 Cortex-M 内核
ITM 只支持 Cortex-M3、M4、M7 及更高版本的内核。Cortex-M0/M0+ 内核不支持 ITM,因此在 STM32F0、STM32L0 等型号上无法使用 SWO 调试。
3.3 SWO 引脚与硬件连接
SWO 是单引脚、异步串行通信接口。在 STM32 中,SWO 引脚通常与 PB3 复用,其复用功能为 TRACESWO(AF0)。具体引脚定义请查阅所用 MCU 的参考手册。
与一般的 SWD 调试接口需要 SWDIO 和 SWCLK 两根线相比,SWO 是额外的第三根线,用于输出跟踪数据。但注意,不是所有的开发板都把 SWO 引脚引出,在调试前需要确认硬件连接。
3.4 代码配置示例
将 printf 重定向到 SWV/ITM 需要以下步骤:
- 将
syscalls.c文件包含在工程中。printf() 会调用_write()函数,该函数在syscalls.c中有实现。 - 修改
__io_putchar函数:
int __io_putchar(int ch) {
ITM_SendChar(ch);
return(ch);
}
- 使能跟踪时钟和睡眠模式下的调试保持:
// 使能跟踪时钟(TRACE_CLK_EN,位21)以及睡眠模式下的调试连接(DBG_SLEEP,位22)
DBGMCU->CR |= DBGMCU_CR_TRACE_CLK_EN | DBGMCU_CR_DBG_SLEEP;
// 使能 ITM 端口0 和 ITM 全局控制
ITM->TER |= 0x1; // 使能刺激端口0
ITM->TCR |= ITM_TCR_ITMENA_Msk; // 使能 ITM 全局
- 配置 SWO GPIO(以 STM32 的 PB3 为例):
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef gpio_init = {0};
gpio_init.Pin = GPIO_PIN_3; // SWO 引脚为 PB3
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_PULLUP;
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init.Alternate = GPIO_AF0_TRACE; // 复用功能 AF0(TRACE)
HAL_GPIO_Init(GPIOB, &gpio_init);
3.5 在 IDE 中查看输出
以 Keil MDK 为例,完成配置后,进入调试模式,打开 Debug (printf) Viewer 窗口,即可观察到 MCU 通过 ST-LINK 向编译器输出的打印信息。
在 STM32CubeIDE 中,需要在 Run → Debug Configuration 中启用 SWV 相关的 Trace 配置,然后在 SWV Data Trace 窗口中查看 ITM 输出的数据。
📌 四、DWT:数据观察点与性能计数器
4.1 DWT 简介
DWT(Data Watchpoint and Trace,数据观察点与跟踪)是 CoreSight 中的另一个核心组件,主要用于系统调试及跟踪。DWT 包含多个计数器,典型地用于程序代码的“性能速写”(profiling)。通过编程它们,可以让计数器在溢出时发出跟踪数据包。
DWT 的主要功能包括:
- 数据观察点(Data Watchpoint) :监视特定内存地址的访问(读/写),当条件匹配时触发调试事件。
- 性能计数器:包括 CYCCNT(时钟周期计数器)、CPI(每条指令平均周期数)计数器、异常开销计数器等。
- PC 采样(PC Sampling) :周期性地记录程序计数器值,用于代码覆盖率分析和性能瓶颈定位。
- 事件跟踪:记录异常进入/退出、数据访问等事件。
4.2 CYCCNT:高精度时钟周期计数器
DWT 中最常用的组件是 CYCCNT 寄存器。它是一个 32 位向上的计数器,记录的是内核时钟运行的个数——内核时钟跳动一次,该计数器就加 1,精度非常高。
精度 = 1 / 内核时钟频率
最长计时时间 = 2^32 / 内核时钟频率
例如,如果内核时钟是 72 MHz,精度就是 1/72M ≈ 14ns,最长计时约 59.65 秒。对于 STM32H7 等 400 MHz 主频的芯片,计时精度高达 2.5ns。CYCCNT 溢出后会自动清零重新向上计数,因此在使用过程中需要考虑溢出处理。
4.3 如何使能 DWT 和 CYCCNT
使能 DWT 和 CYCCNT 需要经过以下三个步骤。
- 使能 DWT 外设:通过内核调试寄存器 DEMCR 的位 24 控制,写入 1 使能 DWT 功能。DEMCR 地址为
0xE000EDFC。
#define DEMCR (*(unsigned int *)0xE000EDFC)
#define TRCENA (0x01 << 24)
DEMCR |= TRCENA;
- 清空 CYCCNT 寄存器:CYCCNT 的基地址是
0xE0001004。在使能 CYCCNT 之前,先将其清零。
#define DWT_CYCCNT (*(unsigned int *)0xE0001004)
DWT_CYCCNT = 0;
- 使能 CYCCNT 计数器:通过 DWT 控制寄存器的位 0(CYCCNTENA)控制,写入 1 使能 CYCCNT 开始计数。
#define DWT_CTRL (*(unsigned int *)0xE0001000)
#define CYCCNTENA (0x01 << 0)
DWT_CTRL |= CYCCNTENA;
4.4 DWT 的实用场景
高精度计时与延时:利用 CYCCNT 可以实现微秒级的高精度延时。由于 CYCCNT 直接记录内核时钟周期,不受 SysTick 配置或中断优先级的影响,精度远高于普通循环延时。
uint32_t DWT_GetCycle(void) {
return DWT_CYCCNT;
}
void DWT_DelayUs(uint32_t us) {
uint32_t ticks = (SystemCoreClock / 1000000) * us;
uint32_t start = DWT_GetCycle();
while ((DWT_GetCycle() - start) < ticks);
}
代码执行时间测量:通过读取 CYCCNT 的前后差值,可以精确测量任意代码块的执行周期数。这在优化算法、对比不同实现方式的性能时非常有用。
CPU 负载统计:在 RTOS 中,可以利用 DWT 统计 CPU 使用率。在空闲任务中读取 CYCCNT 并计算空闲时间占比,从而得出 CPU 负载。
PC 采样与代码覆盖率:DWT 可以周期性地采样 PC 值,记录程序运行路径,用于分析代码覆盖率和定位执行热点。
📌 五、ETM:指令跟踪与代码覆盖率
5.1 ETM 的原理与作用
ETM(Embedded Trace Macrocell,嵌入式跟踪宏单元)是 CoreSight 中功能最强大的跟踪组件。它能够收集连续执行的每一条指令序列,并以跟踪数据包的形式输出到片外。
ETM 的核心价值在于:
- 历史序列调试:可以回放程序执行的历史,定位那些“抓不住”的偶发故障。
- 代码覆盖率分析:通过跟踪执行的指令,精确计算哪些代码被执行了,哪些没有。
- 性能瓶颈分析:结合 DWT 的性能计数器,分析流水线停顿、分支预测失败等微架构行为。
5.2 ETM 与其他跟踪组件的区别
| 组件 | 跟踪内容 | 数据量 | 适用场景 |
|---|---|---|---|
| ITM | 软件打印信息 | 小(由软件控制) | printf 调试、事件标记 |
| DWT | 数据访问、性能计数、PC 采样 | 中等 | 性能分析、内存访问跟踪 |
| ETM | 完整指令流 | 巨大(每条指令都产生数据) | 代码覆盖率、历史序列调试 |
由于 ETM 产生的跟踪数据量巨大,通常需要使用并行跟踪端口(Clocked Mode)输出,而非 SWO 的单引脚串行模式。ETM 的指令跟踪必须使用并行跟踪端口。
5.3 ETM 的局限性
- 引脚占用较多:并行跟踪模式需要 1~4 条数据线,占用较多 GPIO 引脚。
- 并非所有 Cortex‑M 系列都支持:Cortex‑M0/M0+ 不支持 ETM;M3、M4、M7 部分型号支持;M33、M55、M85 支持更高级的跟踪特性。
- 需要专用的跟踪捕捉器:普通的 J-Link 或 ST-Link 无法捕捉 ETM 的指令跟踪流,需要专用的 Trace Port Analyzer(TPA)。
对于大多数日常调试,ITM 和 DWT 已足够使用。ETM 主要用于深度性能分析和代码覆盖率测试。
📌 六、SWO 与 SWV:跟踪数据的输出通道
6.1 SWO 与 SWV 的关系
SWO(Serial Wire Output)是 TPIU 的一种工作模式,使用单引脚异步串行输出。SWV(Serial Wire Viewer)是调试器侧的功能名称——通过 SWO 引脚接收并解析跟踪数据,在 IDE 中实时显示的程序计数器采样、数据跟踪、事件跟踪和仪器跟踪信息。
SWO 输出的跟踪数据包括:
- PC 采样:显示 CPU 周期统计信息。
- 数据跟踪:记录数据读/写访问,用于时序分析。
- 事件跟踪:异常和中断执行统计。
- ITM 跟踪信息:printf 样式的调试输出。
JTAG 接口中的 TDO 引脚与 SWO 复用,因此 SWO 跟踪只能在 SWD 接口模式下使用。
6.2 SWO 支持的跟踪源
SWO 是 TPIU 串行输出模式下的物理引脚,可以同时输出 ITM 的软件跟踪数据(printf 调试)和 DWT 的硬件事件跟踪数据(PC 采样、数据访问、异常统计等)。这两类数据在 TPIU 中合并、格式化后,通过 SWO 引脚串行发送到调试器。
6.3 调试器的 SWO 支持
- ST-LINK:支持 SWV,但需要正版 ST-Link V2 或以上版本。
- J-Link:支持 SWO/SWV,但需要特定的引脚连接配置。
- ULINKplus:支持 SWO 跟踪。
并非所有的开发板都引出了 SWO 引脚,在项目规划时需要确认硬件支持。
6.4 SWO 输出速率配置
SWO 的串行输出速率需要通过调试器配置,通常设置为 2 MHz ~ 4.5 MHz。过高的速率可能导致信号完整性问题,过低则可能无法及时输出跟踪数据。
在 Keil MDK 中,需要在 Trace Settings 中配置 SWO 的时钟频率和输出速率。在 STM32CubeIDE 中,需要在 Debug Configuration → SWV 选项卡中进行配置。
📌 七、内核状态跟踪:异常统计与睡眠深度
7.1 使用 DWT 统计异常执行
DWT 模块提供了专门的事件跟踪能力,可以记录异常和中断的执行信息。通过 DWT 的异常开销计数器,可以监控:
- 每种异常(IRQ 或系统异常)被触发的次数。
- 异常进入和退出的耗时(异常开销)。
- 中断嵌套深度等。
调试器工具(如 STM32CubeIDE 的 SWV 功能)可以实时显示这些统计信息。
在实际调试中,可以使用 SWV 的数据时间线窗口实时观察中断的触发频率和执行时长。例如,当怀疑某中断执行时间过长导致系统响应延迟时,可以开启 DWT 的中断事件跟踪,在 SWV 数据时间线中直观地看到中断进入和退出的时刻点,从而精确计算中断服务函数的执行耗时。
7.2 跟踪睡眠深度与功耗模式
Cortex‑M 支持通过 DWT 跟踪系统进入低功耗模式的频率和时长。DWT 中的睡眠计数器(SLEEPCNT)是一个 8 位寄存器,记录处理器处于睡眠模式时的时钟周期数,每 256 个周期溢出一次。它可以用于跟踪睡眠深度,但测量较长睡眠时间时需要处理溢出中断或配合软件累加。
当 CPU 执行 WFI 或 WFE 指令时,DWT 可以记录睡眠状态的进入和退出事件。结合本章的低功耗知识和 Tickless 模式,开发者可以通过 DWT 验证:
- CPU 是否成功进入了预期的睡眠模式。
- 唤醒延迟是否符合预期。
- 是否存在未预期的频繁唤醒(功耗异常的根本原因)。
7.3 使用 SWV 进行实时内核状态监控
SWV 串行线查看器提供的典型信息包括:
- PC 采样:显示 CPU 周期统计信息。
- 事件计数器:用于跟踪中断和异常的频率。
- 数据跟踪:数据读写时序分析。
- ITM 跟踪信息:软件 printf 输出。
在调试低功耗问题时,可以通过 SWV 实时查看系统何时进入睡眠、何时被唤醒、以及唤醒源是哪个中断。这些信息对于优化功耗和定位异常唤醒问题至关重要。
📌 八、总结
8.1 本篇核心要点
- CoreSight 架构:ARM 的系统级调试与跟踪解决方案,遵循“源→链路→接收端”的数据流逻辑。调试通路通过 DAP(SWJ-DP 和各 AP)访问内核和外设,跟踪通路通过 ITM/DWT/ETM 生成数据,经 ATB 总线传输,由 TPIU 通过并行端口或 SWO 串行线输出至调试器。
- ITM 软件跟踪:支持无外设占用的 printf 调试。ITM 包含 32 个刺激端口,通过 SWO 引脚输出,CMSIS 提供了
ITM_SendChar()函数,仅需重定向__io_putchar即可实现。 - DWT 性能计数器:提供 CYCCNT 高精度周期计数器(精度可达 2.5ns),可进行微秒级延时、代码执行时间测量、PC 采样和异常统计。使能 DWT 需要配置 DEMCR.TRCENA 和 DWT_CTRL.CYCCNTENA。
- ETM 指令跟踪:提供完整的指令流跟踪,用于代码覆盖率分析和历史序列调试,但需要并行跟踪端口和专业捕捉器支持。
- SWO/SWV 跟踪数据流:SWO 是 TPIU 的串行输出模式,可同时输出 ITM 的软件跟踪和 DWT 的硬件事件跟踪数据。SWV 是调试器侧的功能名称,用于解析和显示这些数据。
- 内核状态跟踪:通过 DWT 和 SWV 可实时监控异常统计、中断延迟和睡眠深度,是调试低功耗问题和系统性能瓶颈的有力工具。注意 DWT 的 SLEEPCNT 是 8 位寄存器,测量长时间睡眠需配合溢出处理。
8.2 下篇预告:《内核性能指标 —— CoreMark、DMIPS、中断延迟实测》
从下一篇开始,我们将进入内核性能评测的领域:CoreMark 和 DMIPS 的由来与测试方法、如何精确测量中断延迟、以及代码密度的对比分析。
💬 读者问题专栏 · 问题征集
你在内核调试或跟踪过程中,是否遇到过:
- SWO 没有数据输出,不知道从哪里排查?
- DWT 的 CYCCNT 计数器不计数,检查过 DEMCR 和 DWT_CTRL 了吗?
- 想测量中断延迟或代码执行时间,不知道用 DWT 还是用逻辑分析仪更合适?
- 调试低功耗时,如何确认 CPU 确实进入了预期的睡眠模式?
欢迎留言,我会在 《Cortex‑M 有问必答》 中专题解答。
📢 关于作者与更多内容
我是 BackCatK Chen,长期关注嵌入式底层、国产半导体与 AI 算力芯片。
如果你对芯片架构、行业趋势感兴趣,欢迎关注我的公众号,获取更多宏观技术观察。
文章标签:Cortex-M CoreSight ITM DWT ETM SWO 调试 跟踪
更多推荐

所有评论(0)