用VS Code开发STM32(四)——增加SEGGER RTT日志输出支持
之前的教程都是使用OpenOCD作为GDB Server,好处是支持各种不同的调试器。但 如果你仅使用Jink,不用其他的调试器,那么显然用Jlink自己的GDB Server是更加合适的 。
SEGGER为jlink提供了各种工具,例如J-Scope,RTT(Real Time Transfer)等。今天的内容就是把RTT Client嵌入到VS Code中。
最终效果 :只插一个Jlink,使用SWD接口,无需占用串口,无需SWO引脚,实现日志printf输出(带颜色)如下:
1 为什么需要日志
虽然利用断点、调用堆栈和变量窗口能很方便地进行调试,但是在一些情况下,是不允许打断点的,例如无人机、蓝牙/WiFi协议栈等。一旦程序暂停,就会造成连接断开、坠机等事故。因此,日志的输出也是很重要的调试手段,它不仅能够输出数据、还能够给我们提供程序跳转的信息。
2 日志的输出方法
- 串口输出
在刚开始学习STM32时,有些教程会教你把fputc函数映射到串口输出上,这样就可以使用printf函数从串口输出日志了。但是这样要占用一个串口资源、而且映射的串口发送函数是阻塞的,如果波特率太低或者发送数据太多,就会导致你的程序卡顿。
- 半主机
另一种日志输出方案是 半主机(Semihosting) ,它是ARM调试的一种机制,利用软件中断,让嵌入式设备在调试时使用调试主机(PC)的显示器和键盘进行标准输入和输出。这样的好处是省一个串口,坏处是 速度太慢,大概10ms才能出一个字符......
- SWO
Cortex-M3/M4内核的调试组件中有一个专用的模块——仪器化跟踪单元(ITM),它的作用就是输出调试信息。利用JTAG的SWO引脚可以进行输出,速度比较快。缺点是要占用一个SWO引脚,现在很多买的调试器都是SWD接口,只有SWDIO和SWCLK引脚了,带SWO的要么贵、要么太大看着笨重。
- SEGGER RTT
SEGGER RTT (Real-Time Transfer)结合了以上所有方法的优点:无需额外引脚、无需占用外设、只需要SWD引脚就可以输出日志,并且 速度快,不影响应用程序的实时性。
想想只用插一个Jlink就可以同时断点调试+输出日志,还是很爽的。
3 安装SEGGER Jlink驱动全家桶
为了使用RTT,我们需要先安装jlink驱动全家桶,这里给出网址: https://www. segger.com/downloads/jl ink/
找到这个jlink大礼包,点击Click for downloads,选择你的平台(windows,linux,osx)。下载完后安装即可。
【注】 如果你看了第一篇文章: 《用VS Code开发STM32(一)——软件安装》 ,安装了Zadig并且修改了jlink驱动,建议直接在设备管理器里面卸载这个修改过的驱动,然后再安装jlink大礼包。
安装完毕后你的电脑里会多出一堆工具:
然后,把这些工具的路径加入到“Path”环境变量中:
4 给代码中添加源文件和头文件
在
C:\Program Files (x86)\SEGGER\JLink\Samples\RTT
路径中,有一个Jlink RTT例程源码压缩包,我们把它复制到桌面再解压。
然后把压缩包里的整个RTT文件夹复制到你的STM32工程中:
这里,User目录下的log.h是我自己写的,目的是方便日志输出,内容如下:
/*
* Author: Jayant Tang
* Email: jayant97@foxmail.com
#ifndef _LOG_H_
#define _LOH_H_
#include "SEGGER_RTT.h"
#define LOG_DEBUG 1
#if LOG_DEBUG
#define LOG_PROTO(type,color,format,...) \
SEGGER_RTT_printf(0," %s%s"format"\r\n%s", \
color, \
type, \
##__VA_ARGS__, \
RTT_CTRL_RESET)
/* 清屏*/
#define LOG_CLEAR() SEGGER_RTT_WriteString(0, " "RTT_CTRL_CLEAR)
/* 无颜色日志输出 */
#define LOG(format,...) LOG_PROTO("","",format,##__VA_ARGS__)
/* 有颜色格式日志输出 */
#define LOGI(format,...) LOG_PROTO("I: ", RTT_CTRL_TEXT_BRIGHT_GREEN , format, ##__VA_ARGS__)
#define LOGW(format,...) LOG_PROTO("W: ", RTT_CTRL_TEXT_BRIGHT_YELLOW, format, ##__VA_ARGS__)
#define LOGE(format,...) LOG_PROTO("E: ", RTT_CTRL_TEXT_BRIGHT_RED , format, ##__VA_ARGS__)
#else
#define LOG_CLEAR()
#define LOG
#define LOGI
#define LOGW
#define LOGE
#endif
#endif // !_LOG_H_
5 添加测试程序、修改
Makefile
和
c_cpp_properties.json
-
在
main.c
的main函数while(1)循环附近,添加相关测试代码:
- 修改Makefile,添加头文件路径和源文件:
-
修改
c_cpp_properties.json
:
6 修改
launch.json
之前的教程是openOCD的,这里改回Jlink GDB Server:
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
"name": "Cortex Debug",
"cwd": "${workspaceRoot}",
"executable": "${workspaceRoot}/build/${workspaceFolderBasename}.elf",
"request":"launch",
"type":"cortex-debug",
"device":"STM32F407VE", //使用J-link GDB Server时必须有;其他GBD Server时可选(有可能帮助自动选择SVD文件)。支持的设备见 https://www.segger.com/downloads/supported-devices.php
"svdFile": "./STM32F407.svd", //svd文件,有这个文件才能查看寄存器的值,每个单片机都不同。可以在以下地址找到 https://github.com/posborne/cmsis-svd
"servertype": "jlink", //使用的GDB Server
"configFiles": [