对于SEGGER RTT这个工具的确是个好东西(基本上只要是能用Jlink的芯片就能使用这个功能),但是许多时候还是在使用串口进行log输出,而对于nRF52832以及nRF52840这些芯片的串口非常稀缺的资源,所以使用SEGGER RTT作为调试接口是再好不过的,但是Nordic的sdk本身就有log通过SEGGER RTT输出,如果都打在一起不是很难看。这里解决的方法是,RT-Thread的finsh信息输出到J-Link RTT Viewer的channel 0,而NORDIC的LOG输出到J-Link RTT Viewer的channel 1。
先来个靓照吧!
-
finsh channel 0
-
NORDIC LOG channel 1
代码已经上传至GitHub以及Gitee
Github 【https://github.com/ZJ-TEK/ZJ-SDK-RT-Thread-NORDIC】
Gitee 【https://gitee.com/ZJ-TEK/ZJ-SDK-RT-Thread-NORDIC】
这里讲讲SEGGER RTT 以及移植的方法。
-
SEGGER RTT
其实在《RT-Thread BLE5.0和ANT+应用开发实战指南》中得15章中“重映射 Segger RTT 到 rt_kprintf”就有讲到SEGGER RTT的移植。这里拷贝部分。
15.1 Segger RTT简介
SEGGER的实时传输(Real Time Transfer, RTT)是嵌入式应用中交互式用户I/O的新技术,它结合了SWO和半主机的优点,具有很高的性能,使用的就是jlink作为通信工具,完全不需要额外占用芯片的硬件外围资源。它的通信模拟示意图如15-1所示。
图15-1 PC和CPU通过RTT打印示意图
RTT支持CPU到PC端的上传消息,同时也支持PC到CPU的下传消息,它的工作原理也非常简单,Segger RTT有一个控制块,这个控制块可以从一个环形缓冲器中进行数据的读写,从而能将数据传给PC,或者从PC端传给CPU。内部结构示意图如15-2所示。
图15-2 Segger RTT内部结构示意图
它的PC端软件在安装jlink驱动的时候,就已经安装好了,可以到jlink安装目录中找到一个名为J-Link RTT Viewer的软件,这个软件就像一个串口调试工具一样,有输入和显示窗口,不过可以更加高级的支持彩色打印。J-Link RTTViewer界面如图15-3所示。
图15-3 J-Link RTT Viewer界面
15.2 移植Segger RTT
15.2.1 Segger RTT源码获取
在安装jlink后,安装目录SEGGER\JLink_Vxxx\Samples\RTT中就有RTT的源码,例如我安装的是V6.30的jlink,当然也可到官网下载,其RTT源码资源如图15-4所示。
图15-4 Segger RTT源码资源
其实用到的源码文件是SEGGER_RTT.c、SEGGER_RTT.h、SEGGER_RTT_Conf.h、SEGGER_RTT_printf.c和SEGGER_RTT_Syscalls_SES.c。最后一个文件是根据编译选的,支持GCC、IAR、KEIL和SES。
15.2.2 移植RTT调试
源码上面介绍了,幸运的是NORDIC的SDK本身就支持Segger的RTT,所以它的SDK中有RTT的源码,所以我们只需添加到工程即可。
将004.led_Component工程复制为005.Seger_RTT,并将3个.c文件添加到工程,将头文件包含进工程,添加完后004和005工程的对比图如15-5所示。
图15-5 添加Segger RTT的工程对比
将文件添加完后进行编译时,出现如图15-6所示的错误.
图15-6 buffer宏没有定义
在15.1节中提到,RTT的工作是基于一个环形缓冲区,也就是一段内存,涉及到的宏就是图15-6中5个宏。所以只需要定义这5个宏就可以了,所以在sdk_config.h文件末尾添加如代码清单15-1所示的代码,这样就能正常编译了。
代码清单15-1 支持RTT的宏
// <h> nRF_Segger_RTT
//==========================================================
// <h> segger_rtt - SEGGER RTT
//==========================================================
// <o> SEGGER_RTT_CONFIG_BUFFER_SIZE_UP - Size of upstream buffer.
// <i> Note that either @ref NRF_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE
// <i> or this value is actually used. It depends on which one is bigger.
#ifndef SEGGER_RTT_CONFIG_BUFFER_SIZE_UP
#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 512
#endif
// <o> SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS - Size of upstream buffer.
#ifndef SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS
#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 2
#endif
// <o> SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN - Size of upstream buffer.
#ifndef SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN
#define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16
#endif
// <o> SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS - Size of upstream buffer.
#ifndef SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS
#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 2
#endif
// <o> SEGGER_RTT_CONFIG_DEFAULT_MODE - RTT behavior if the buffer is full.
// <i> The following modes are supported:
// <i> - SKIP - Do not block, output nothing.
// <i> - TRIM - Do not block, output as much as fits.
// <i> - BLOCK - Wait until there is space in the buffer.
// <0=> SKIP
// <1=> TRIM
// <2=> BLOCK_IF_FIFO_FULL
#ifndef SEGGER_RTT_CONFIG_DEFAULT_MODE
#define SEGGER_RTT_CONFIG_DEFAULT_MODE 0
#endif
// </h>
//==========================================================
// </h>
//==========================================================
15.3 RTT映射到rt_kprint函数
先看看RTT的API接口如表15-1所示。
表15-1 RTT的应用接口
-
RT-Thread rt_kprinf使用SEGGER RTT
将ZJ-SDK中的020.ble_nus_close_log_uart_low_power工程复制为021.ble_nus_segger_rtt_finsh的工程。在这个基础上进行修改,其实修改的地方很简单。
-
从RT-Thread官网上得到SEGGER_RTT_Device.c文件,因为这个是前辈做好了驱动,只是需要做小小的修改。
https://github.com/RT-Thread/segger_debug/blob/master/SystemView_Src/Config/SEGGER_RTT_Device.c
-
将SEGGER_RTT_Device.c这个文件放到ZJ-SDK-RT-Thread-NORDIC\NORDIC_SDK\external\segger_rtt目录下
-
将SEGGER_RTT_Device.c添加到021.ble_nus_segger_rtt_finsh工程,移除rt_nrf_hal_uart.c文件
-
修改rt_config.h
-
在sdk_config.h中使能#define NRF_LOG_ENABLED 1
-
修改 SEGGER_RTT_Device.c中的segger_putc函数,从channel 0输出
SEGGER_RTT_SetTerminal(0);设置输出channel
SEGGER_RTT_WriteString(0,RTT_CTRL_TEXT_BRIGHT_YELLOW);设置输出颜色为黄色
-
修改nrf_log_backend_rtt.c中的serial_tx函数,从channel 1输出
经过上面几步就能实现文中开头的效果了,即RT-Thread的调试信息输出哎channel 0,而nordic的log输出在channel 1,只是还是有些不足的地方,就是使用finish调试时,无法像SecureCRT一样直接输入,如果使用J-Link RTT Viewer.exe工具,那么它的输入有专门的输入区,所以对于tab键就无法实现,不过能省下串口也不错了。
同样SEGGER RTT也支持使用 127.0.0.1:19021进行数据转移,但是一旦转移,所有的数据都转移了,也就是channel 0 和 1 的数据都转移了,当然还是不能使用tab键以及上下键(如果要转移,需要先打开J-Link RTT Viewer.exe工具才能获取到数据)。下图是使用SecureCRT进行转移的,当然也可以使用SEGGER的J-Link RTT Client.exe工具。
还有一个需要注意的地方是,因为函数调用没有加互斥,同时输出buffer使用的同一个也会存在channel 0的数据输出到channel 1里面,反之也有可能,这个问题本应该使用不同的两个buffer就OK了的,但是不知道为啥SEGGER RTT的无法使用第2个Buffer,我也已经在其论坛提出了这个问题,所以可能也还存在一定的问题,这个日后慢慢修改。
OK!这篇文章到此结束,所有代码已经提交,只是文档还需要时间写,各位朋友可以先关注,同时这代码支持的板子是ZJ-曹孟德nRF52840开发板,同时ZJ-关云长nRF52832开发板已经打板,预计月底能贴出来,也希望各位给与支持,多谢!
Github 【https://github.com/ZJ-TEK/ZJ-SDK-RT-Thread-NORDIC】
Gitee 【https://gitee.com/ZJ-TEK/ZJ-SDK-RT-Thread-NORDIC】
公众号:Bluetooth-BLE
bbs.codertown.cn
QQ群:177341833