《嵌入式 - 嵌入式大杂烩》详解J-Link RTT打印
开发环境:
J-Link版本:V9.4
J-Link驱动版本:V760h_x86_64
Keil:V5.30
在嵌入式开发过程中,经常需要进行打印调试,通常使用串口进行打印输出,但通常串口资源有限,这时就可以通过J-Link工具里面自带的RTT实现打印,从而节约一个串口资源。
1 RTT简介
RTT全称是Real Time Transmit(实时传输)**,是Segger公司推出的调试手段之一。它是一种用于嵌入式中与用户进行交互的技术。
使用RTT可以从MCU快速输出调试信息和数据,且不影响MCU的实时性。只要支持J-Link的MCU就可使用RTT功能,兼容性非常强。
RTT支持两个方向的多个通道,上到主机,下到目标,它可以用于不同的目的,为用户提供尽可能多的自由。默认实现每个方向使用一个通道,用户可在在调试终端输入和输出。
使用J-Link RTT Viewer,可用于“虚拟”终端,允许打印到多个窗口(例如,一个用于标准输出,一个对于错误输出,一个用于调试输出)。
RTT的通信可以通过不同的应用程序完成,可以使用SDK集成到自定义的应用程序中,可本地连接,可远程连接。
Segger也给出了相应的实例,使用起来非常简单。
关于RTT的更多介绍请参看Segger官网:
About-real-time-transfer
2 RTT的工作原理
RTT在MCU的存储器中使用Segger RTT控制块结构管理数据的读写操作。控制块对于每个可用的信道都在内存中包含了一个ID,用于描述通道缓冲区及其状态,通过J-Link或者环形缓冲结构区(链表)都可以通过ID找到对应的控制块。
可用信道的最大数目可以在编译时配置,并且每个缓冲区都可以在MCU运行时配置和使用。上下缓冲区可以分开处理。每个通道都可以配置为阻塞或非阻塞。
在阻塞模式下,应用程序将等待缓冲区写满,直到可以写入所有内存为止,这将导致应用程序处于阻塞状态,但可以防止数据丢失。
在非阻塞模式下,只会写入适合缓冲区的数据,或完全不写入缓冲区,其余的数据将被丢弃。这样即使没有连接调试器,也可以实时运行。开发人员不必创建特殊的调试版本,并且代码可以保留在发布应用程序中。
当 RTT处于活动状态时,无论是通过 RTT Viewer 等应用程序直接使用 RTT,还是通过 Telnet 连接到使用 J-Link 的应用程序(如调试器),J-Link 都会在目标的已知 RAM区域中自动搜索 Segger RTT 控制块。RAM区域或控制块的特定地址也可以通过主机应用程序设置以加快检测速度,否则无法自动找到控制块。
下图显示了Segger RTT 控制块的内部结构:
RTT不需要通过额外SWO引脚,即可实现printf输出,它也不需要对目标进行任何配置或在调试环境中进行任何配置,甚至可以在不同的目标速度下使用。
3 RTT的性能
RTT的性能(耗时)远高于SWO。平均一行文本可以在一微秒或更短的时间内输出,基本上只需要做一个memcopy() 的时间。
RTT的最大速度取决于目标缓冲区大小和目标接口速度。 即使使用 512 字节的小型目标缓冲区,高版本的J-Link的速度高达 1 MiB/s,而使用低版本的J-Link只有0.5 MiB/s。
RTT实现代码使用大约500字节的ROM和(n(通道数) * (24字节ID+24字节))的RAM。推荐的大小是1 kByte(上行信道)和16到32字节(下行信道),这取决于输入/输出的负载。
Memory | Usage |
---|---|
ROM Usage | ~500 Bytes |
RAM Usage | 24 Bytes fixed + (24 + SizeofBuffer) Bytes / channel |
4 J-Link驱动安装及RTT工具简介
4.1 驱动安装
在使用RTT之前,先要J-Link驱动。
J-Link驱动下载地址
根据自己的电脑选择相应的软件,笔者的使用的是Windows 64bit的。下载好J-Link驱动程序后,双击安装即可,这里就不在赘述了。
4.2 RTT工具简介
安装完成后,会有三个与RTT相关的软件。
1.J-Link RTT Viewer
J-Link RTT Viewer是在调试主机上使用RTT功能的Windows GUI应用程序。
RTT Viewer可以独立使用,打开自己与J-Link的连接,并与正在运行的调试会话目标或并行,连接到它并使用现有的J-Link连接。
RTT Viewer支持RTT的主要功能:
- 通道0上的终端输出
- 将文本输入发送到通道0
- 最多16个虚拟终端,只有一个目标通道
- 控制文本输出:彩色文本,擦除控制台
- 在通道1上记录数据
本文主要讲解J-Link RTT Viewer的使用。
2.J-Link RTT Client
J-Link RTT Client可以充当 Telnet 客户端,但在调试会话关闭时会尝试自动重新连接到 J-Link。
【PS】要想使用J-Link RTT Client,需要开启telnet。如果你的电脑没有开启telnet功能,需要打开“启用或关闭Windows功能”,打开方法如下:
然后在里面找到“telnet客户端”,启动即可。
3.J-Link RTT Logger
使用 J-Link RTT Logger可以读取来自上行通道 1 的数据并将其记录到文件中。
例如,可用于向主机发送性能分析数据。 J-Link RTT Logger 与 J-Link 建立专用连接,可独立使用,无需运行调试器。
J-Link RTT Logger 的源代码可用作将 RTT 集成到其他 PC 应用程序(如调试器)的起点,并且是 J-Link SDK 的一部分。
5 RTT移植及RTT Viewer使用
5.1 RTT Viewer快速使用
【Note】笔者后文将使用STM32F103演示RTT的使用。
1.添加RTT文件
安装完J-Link驱动之后,在安装目录下有相应的RTT源码包。
笔者的安装目录是:C:\Program Files\SEGGER\JLink\Samples\RTT
解压SEGGER_RTT_V760h.zip文件,加解压后文件内容如下:
将RTT复制到自己的基础工程中,笔者使用的是带串口的基础工程。
另外还需要将Config目录下的SEGGER_RTT_Conf.h复制到工程目录下的RTT文件夹中,值得注意的是,不同的J-Llink驱动版本,Config文件存放的地方是不同的。
最后工程目录如下:
然后将RTT下的所有文件添加到Keil工程中。
值得注意的是,需要将RTT的头文件路径也添加到工程中。
值得注意的是,如果直接将Config目录下的SEGGER_RTT_Conf.h复制到工程目录下,还需要修改SEGGER_RTT.h文件中SEGGER_RTT_Conf.h的路径。修改后如下:
当然也可直接将Config目录复制到工程目录下,这样只需要添加头Config文件路径即可。
这里就更具自己喜好添加吧。
2.添加测试代码
修改main.c中代码,修改后如下:
/********************************************************************************* @file main.c* @author BruceOu* @lib version V3.5.0* @version V1.0* @date 2022-02-12* @blog https://blog.bruceou.cn/* @Official Accounts 嵌入式实验楼* @brief *******************************************************************************/
/* Includes*********************************************************************/
#include "./USART1/stm32f103_usart1.h"
#include "./SysTick/stm32f103_SysTick.h"#include "SEGGER_RTT.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//*** @brief mian* @param None* @retval int*/
int main(void)
{ SysTick_Init();/* USART1 配置模式为 115200 8-N-1,中断接收 */USART1_Config();/*无限循环*/ while (1){ printf("%s\r\n","Hello World from SEGGER!");SEGGER_RTT_WriteString(0, "Hello World from SEGGER!\r\n");Delay_ms(1000); }
}/*********************************END OF FILE******************************/
笔者这里还使用了串口打印输出,用于对比。
【PS】关于STM32F103的串口工程请参看笔者博客:
串口通信
3.测试
编译下载,启动RTT Viewer软件。
选择相应的目标设备,这里就根据自己的MCU选择相应的型号。
其他默认即可。
最后点击‘OK’,就会看到打印信息。
当然。我们使用串口也能看到串口打印。
可以看到不管是使用RTT,还是使用串口其效果都是一样的。是不是很nice!
5.2 RTT Viewer多终端使用
另外,上面的实例中使用的终端0,还可以同时使用多个终端。
核心代码如下:
/********************************************************************************* @file main.c* @author BruceOu* @lib version V3.5.0* @version V1.0* @date 2022-02-12* @blog https://blog.bruceou.cn/* @Official Accounts 嵌入式实验楼* @brief *******************************************************************************/
/* Includes*********************************************************************/
#include "./USART1/stm32f103_usart1.h"
#include "./SysTick/stm32f103_SysTick.h"#include "SEGGER_RTT.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//*** @brief mian* @param None* @retval int*/
int main(void)
{ SysTick_Init();/* USART1 配置模式为 115200 8-N-1,中断接收 */USART1_Config();/* 无限循环*/ while (1){ /* STM32->RTT Viewer */SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);SEGGER_RTT_ConfigUpBuffer(1, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);/* RTT Viewer->STM32 */ SEGGER_RTT_ConfigDownBuffer(0, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);SEGGER_RTT_ConfigDownBuffer(1, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);printf("%s\r\n","Hello World from SEGGER, Terminal 0!");SEGGER_RTT_SetTerminal(0);SEGGER_RTT_WriteString(0, "Hello World from SEGGER, Terminal 0!\r\n");printf("%s\r\n","Hello World from SEGGER, Terminal 1!"); SEGGER_RTT_SetTerminal(1);SEGGER_RTT_WriteString(0, "Hello World from SEGGER, Terminal 1!\r\n");Delay_ms(1000); }
}/*********************************END OF FILE******************************/
编译下载,添加Terminal1,打印如下:
同样使用串口打印:
5.3 RTT Viewer自定义颜色
RTT还可以自定义打印颜色,在SEGGER_RTT.h文件可以查看不同颜色的宏定义。
核心代码如下:
/********************************************************************************* @file main.c* @author BruceOu* @lib version V3.5.0* @version V1.0* @date 2022-02-12* @blog https://blog.bruceou.cn/* @Official Accounts 嵌入式实验楼* @brief *******************************************************************************/
/* Includes*********************************************************************/
#include "./USART1/stm32f103_usart1.h"
#include "./SysTick/stm32f103_SysTick.h"#include "SEGGER_RTT.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//*** @brief mian* @param None* @retval int*/
int main(void)
{ SysTick_Init();/* USART1 配置模式为 115200 8-N-1,中断接收 */USART1_Config();/* 无限循环*/ while (1){ /* STM32->RTT Viewer */SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);SEGGER_RTT_ConfigUpBuffer(1, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);/* RTT Viewer->STM32 */ SEGGER_RTT_ConfigDownBuffer(0, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);SEGGER_RTT_ConfigDownBuffer(1, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);printf("%s\r\n","Hello World from SEGGER, Terminal 0!");SEGGER_RTT_SetTerminal(0);SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_RED "Hello World from SEGGER, Terminal 0!\r\n");printf("%s\r\n","Hello World from SEGGER, Terminal 1!"); SEGGER_RTT_SetTerminal(1);
SEGGER_RTT_printf(0, RTT_CTRL_TEXT_GREEN"Hello World from SEGGER, Terminal 1!\r\n");Delay_ms(1000); }
}/*********************************END OF FILE******************************/
最会效果如下:
5.4 RTT Viewer printf重定向
RTT还可以使用printf重定向,只需要简单修改fputc()函数即可。
int fputc(int ch, FILE *f)
{#if defined (RTT)SEGGER_RTT_PutChar(0, ch);
#else/*清除标志位*/USART_ClearFlag(USART1,USART_FLAG_TC);/* 发送一个字节数据到USART1 */USART_SendData(USART1, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
#endifreturn (ch);
}
核心代码如下
/********************************************************************************* @file main.c* @author BruceOu* @lib version V3.5.0* @version V1.0* @date 2022-02-12* @blog https://blog.bruceou.cn/* @Official Accounts 嵌入式实验楼* @brief *******************************************************************************/
/* Includes*********************************************************************/
#include "./USART1/stm32f103_usart1.h"
#include "./SysTick/stm32f103_SysTick.h"#include "SEGGER_RTT.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//*** @brief mian* @param None* @retval int*/
int main(void)
{ SysTick_Init();USART1_Config();/* 无限循环*/ while (1){ SEGGER_RTT_SetTerminal(0);SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_RED"Hello World from SEGGER, Terminal 0!\r\n");printf("printf: %s\r\n","Hello World from SEGGER, Terminal 0!");SEGGER_RTT_SetTerminal(1);SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_GREEN"Hello World from SEGGER, Terminal 1!\r\n");printf("printf: %s\r\n","Hello World from SEGGER, Terminal 1!"); Delay_ms(1000); }
}/*********************************END OF FILE******************************/
最后效果如下:
5.5 RTT Viewer打印float
RTT Viewer不能打印出float类型的数据,要想打印浮点数,最简单的办法就是将浮点型数据转为字符串。
在C的标准库中有两个转换的函数:
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
下面是转换实例:
/********************************************************************************* @file main.c* @author BruceOu* @lib version V3.5.0* @version V1.0* @date 2022-02-12* @blog https://blog.bruceou.cn/* @Official Accounts 嵌入式实验楼* @brief *******************************************************************************/
/* Includes*********************************************************************/
#include <string.h>#include "./USART1/stm32f103_usart1.h"
#include "./SysTick/stm32f103_SysTick.h"#include "SEGGER_RTT.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//*** @brief mian* @param None* @retval int*/
int main(void)
{ float fData = 3.1415926;char chData[32];SysTick_Init();/* USART1 配置模式为 115200 8-N-1,中断接收 */USART1_Config();sprintf(chData,"%.4f", fData);/* 无限循环*/ while (1){ SEGGER_RTT_printf(0,"float value = %s \n", chData);Delay_ms(1000); }
}/*********************************END OF FILE******************************/
最后编译下载。
打印信息如下:
当然啦,也可以自己实现浮点数转字符串的函数,有兴趣的可以试试。
另外还可通过telnet(127.0.0.1 : 19021)连接J-Link RTT Viewer查看打印信息。笔者这里使用xShell,当然也可使用其他的telnet工具。
连接成功后其打印信息如下:
在SEGGER_RTT_V760h.zip文件中的Examples目录下还有很多实例,大家都可以参看。
RTT不仅可以打印输出,也是可以输入的,可以参看Main_RTT_InputEchoApp.c实例。
附上RTT API。
函数 | 描述 |
---|---|
SEGGER_RTT_Read() | Read data from an input buffer. |
SEGGER_RTT_Write() | Write data to an output buffer. |
SEGGER_RTT_WriteString() | Write a zero-terminated string to an output buffer. |
SEGGER_RTT_printf() | Write a formatted string to an output buffer. |
SEGGER_RTT_GetKey() | Get one character from input buffer 0. |
SEGGER_RTT_HasKey() | Check if a character is available in input buffer 0. |
SEGGER_RTT_WaitKey() | Wait for a character to be available in input buffer 0 and get it. |
SEGGER_RTT_ConfigUpBuffer() | Configure an up (output) buffer. |
SEGGER_RTT_ConfigDownBuffer() | Configure a down (input) buffer. |
SEGGER_RTT_Init() | Initialize RTT Control Block structure when using RAM only targets. |
SEGGER_RTT_SetTerminal() | Set the “virtual” Terminal to use for output on channel 0 via Write and WriteString. |
SEGGER_RTT_TerminalOut() | Send a zero-terminated string via a “virtual” terminal. |
6 RTT Client使用
这里使用前面的任何一个工程。
1.点击MDK的Debug按钮进去Debug模式。
2.打开RTT Client,显示如下:
出现以上信息表示连接成功。
3.点击MDK的Run全速运行。控制台开始输出调试信息。
是不是很方便。
7 RTT Logger使用
使用前面任意一个工程。
编译下载程序,打开RTT Logger后如下所示:
在RTT Logger中,‘>’后面可以自由输入,按回车键确认。无输入的情况下,按回车键跳过。一直回车键,笔者这里使用的通道0,RTT Logger默认使用的通道1。
打开上述路径中的.log文件,里面的内容如下所示。
以上说明成功的生成了log文件。
当然啦,关于RTT更多使用请访问Segger官网学习吧。
资源获取方式
1.关注公众号[嵌入式实验楼]
2.在公众号回复关键词[J-Link RTT]获取资料提取码
欢迎访问我的网站
BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书
BruceOu的知乎
《嵌入式 - 嵌入式大杂烩》详解J-Link RTT打印相关推荐
- 《嵌入式Linux软硬件开发详解——基于S5PV210处理器》——2.2 DDR2 SDRAM芯片
本节书摘来自异步社区<嵌入式Linux软硬件开发详解--基于S5PV210处理器>一书中的第2章,第2.2节,作者 刘龙,更多章节内容可以访问云栖社区"异步社区"公众号 ...
- 《嵌入式Linux软硬件开发详解——基于S5PV210处理器》——1.2 S5PV210处理器
本节书摘来自异步社区<嵌入式Linux软硬件开发详解--基于S5PV210处理器>一书中的第1章,第1.2节,作者 刘龙,更多章节内容可以访问云栖社区"异步社区"公众号 ...
- 单片机c语言中枚举,嵌入式开发-枚举详解---朱有鹏
嵌入式开发-枚举详解 朱有鹏 1.枚举m 1.1.枚举是用来干嘛的? #include // 这个枚举用来表示函数返回值,ERROR表示错,RIGHT表示对 enum return_value { E ...
- 《嵌入式Linux软硬件开发详解——基于S5PV210处理器》——2.5 WM8960音频编解码芯片...
本节书摘来自异步社区<嵌入式Linux软硬件开发详解--基于S5PV210处理器>一书中的第2章,第2.5节,作者 刘龙,更多章节内容可以访问云栖社区"异步社区"公众号 ...
- ROS学习:URDF语法详解一link篇
ROS学习:URDF语法详解一link篇 1.概述 1.1 URDF语法详解_robot 1.2 URDF语法详解_link 1.2.3.案例需求:分别生成长方体.圆柱与球体的机器人部件 1.概述 参 ...
- 佳能2206打印机扫描显示连接计算机,佳能网络扫描怎么设置?图文步骤详解,29年打印经验总结...
原标题:佳能网络扫描怎么设置?图文步骤详解,29年打印经验总结 第一步:在电脑硬盘的根目录中建立共享文件夹,名字随便取,(建议不要建在桌面上),以win7为例:(适用于canon ir 2530i) ...
- 嵌入式 RTP协议详解以及其他相关协议
RTP协议 1 RTP报文格式 2 基于RTP的带宽控制方法 1.接收端的控制策略 2.发送端的控制策略 RTP(Real-timeTransportProtocol)是由IETF开发的实时传输 ...
- 【嵌入式小技巧】STM32 实现 SEGGER RTT 打印(超详细)
文章目录 原创声明 前言 一.RTT 是什么? 二.使用步骤 1.引入驱动库 2.实现 log 打印输出 2.0 编译选项注意 2.1 直接使用 2.2 封装使用(推荐) 2.3 效果演示 总结 授权 ...
- nRF52832 bootloader DFU固件升级源码详解(结合RTT日志打印)
文章目录 一.前文 二.init 三.nrf_dfu_command_req 四.dfu_handle_prevalidate 五.nrf_dfu_find_cache 六.nrf_dfu_data_ ...
- 嵌入式C++开发详解
一.C++概述 1.嵌入式开发中为什么选择C++语言? (1)面向过程编程的特点 C语言特点:C语言是在实践的过程中逐步完善的 ·没有深思熟虑的设计过程 ·使用时存在很多"灰色地带" ...
最新文章
- Socket:注意事项
- linux proc
- 前端面试问题(HTML5+Http+web)
- yo 搭建angular应用
- 【XAudio2】4.库版本
- lazada发货_Lazada怎么发货?最全Lazada发货流程及注意事项!值得收藏!
- cursor: mutex S等待事件
- 使用storm 实时计算_使用Storm进行可扩展的实时状态更新
- 在Kotlin中使用Gradle构建缓存
- 嵌入式Linux入门10:编译管理Makefile
- mysql show命令用不了_MySQL show命令的用法
- 电脑运行c语言时错误,电脑出现microsoft visual c++ runtime error 解决方法(多图)
- 好用的飞书版固定资产管理系统
- win7连接远程服务器特别慢,win7远程桌面连接速度慢的问题如何解决
- python 时间序列分析 图 公众号_【5分钟干货】微信朋友圈、公众号图文找图的经验之谈...
- Android 最常用的设计模式一 安卓源码分析—单例模式singleInstance
- QQ向陌生人聊天的autoit脚本
- MySQL入门系列:查询简介(二) 过滤数据
- 【Java爬虫】爬取南通大学教务处成绩
- 内网穿透工具(永久免费、永不限速、开源)、一键启动、页面操作(支持window,mac),自定义二级域名