[应用相关] 如何使用JLINK RTT打印log日志

[复制链接]
 楼主| htmlme 发表于 2023-2-23 16:12 | 显示全部楼层 |阅读模式
没有串口的情况下可以使用JLINK的RTT即 Real Time Transfer功能。RTT的工作原理大致就是在内存里面创建一个RTT控制块RTT Control Block,即SEGGER_RTT_CB结构体。这个结构体里面存放了若干个上行通道和下行通道,每个通道都有一个数据buffer以及读写指针,构成了数据队列。向RTT控制块里面的任意一个上行通道的数据队列中写入log信息,然后JLINK能够通过读写RAM内容,获取到队列的数据buffer和写指针的内容,并更新读指针。如果写入的数据太快,JLINK的刷新速率来不及读取队列内容的话,可能导致队列满,数据丢失情况,可以适当加大上传队列的长度:BUFFER_SIZE_UP,在配置文件SEGGER_RTT_Conf.h中。
在JLINK的安装目录里面有RTT的代码:
可以直接使用SEGGER_RTT_Write函数写字符串:
  1. SEGGER_RTT_Write(0, "0123456789", 10);


或者使用SEGGER_RTT_printf进行格式化打印:
  1. SEGGER_RTT_printf(0, "%s\n", "test");


使用RTTViewer工具可以通过JLINK实时读取RAM内容获取上传通道的数据内容:
由于需要获取芯片RAM中的数据,那就得要知道要读取的RAM地址,也就是RTT Control Block的地址。RTT Control Block的结构体定义为:


    1. typedef struct {
    2.   char                    acID[16];                                 // Initialized to "SEGGER RTT"
    3.   int                     MaxNumUpBuffers;                          // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
    4.   int                     MaxNumDownBuffers;                        // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
    5.   SEGGER_RTT_BUFFER_UP    aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS];       // Up buffers, transferring information up from target via debug probe to host
    6.   SEGGER_RTT_BUFFER_DOWN  aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS];   // Down buffers, transferring information down from host via debug probe to target
    7. } SEGGER_RTT_CB;




程序定义了一个RTT Control Block变量:_SEGGER_RTT
  1. SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT));


其中acID会被初始化为固定字符串值:“SEGGER RTT”,可以用这个字符串做为Magic Number,在整个RAM空间里面搜索到RTT Control Block的位置,但是有点傻。找到编译生成的map文件,查找_SEGGER_RTT的位置:
然后在RTT Viewer里面connect的时候设置RTT control block地址为_SEGGER_RTT的地址:
运行结果:
RTT Viewer终端支持显示不同字符颜色以及清空屏幕指令,SEGGER_RTT.h中有控制指令定义,使用方式示例:


    1. SEGGER_RTT_Write(0, RTT_CTRL_BG_BLACK RTT_CTRL_TEXT_RED "0123456789", 20);

    2. SEGGER_RTT_printf(0, RTT_CTRL_BG_GREEN RTT_CTRL_TEXT_YELLOW "%s\n", "test");




运行结果:
有点不方便的是每次在data段添加变量的时候,数据的内存地址可能会改变,那么_SEGGER_RTT的地址就会变化,这样每次都要查看_SEGGER_RTT的地址,比较麻烦,可以使用attribute关键字指定_SEGGER_RTT变量存放在内存的位置,注意要避开启动文件中默认分配的stack的地址区域和heap地址区域,例如这里我改成:


    1. //SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT));
    2. SEGGER_RTT_CB _SEGGER_RTT __attribute__ ((at(0x1FFE4000)));




豌豆爹 发表于 2023-2-28 11:30 来自手机 | 显示全部楼层
感谢分享,学一学
gygp 发表于 2023-5-7 10:26 | 显示全部楼层
在程序中添加JLINK RTT库函数和头文件。例如,对于Cortex-M系列的MCU,可以使用SEGGER公司提供的J-Link软件包,并添加相应的.h和.c文件到工程中。
jonas222 发表于 2023-5-7 10:44 | 显示全部楼层
使用JLINK调试器连接单片机后,可以在J-Link RTT Viewer或J-Link GDB Server等工具中查看log信息。
belindagraham 发表于 2023-5-7 14:02 | 显示全部楼层
怎么在mdk 添加jlink rtt
belindagraham 发表于 2023-5-7 14:59 | 显示全部楼层
#include "SEGGER_RTT.h"

int main(void)
{
    SEGGER_RTT_WriteString(0, "Hello World!\r\n");  // 输出字符串
    SEGGER_RTT_printf(0, "The value is %d\r\n", value);  // 格式化输出
    ...
}
maqianqu 发表于 2023-5-7 18:21 | 显示全部楼层
在主函数中初始化JLINK RTT,并设置输出通道。  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

2936

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部