J-Link RTT & JTrace
序言
Jlink可用直接输出调试信息,省去串口工具(配置麻烦+硬件接线乱+占用IO)
Jlink输出调试信息有两种
- Jlink的Trace
- Jlink的RTT (Real Time Transfer)
Jlink Trace
!!!Jlink Trace 待完善!!!
MDK 环境下:
#define ITM_Port8(n) (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n) (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n) (*((volatile unsigned long *)(0xE0000000+4*n)))
#define DEMCR (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA 0x01000000
int fputc(int ch, FILE *f)
{
if (DEMCR & TRCENA) {
while (ITM_Port32(0) == 0);
ITM_Port8(0) = ch;
}
return(ch);
}
RTT
RTT其实原理就是读取RAM上某个Buff的数据,这个Buff可以通过RTT的CB(control block)找到。
教程
下载Jlink的工具后,安装后程序目录有Samples文件夹(default: C:\Program Files\SEGGER\JLink\Samples),文件夹内就有RTT的源码。
-
将源码的
RTT/
目录下SEGGER_RTT_Printf.c
SEGGER_RTT.c
两个文件添加到工程里,并解决头文件包含问题。 -
看
Examples/
目录下就有使用历程,移植到你的工程就好。可以参考Main_RTT_InputEchoApp.c
和Main_RTT_PrintfTest.c
。 -
打开
J-Link RTT Viewer
软件,选择Device
,输入RTT Control Block
的地址connect即可。RTT Control Block
的地址可以输入RAM的范围让J-Link RTT Viewer
软件自己去搜索。- 也可手动输入,而RTT_V754a的
RTT Control Block
是_SEGGER_RTT
在file:SEGGER_RTT.c line:279
。
-
一顿操作下来正常就可以收到数据了。
RTT 源码
Included files
RTT/
SEGGER_RTT.c
- RTT的主要模块。SEGGER_RTT.h
- RTT的主要模块。SEGGER_RTT_ASM_ARMv7M.S
- ARMv7M 的优化实现SEGGER_RTT_Printf.c
- (’ SEGGER_RTT_Printf() ')的简单实现。
Syscalls/
SEGGER_RTT_Syscalls_*.c
-printf()
重定向
Config/
SEGGER_RTT_Conf.h
- RTT配置文件。
Examples/
Main_RTT_InputEchoApp.c
- Example application which echoes input on Channel 0.Main_RTT_MenuApp.c
- Example application to demonstrate RTT bi-directional functionality.Main_RTT_PrintfTest.c
- Example application to test RTT’s simple printf implementation.Main_RTT_SpeedTestApp.c
- Example application to measure RTT performance. (Requires embOS)
API
函数名称 | 描述 |
---|---|
SEGGER_RTT_Read() | 从输入缓冲区读取数据。 |
SEGGER_RTT_Write() | 将数据写入输出缓冲区。 |
SEGGER_RTT_WriteString() | 将\0结尾字符串写入输出缓冲区。 |
SEGGER_RTT_printf() | 将格式化的字符串写入输出缓冲区。 |
SEGGER_RTT_GetKey() | 从输入缓冲区 0 中获取一个字符。 |
SEGGER_RTT_HasKey() | 检查输入缓冲区 0 中是否有字符可用。 |
SEGGER_RTT_WaitKey() | 等待输入缓冲区 0 中的字符可用并获取它。 |
SEGGER_RTT_ConfigUpBuffer() | 配置向上(输出)缓冲区。 |
SEGGER_RTT_ConfigDownBuffer() | 配置向下(输入)缓冲区。 |
SEGGER_RTT_Init() | 仅使用 RAM 目标时初始化 RTT 控制块结构。 |
SEGGER_RTT_SetTerminal() | 将“虚拟”终端设置为通过 Write 和 WriteString 用于通道 0 上的输出。 |
SEGGER_RTT_TerminalOut() | 通过“虚拟”终端发送以\0结尾的字符串。 |
RTT 软件
-
J-Link RTT Viewer
软件用的比较多 -
J-Link RTT Logger
软件可以将输出的数据保存到文件,并显示通信速率和通信数据量。 -
J-Link RTT Client
可以在调试的时候,充当客户端,输出数据。据说支持中文
note:
- 程序如果跑在RAM中,J-Link可能会错误地识别出init部分中的块,而不是数据部分中的实际块。为了防止这种情况,将SEGGER_RTT_IN_RAM的定义设置为1。现在,J-Link将在应用程序中调用第一个SEGGER_RTT函数之后找到正确的RTT缓冲区。建议在应用程序开始时调用SEGGER_RTT_Init()。
不同通道输出数据
SEGGER_RTT_TerminalOut(0, "SEGGER_RTT_TerminalOut 0\r\n");
SEGGER_RTT_TerminalOut(1, "SEGGER_RTT_TerminalOut 1\r\n");
SEGGER_RTT_TerminalOut(2, "SEGGER_RTT_TerminalOut 2\r\n");
SEGGER_RTT_SetTerminal(0);
SEGGER_RTT_printf(0, "SEGGER_RTT_printf 0\r\n");
SEGGER_RTT_SetTerminal(1);
SEGGER_RTT_printf(0, "SEGGER_RTT_printf 1\r\n");
SEGGER_RTT_SetTerminal(2);
SEGGER_RTT_printf(0, "SEGGER_RTT_printf 2\r\n");
输出带颜色的字符
//
// Control sequences, based on ANSI.
// Can be used to control color, and clear the screen
//
#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors
#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left
#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m"
#define RTT_CTRL_TEXT_RED "\x1B[2;31m"
#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m"
#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m"
#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m"
#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m"
#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m"
#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m"
#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m"
#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m"
#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m"
#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m"
#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m"
#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m"
#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m"
#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m"
#define RTT_CTRL_BG_BLACK "\x1B[24;40m"
#define RTT_CTRL_BG_RED "\x1B[24;41m"
#define RTT_CTRL_BG_GREEN "\x1B[24;42m"
#define RTT_CTRL_BG_YELLOW "\x1B[24;43m"
#define RTT_CTRL_BG_BLUE "\x1B[24;44m"
#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m"
#define RTT_CTRL_BG_CYAN "\x1B[24;46m"
#define RTT_CTRL_BG_WHITE "\x1B[24;47m"
#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m"
#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m"
#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m"
#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m"
#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m"
#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m"
#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m"
#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m"
SEGGER_RTT_WriteString(0,RTT_CTRL_RESET"Red: "\
RTT_CTRL_TEXT_RED"This text is red."\
RTT_CTRL_BG_BRIGHT_GREEN"This background is green.\r\n");
输入字符
if(SEGGER_RTT_HasKey())
{
char r = SEGGER_RTT_GetKey();
SEGGER_RTT_WriteString(0,"input:%c\r\n", r);
}
if(SEGGER_RTT_HasKey())
{
ReadNum = SEGGER_RTT_Read(0, &acIn[0], sizeof(acIn));
for(i=0;i<20;i++)
{
if(0x0A != acIn[i])
{
ReadNum++;
}
else
{
break;
}
}
SEGGER_RTT_Write(0,acIn,ReadNum);
ReadNum=0;
memset(acIn,0,sizeof(acIn));
}