在使用STM32L系列开发的时候大家不知道注意过,用jlink rtt viewer可以省去一个串口,对资源紧张的芯片还是很有意义的,而且rtt的原理是芯片主程序和jlink共享一块内存,由jlink去读该内存的变量即可知道当前的状态,对于系统程序而言,相比传统的串口打印,不需要调用硬件去中断发送或者软件发送,而是将要打印的内容送入指定的内存地址即可,对单片机程序而言约等于变量赋值操作;最关键的是,可以在中断函数中直接调用,而传统的串口则会有问题;因此这么好用的东西当然要利用起来:
本次使用的是STM32L4系列,该系列的STM32有两块RAM空间,分别是RAM1和RAM2(这里很重要,等下就知道为什么);在使用标准的RTT viewer 查看日志和shell调试的过程中(启动shell和添加 SEGGER_RTT库的办法在此不赘述,查看官方文档即可),可以省去一个串口,尤其是对于L431CC这种IO资源紧张的芯片。在使用MDK添加RT -thread nano后,直接在目录里添加如下4个文件:SEGGER_RTT.h;SEGGER_RTT.c;SEGGER_RTT_Conf.h;SEGGER_RTT_printf.h;
之后在option》C/C++》include Path中添加该库文件,并在函数中初始化,
并分别在rt_hw_console_getchar()和 rt_hw_console_output()函数中添加输入输出即可;
这样就可以把rt_kprint函数重定向到jlink的rtt里了 。
之后是在RT -Thread Master基于RT studio开发的版本V4.02;和nano有很多部分的定义不一样,比如board文件内的函数有的移动到了drv_common.c 中,这点需要注意;最关键的是,RT-thread
master版本的HAL库利用了之前提到的ram2;按照官方的说法,RAM1是主RAM,存放常规的变量和函数,而RAM2则是用于做高速缓存,可以理解为cache,存放ringbuffer,DMA高速读写的数据等等,而最关键的是masterV4.02以上的版本,将segger_rtt的变量也存放到了RAM2!!
这直接导致的后果是在打开jlink rtt viewer等工具后,找不到_SEGGER_RTT的变量!。因为该变量的位置并不在默认的0x2000000之后,而是在0x1000000之后!
这就是我在苦苦debug始终找不到jlink rtt shell的症结所在。
对于STM32L431CC,RAM1 的地址为0X200000000~0X20048A20,这也是JLINK RTT viewer的默认查看地址;
我们打开刚刚的nano版本的工程的map文件:
可以看到rtt_viewer 所显示的默认地址和_SEGEER_RTT 变量是在0x2000000之后的;因此打开jlink rtt viewer后选择默认自动搜寻即可找到该地址;
而在使用v4.02之后的版本中,该版本将_SEGEER_RTT 优化到了RAM2,我们同样打开编译后产生的map文件:
可以看到,data段,bss段等的数据已经全部移送到ram2中了,
我们再看下工程目录下的link.lds文件:而我们在编译后,_SEGEER_RTT 地址会变化;因此,当编译后的工程发现变量在RAM2的时候,我们在打开jlink rtt的时候需要选择地址为0x1000000,范围根据RAM2大小来填写,如笔者使用的是STM32L431,RAM1 48K,RAM2 16K;因此地址区为0x1000000 0x4000;
如此就可以正常搜到地址了!