如何输出 RTT 日志?
解读
在国内嵌入式/系统级 Rust 岗位面试中,**“RTT 日志”**通常特指 SEGGER RTT(Real-Time Transfer) 方案:通过 J-Link 调试器在 MCU 内部 RAM 中开辟环形缓冲区,实现 零引脚、微秒级延迟、最高 3 MB/s 吞吐 的日志输出。
面试官问“如何输出”,既考察你对 Rust 嵌入式生态的熟悉度,也验证你是否真正在产线上解决过“调试口被占用、波特率受限、不能加 USB 转串口”等现场痛点。回答必须给出 Cargo 依赖、初始化流程、宏封装、链接脚本适配、IDE/命令行抓取 五步闭环,否则会被认为“只玩过开发板”。
知识点
- SEGGER RTT 协议原理:MCU 端写环形 buffer,J-Link 通过 SWD 读取,PC 端使用 J-Link RTT Viewer 或 pylink-rtt 抓取。
- ** cortex-m-rt 与 rtt-target crate**:
rtt-target提供rprintln!宏,内部使用cortex_m::interrupt::free保证中断安全。 - 内存布局:链接脚本需保留
_SEGGER_RTT段,防止被 linker garbage collect。 - Cargo features 隔离:debug 镜像开启 rtt,release 镜像可关闭以节省 2–3 kB Flash。
- 国内量产常用工具链:
- 调试器:J-Link OB(淘宝 30 元版) 或 DAPLink 刷 J-Link固件;
- 上位机:J-Link RTT Viewer 7.20 以上(支持中文时间戳)、RTT-Logger(可转 Syslog 对接阿里云日志服务)。
答案
步骤如下,可直接用于 STM32/GD32/NRF52 等国内主流 MCU:
- Cargo.toml 引入依赖
[dependencies]
cortex-m-rt = "0.7"
rtt-target = { version = "0.4", features = ["cortex-m"] }
panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
- main.rs 初始化并替换 panic handler
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use rtt_target::{rtt_init_print, rprintln};
use panic_rtt_target as _;
#[entry]
fn main() -> ! {
rtt_init_print!(); // 申请 Up buffer 1024 B
rprintln!("===== 国产Rust固件启动 =====");
let mut counter = 0u32;
loop {
rprintln!("tick: {}", counter);
counter = counter.wrapping_add(1);
cortex_m::asm::delay(48_000_000); // 1 s @48 MHz
}
}
- memory.x 保留 RTT 控制块
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
RAM : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.rtt (NOLOAD) :
{
KEEP(*(.rtt));
. = ALIGN(4);
} > RAM
}
- build 并烧录
cargo build --release --bin firmware
JLinkExe -device STM32F103C8 -if swd -speed 4000 -autoconnect 1
JLink> loadbin target/thumbv7m-none-eabi/release/firmware 0x08000000
JLink> r
JLink> g
- 实时查看日志
JLinkRTTViewer -device STM32F103C8 -if swd -speed 4000 -a "log.txt"
终端即可看到中文时间戳日志,无需额外飞线,不影响主频,SWD 接口复用。
拓展思考
- 多通道 RTT:使用
rtt_target::rtt_init!创建 3 个 Up buffer,分别对应 INFO、WARN、TRACE,上位机通过通道号过滤,解决国内“日志太多把 J-Link 堵死”的老问题。 - 零拷贝大块数据:
rtt_target::write直接写 slice,配合 DMA 双缓冲,可在 1 ms 内导出 4 kB 波形数据,替代传统串口 YModem。 - 安全认证场景:RTT 缓冲区位于 RAM,量产时可把
.rtt段放到 SRAM3(STM32H7 的 64 kB AXI SRAM),烧录后使用 J-Link Commander 的w4 0x20000000 0xFFFFFFFF清零,防止日志残留泄露密钥。 - 与 defmt 对比:defmt 使用 LEB128 压缩 + 索引字符串表,同样通过 RTT 传输,比 rtt-target 节省 70 % 带宽,但需引入
probe-run工具链;国内部分公司因 版权合规 仍倾向 SEGGER 官方方案。