RTT是SEGGER基于共享内存的实时数据传输技术,无需UART硬件、无波特率限制,吞吐量达数MB/s;依赖J-Link调试器和RAM中预置的控制块与环形缓冲区。

RTT 是什么,为什么能比串口快
SEGGER RTT(Real Time Transfer)本质是用一块共享内存做缓冲区,J-Link 在后台轮询这块内存,把数据直接抓走。它不经过 UART 外设、不依赖波特率、没有起始/停止位开销,所以吞吐量轻松做到几 MB/s。你看到的 SEGGER_RTT_printf 看似像 printf,背后其实是原子写入环形缓冲区 + J-Link 侧异步搬运,和串口的阻塞式发送完全是两套逻辑。
关键前提:你的单片机必须有 RAM 可供 RTT 分配缓冲区(通常 1–4 KB 就够),且调试器必须是 J-Link(含 OB/J-Trace)——CMSIS-DAP、ST-Link、DAPLink 都不支持 RTT。
怎么在工程里启用 RTT(以 STM32 + Keil MDK 为例)
不是加个头文件就能用,得让链接器把 RTT 控制块和缓冲区放到确定位置。SEGGER 提供的 SEGGER_RTT.c 和 SEGGER_RTT_Syscalls_GCC.c(或对应 Keil 版本)必须加入工程;更重要的是 SEGGER_RTT_Config.h 要配置好缓冲区大小和通道数,比如:
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (2) #define BUFFER_SIZE_UP (1024)
链接脚本里要确保 __SEGGER_RTT 符号被正确定义到 RAM 段开头(Keil 中常设为 RAM 段起始地址),否则 J-Link 找不到控制块,SEGGER_RTT_WriteString 会静默失败。
立即学习“C++免费学习笔记(深入)”;
常见错误现象:SEGGER_RTT_printf 调用后 Host 端(J-Link Commander 或 RTT Viewer)完全没输出——先检查 __SEGGER_RTT 地址是否落在 RAM 区间内,再确认 J-Link 驱动已安装且固件版本 ≥ V6.10。
如何安全地在中断里调用 RTT 输出
RTT 的上行通道(target → host)默认使用无锁环形缓冲区,但前提是写入长度 ≤ 缓冲区剩余空间,否则 SEGGER_RTT_Write 会返回 0 并丢弃整条日志。中断中尤其危险:如果日志字符串过长(比如带浮点格式化),或者缓冲区刚好被主循环占满,就会静默丢数据。
- 避免在中断中用
SEGGER_RTT_printf—— 它内部有格式化+多次小写入,不可预测 - 改用
SEGGER_RTT_Write直接写入预格式化字符串(如"IRQ: ADC done\n"),且长度严格控制在BUFFER_SIZE_UP / 2以内 - 若必须动态格式化,把格式化挪到主循环,中断只置标志位或存入轻量队列
性能影响:一次 SEGGER_RTT_Write 耗时约几十到几百 ns(取决于长度和缓存命中),远低于 UART 发送一个字节的 ms 级等待,但频繁写入仍会增加 RAM 总线竞争。
Host 端怎么实时看到日志(不用 J-Link Commander)
J-Link SDK 自带的 JLinkRTTViewer.exe 最轻量,启动即连,自动识别通道;但如果你集成到 VS Code 或自建脚本,就得用 JLinkExe 命令行:
JLinkExe -device STM32F407VG -if SWD -speed 4000 -autoconnect 1 -CommanderScript rtt.script
其中 rtt.script 内容只需两行:
exec SetRTTSearchRanges 0x20000000 0x10000 exec EnableRTT
注意地址 0x20000000 必须和你链接脚本中 __SEGGER_RTT 的实际地址一致,否则搜不到控制块。Mac/Linux 用户可用 JLinkExe 的终端模式,但别用 screen 或 minicom —— 它们只认串口设备节点,对 RTT 无效。
容易被忽略的一点:RTT 通道是静态分配的,SEGGER_RTT_printf 默认走通道 0,但你可以用 SEGGER_RTT_printf(1, "...") 切到通道 1,再让 Host 端分别监听不同通道——比如通道 0 打印错误,通道 1 打印性能计数,互不干扰。


















