“ Real Time Transfer(简称RTT)是Segger公司推出的用于嵌入式系统监控和交互的工具,其融合了SWO(SWD调试技术中的调试日志输出)等能力,且具备极高的性能。”
Real Time Transfer(简称RTT)是Segger公司推出的用于嵌入式系统监控和交互的工具,其融合了SWO(SWD调试技术中的调试日志输出)等能力,且具备极高的性能。RTT的技术特点如下:
与目标嵌入式应用的双向通信能力
不影响嵌入式应用的实时行为的高速传输速率
使用调试通道用作通信(相当于不用再额外占用GPIO等外设接口)
不需要在目标嵌入式系统增加额外的硬件或引脚
任何的J-Link型号都支持(J-Link型号列表和比较可参考https://www.segger.com/products/debug-probes/j-link/models/model-overview/)
能被ARM Cortex-A/R/M系列芯片支持,以及被RISC-V和Renesas RX支持
提供完整的RTT的实现代码
01
什么是RTT
RTT能够在不影响嵌入式应用的实时行为下,能够高速双向通信,既可以输出调试信息,也能够从外部输入相关的控制命令。RTT可以在两个传输方向(输出和输入)上支持多个通道,不同的通道可用于不同的目的。
常见的实现是每个传输方向使用一个通道,用于调试的输入输出:
通过在PC上使用J-Link RTT Viewer工具,在工具中可以有多个虚拟终端,可以用来打印不同的信息(如一个窗口做标准输出,一个窗口做错误信息的输出,一个窗口做调试信息输出)。
在目标应用程序中使用RTT非常容易。实现代码可以免费下载,并且可以集成到任何现有的应用程序中。
通过RTT通信,可以使用任何J-Link。通过终端(通道0)进行通信的简单方法是,当到J-Link的连接(例如,通过调试会话)处于活动状态时,使用Telnet客户机或类似的设备创建到localhost:19021的连接。
02
RTT相关工具
RTT工具包含在J-Link软件包中,可根据系统需要下载对应安装包(地址:https://www.segger.com/downloads/jlink/),Windows和MAC的都是图形化界面安装,都很简单,这里对Linux系统下的安装细节进行补充说明,以树莓派系统为例:
# 首先下载好.tgz安装包,然后按照下面步骤解压缩 $ mkdir -p ~/opt/SEGGER $ cd ~/opt/SEGGER $ tar xf ~/Downloads/JLink_Linux_V684_arm64.tgz $ chmod a-w ~/opt/SEGGER/JLink_Linux_V684_arm64 $ ls -l ~/opt/SEGGER/JLink_Linux_V684_arm64 # 接下来是udev配置 $ sudo cp 99-jlink.rules /etc/udev/rules.d/ # 重启系统,或手动敲入如下命令,触发新规则生效 $ sudo udevadm control -R $ sudo udevadm trigger --action=remove --attr-match=idVendor=1366 --subsystem-match=usb $ sudo udevadm trigger --action=add --attr-match=idVendor=1366 --subsystem-match=usb
J-Link RTT Viewer是主要的Windows的GUI应用,用来使用RTT调试的所有功能。RTT Viewer可以单独使用,开启一个连接到J-Link,或者在运行调试会话时并行使用,RTT Viewer支持所有RTT的主要功能:
通道0的Terminal output
通道0的输入
在一个目标通道上支持高达16个虚拟Terminal
可控的字符输出:字体颜色控制,控制台消息擦除
通道1的Logging数据等
关于J-Link RTT Viewer的详细说明可参考J-Link用户指南文档(
https://wiki.segger.com/UM08001_J-Link_/_J-Trace_User_Guide#RTT)。
关于J-Link RTT Viewer的多个虚拟终端,还是相对描述的模糊的,这里以相应实例来说明。
首先打开J-Link RTT Viewer工具,会提示选择对应的设备进行连接,连上后会看到RTT Viewer connected状态
然后可以在RTT Viewer中打开多个虚拟终端
嵌入式应用代码中进行调试日志打印
#include "SEGGER_RTT.h" int main() { // 初始化RTT SEGGER_RTT_Init(); // 进入主循环 while (1) { // 设置虚拟端口0,并输出日志,如果不设置,默认都会用Terminal 0 SEGGER_RTT_SetTerminal(0); SEGGER_RTT_printf(0, "Hello, SEGGER RTT Terminal 0!\r\n"); // 设置虚拟端口1,并输出日志 SEGGER_RTT_SetTerminal(1); SEGGER_RTT_printf(0, "Hello, SEGGER RTT Terminal 1!\r\n"); // 设置虚拟端口2,并输出日志 SEGGER_RTT_SetTerminal(2); SEGGER_RTT_printf(0, "Hello, SEGGER RTT Terminal 2!\r\n"); Delay_ms(1000); // 另外可以输出在RTT Viewer不同颜色的日志,颜色定义可参考SEGGER_RTT.h // 如下为通过红色字体输出日志 // SEGGER_RTT_printf(0, RTT_CTRL_TEXT_RED"Hello, SEGGER RTT Terminal 0!\r\n"); } }
在嵌入式设备运行,且通过J-Link连接到电脑,通过J-Link RTT Viewer工具可进行不同虚终端日志查看
J-Link RTT Client作为一个Telnet Client,当调试会话关闭时其会自动尝试重连到J-Link连接,J-Link RTT Client是J-Link软件包的一部分。
有了J-Link RTT Logger,来自Up-Channel 1的数据可被读取,并且可记录到log文件,这个Channel可以用于发送性能分析数据到主机端,J-Link RTT Logger打开了一个到J-Link的专用连接,可以在无调试会话时单独使用。该应用也是J-Link软件包的一部分。J-Link RTT Logger支持的命令列表如下:
03
RTT工作原理
RTT的实现使用了Control Block的架构,在目标嵌入式系统上通过内存来管理数据的读写。
注:Up Buffer Descriptors: Target -> Host
Down Buffer Descriptors: Host -> Target
上图灰色部分表示有数据存在
Control Block包含了ID,便于J-Link在内存内进行查找,每个可用通道(上面提到的虚拟终端)采用Ring Buffer架构,描述通道的缓存和状态。可用通道的最大个数可被配置,每个Buffer也可以被配置,上行和下行的Buffer是单独分开处理的。每个通道可以配置为阻塞模式或非阻塞模式。
在阻塞模式下,当Buffer满了后应用会等待,这会造成应用阻塞,但是保证了数据不丢失。
在非阻塞模式下,只写入符合缓冲区大小的数据,或者根本不写入数据,其余的将被丢弃,这种方式适用于应用的实时运行。
当RTT被激活,如通过RTT Viewer连接到使用J-Link的应用程序,J-Link会自动在嵌入式目标系统的已知内存区域搜索SEGGER RTT Control Block。RAM区域或Control Block的特定地址也可以通过主机应用程序来设置,以加快检测速度。
04
RTT的性能
如下是RTT, SWO, Semihosting三者速率的一个比较,该数据基于STM32F407上实测:
如下是RTT配合不同的J-Link型号(JTAG速率有差异),以及嵌入式系统上分配给RTT的Control Block缓存大小的一个速率对比:
RTT上行通道的缓冲区可以相对较小,所需的最小缓冲区大小可以用一毫秒内写入的数据量和一次写入操作中写入的最大数据量来近似表示。如果数据发送的频率较低,那么缓冲区应该有足够的空间来容纳一次写入发送的数据。如果更频繁地发送数据,缓冲区大小应该足以满足1毫秒内写入的最大数据量。下图显示了发送不同数量的数据时所需的最小缓冲区大小,平均分布,每100 us和每1 ms:
RTT实现代码大约需要500字节的ROM空间,RAM的占用则和Control Block的Buffer个数相关,24字节的ID + 24字节的单个通道控制块。每个通道都需要一些缓冲区的内存。根据输入/输出负载的不同,上行通道推荐的大小为1 kByte,下行通道推荐的大小为16到32字节。
05
RTT代码实现
SEGGER RTT代码用ANSI C编写,能方便集成到任何嵌入式应用程序中。RTT可以通过简单易用的API来使用。甚至可以重写标准的printf()函数来使用RTT。使用RTT将printf()所花费的时间减少到最低限度,并允许在应用程序执行时间关键的实时任务时向主机PC打印调试信息。
SEGGER RTT实现包括printf()的一个简单实现,可用于通过RTT编写格式化字符串。SEGGER_RTT_Printf()比大多数标准库printf实现要小,并且不需要堆,只需要可配置的堆栈数量。通过使用Lock()和Unlock(),使读取和写入线程安全,缓冲区的数量以及终端缓冲区的大小都可以设置。如下是RTT提供给嵌入式集成的接口函数:
https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/
https://wiki.segger.com/UM08001_J-Link_/_J-Trace_User_Guide#RTT
https://wiki.segger.com/RTT
版权说明:如非注明,本站文章均为 扬州驻场服务-网络设备调试-监控维修-南京泽同信息科技有限公司 原创,转载请注明出处和附带本文链接。
请在这里放置你的在线分享代码