前言

        本文主要是基于OpenOCD DAPLink配置的SEGGER RTT,如果你想直接看配置和使用流程, 下翻到标题移植 SEGGER_RTT 库文件, 前言中会写我接触的契机,以及对RTT进行简单的介绍

        博主最近在复盘电赛,当时做的是e题,意外看见了本题ti杯的开源项目工程, 遂下载来阅读,在此佩服大佬的实力。

        这是一篇 SEGGER RTT(Real Time Transfer) 的使用介绍, 也是从这个里面看到的, 它和printf 都可以用于在嵌入式系统中输出信息,但是 SEGGER RTT 是要比printf要快个几十倍甚至上百倍的,这对于实时性要求比较高或者传输数据量比较大的场景来说无疑是很有用的.
        我记得自己第一次做巡线小车的时候,采用时间片轮询, printf输出是放在中断里面进行执行的,当时同时观测了很多个变量,导致小车跑起来是一卡一卡的,和个拖拉机一样,当时并不知道是由于printf开销过大导致的.

和printf对比来看, SEGGER RTT有许多的优势: (来自deepseek)

  1. RTT利用了目标设备的内存区域(控制块和缓冲区)作为数据传输的通道,主机(如调试器、上位机软件)通过调试接口(如 J - Link)直接访问目标设备内存中的 RTT 缓冲区来获取数据,而不需要像 printf 那样依赖特定的外设(如串口)进行数据传输, 如果搭配无线调试器, 是不是意味着可以不用蓝牙进行无限调试或者调参了?
  2. RTT数据传输速度远远高于串口, 以 J - Link 为例,其数据传输速度可以达到几十 MByte/s 甚至更高,能快速地将大量数据传输到主机,因此在传输效率上,SEGGER RTT 通常比 printf 快很多,在一些简单测试中,当数据量较大时,SEGGER RTT 可能比 115200 波特率串口的 printf 快几十倍甚至上百倍.
  3. RTT虽然也需要在目标设备上占用一定的内存空间来作为缓冲区和控制块,但不需要像 printf 那样占用大量的代码空间来实现复杂的格式化功能。
  • 注: 本文默认你可以在CLion上正常搭配OpenOCD, stm32cubemx进行烧录和调试

开发平台

软件: CLion + stm32cubemx + CMake + OpenOCD

硬件: DAPLink(无线) + STM32H750VBT6

  • 说明: 并不局限于CLion, 只要是使用OpenOCD进行烧录调试的都可以按照此方法进行配置, 如果你使用的是keil,当然也可以,不过你得去看其他文章了。

移植 SEGGER_RTT 库文件

  • 首先需要下载JLink驱动, 得去官网

  • 下载完成后, 你会看到此目录

  • 来到路径 ${JLink_DIR}\Samples\RTT下, 解压, 然后复制图中选中的两个目录到我们的工程目录下

     

     

  • 我在CMake中将此目录添加进来, 这个代码也是来自上述ti杯的
function(include_sub_directories_recursively root_dir)
    if (IS_DIRECTORY ${root_dir})               # 当前路径是一个目录吗,是的话就加入到包含目录
        message("include dir: " ${root_dir})
        include_directories(${root_dir})
    endif()

    file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # 获得当前目录下的所有文件,让如ALL_SUB列表中
    foreach(sub ${ALL_SUB})
        if (IS_DIRECTORY ${root_dir}/${sub})
            include_sub_directories_recursively(${root_dir}/${sub}) # 对子目录递归调用,包含
        endif()
    endforeach()
endfunction()

include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/SEGGER)

# add source, only surfix .c
file(GLOB_RECURSE SOURCES
        "Middlewares/*.c"
)

改写cfg配置文件

下面我配置的.cfg文件, 可以看到, 在原有烧录的基础上添加了rtt配置

source [find interface/cmsis-dap.cfg]
transport select swd

# 设定闪存容量为 512KB
set FLASH_SIZE 0x80000
source [find target/stm32h7x.cfg]

adapter speed 10000

init
# 指定地址 速率
rtt setup 0x20004ca0 0x10000 "SEGGER RTT"       
rtt start
# 设定观测端口
rtt server start 8888 0

# reset_config srst_only

可能遇到的问题

问题1

调试出现

Info : rtt: Searching for control block 'SEGGER RTT' 
Info : rtt: No control block found

访问.map文件, 我的地址为 ** ${CMAKE_SOURCE_DIR}/cmake-build-debug-mingw/Module_H7.map** 搜索字符 _SEGGER_RTT, 将地址进行替换


可以看到我的地址正是0x20004ca0

如果即便替换了还是报相同的错误, 建议先调试后烧录, 两者都没有连接上, 但是一前一后再次点击调试, 本错误就莫名其妙的解决了, 正常显示连接成功.

问题2

最后一句出现

Error: The 'tcl_port' command must be used before 'init'.

研究他究竟在说什么,我们最好是额外配置一个cfg文件, 一个烧录用(不包括SEGGER_RTT配置), 一个调试用(上文所配置的). 然后分开进行
比如说我添加一个仅烧录的.cfg文件

source [find interface/cmsis-dap.cfg]
transport select swd

# 设定闪存容量为 512KB
set FLASH_SIZE 0x80000
source [find target/stm32h7x.cfg]

adapter speed 10000

然后配置两个, 分别命名为DAP_H7 和 DAP_H7_RTT

2025.9.18 配置烧录器一定要勾选“运行”

如何接收信息

打开命令提示符窗口, 输入指令

telnet 127.0.0.1 8888

8888 是上面我们自己设定的地址, 按照你的来就行

可能会出现

telnet : 无法将“telnet”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 行:1 字符: 1

这其实是因为windows并没有启动telnet客户端, 我们只需要在控制面板打开即可, 具体流程如下:

  1. 打开 控制面板 -> 程序和功能 -> 启用或关闭 Windows 功能。
  2. 在弹出的窗口中,找到并勾选 "Telnet 客户端",点击 “确定” 安装。
  3. 安装完成后,重新打开 CLion 终端,再次执行 telnet 命令即可。

关于库的调用, 我直接复制了开源项目 湖南大学RoboMaster跃鹿战队2022-2023电控通用嵌入式框架bsp/log/ 路径下的文件, 该框架对此进行了不错的封装.


完成后我们就可以在调试的时候快速接收输出的日志了,比如我使用以下代码打印hello world

void cpp_StartDefaultTask(void){
    BSPLogInit();
    LOGINFO("hello_world\n");
    for(;;){
    }
}

输出为

我们当然也可以在vofa+中观测, 只需要使用TCP客户端接口即可,输入指定的端口号


红字是我尝试连接的结果,可以看到后面输出了正常的绿色的 hello world

这还是很有好处的单点调试连续性的调试都能在上位机实时接收到日志信息.参考文章
【嵌入式小技巧】STM32 实现 SEGGER RTT 打印(超详细) JLink + Keil版
Clion中OpenOCD结合SEGGER RTT高速输出调试信息
HNUYueLuRM/basic_framework

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐