ITM_SendChar 是 ARM Cortex-M 微控制器中用于通过 ITM(Instrumentation Trace Macrocell)机制输出调试信息的关键函数,它通过 SWO(Serial Wire Output)引脚实现高速、低干扰的调试信息传输,尤其适合替代传统串口输出。以下是详细使用指南:
一、ITM_SendChar 的原理与优势
工作原理
ITM 是 Cortex-M3/M4/M7 内核内置的调试模块,支持 32 个刺激端口(Stimulus Ports)。
ITM_SendChar 将字符写入 ITM 的端口 0(默认端口),通过 SWO 引脚输出到调试器(如 J-Link、ST-Link)。
无需暂停程序:数据在程序全速运行时异步传输,不影响实时性。
核心优势
高速传输:波特率可达数 Mbps(取决于内核时钟)。
零硬件占用:仅需 1 根 SWO 引脚(通常为 PB3),不占用串口资源。
支持标准库函数:可重定向 printf 直接输出调试信息。
二、硬件连接要求
引脚连接
目标板:连接 MCU 的 SWO 引脚(PB3) 到调试器的 SWO 接口(调试器 20 针接口的第 9 脚)。
调试器:使用支持 SWO 的调试器(如 ST-Link V2/V3、J-Link)。
接线示例:
MCU PB3 → 调试器 SWO 引脚
MCU SWDIO → 调试器 SWDIO
MCU SWCLK → 调试器 SWCLK
GND → GND
注意事项
Cortex-M0/M0+ 不支持:仅 M3/M4/M7 内核可用。
时钟匹配:调试器配置的 CPU 时钟必须与实际频率一致(否则无输出)。
三、软件配置步骤
1. 工程设置(以 Keil MDK 为例)
启用 Trace:
Options for Target → Debug → Settings → Trace
勾选 Enable Trace,设置 Core Clock(如 168 MHz),选择 ITM Stimulus Port 0(默认端口)。
SWO 参数:
Trace Port: Serial Wire Output,Prescaler 根据时钟计算(如 168 MHz 时设为 2)。
2. 代码重定向
重写 fputc 函数,调用 ITM_SendChar:
#include <stdio.h>
#include "core_cm4.h" // 根据内核选择 core_cm3.h 或 cm4.h
// 重定向 printf
int fputc(int ch, FILE *f) {
return ITM_SendChar(ch); // 发送字符到 ITM 端口 0
}
多端口支持:
若需使用其他端口(如端口 1),修改为:
#define ITM_PORT1 0x00000001
ITM->PORT[1].u8 = ch; // 发送到端口 1
3. 测试代码
int main(void) {
while (1) {
printf("ADC Value: %d\n", read_adc()); // 直接使用 printf
delay_ms(100);
}
}
四、调试信息查看
Keil MDK
进入调试模式:Debug → Start/Stop Debug Session。
打开输出窗口:View → Serial Windows → Debug (printf) Viewer。
其他工具
ST-Link Utility:SWV → Serial Wire Viewer。
J-Link SWO Viewer:独立工具,支持波形显示。
五、常见问题解决
无输出信息
时钟不匹配:检查调试器中设置的 Core Clock 是否与实际一致。
SWO 引脚未启用:在 MCU 初始化代码中启用 PB3 的复用功能(部分需配置 GPIO)。
端口未使能:在 Keil Trace 配置中勾选 ITM Stimulus Port 0。
输出乱码
波特率错误:调整 Prescaler 值(公式:SWO 频率 = Core Clock / (Prescaler + 1))。
中断冲突:避免在中断服务函数中频繁调用 printf(改用缓冲队列)。
六、高级用法
多端口分类输出
void debug_log(uint8_t port, char *msg) {
while (*msg) {
ITM->PORT[port].u8 = *msg++; // 指定端口发送
}
}
应用场景:端口 0 输出日志,端口 1 输出错误信息,便于过滤。
2.与 RTT 对比

七、最佳实践建议
替代串口调试:在资源受限或高速场景下优先使用 ITM,节省硬件串口。
时钟校准:在 SystemInit() 后读取 SystemCoreClock 动态设置 Trace 时钟。
生产环境禁用:通过宏定义控制调试输出,避免性能损耗:
#ifdef DEBUG_ENABLE
#define LOG printf
#else
#define LOG(...)
#endif
————————————————
版权声明:本文为CSDN博主「风停了123」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2301_79036162/article/details/148892846
|