前面几篇文章,分享了Mac环境搭建STM32开发环境的基本步骤,以及调试工具的使用 编写code用vscode,编译在终端用ARM gcc命令,串口/JLink烧录,GDB command调试,完成整个开发调试需要用到多个工具和方式
开发环境选择,安装配置相关工具 https://blog.csdn.net/u010105424/article/details/106873610简单例子,说明开发过程和使用到的基本工具 https://blog.csdn.net/u010105424/article/details/106874707编写Makefile,定制化编译功能 https://blog.csdn.net/u010105424/article/details/106876102配置Jlink,简单介绍下JTAG/SWD/JLink之间的关系 https://blog.csdn.net/u010105424/article/details/106875832介绍JLink常用功能,包括烧录、GDB、Log https://blog.csdn.net/u010105424/article/details/107074584为了加快开发效率,需要优化一下流程,考虑将以上开发的所有步骤自动化完成,并集成到一起 事实上,vscode就可以做到,利用vscode灵活的配置,将各个功能嵌入
VS code中可以定义一系列的tasks(任务),然后通过任务窗口将任务启用,我们用来实现编译、烧录、测试等功能 参考官网 https://code.visualstudio.com/docs/editor/tasks =》⌃⌥T 组合按键可以唤出任务栏,然后选择要执行的任务
{ "version": "2.0.0", "tasks": [ { "label": "Build", // 任务名 "type": "shell", // 任务执行的是shell命令 "command": "make", // 任务命令 "problemMatcher": "$gcc", // GCC捕获错误 }, { "label": "Program", "type": "shell", "command": "JLinkExe -device stm32f103rc -autoconnect 1 -if SWD -speed 4000 -CommandFile CommandFile.jlink", "dependsOn": "Build", // 依赖"Build"命令先运行 "problemMatcher": [], "group": { // 设置为默认"build"组命令,⇧⌘B 按键快速编译烧录 "kind": "build", "isDefault": true } }, { "label": "Disassembly", "type": "shell", "command": "arm-none-eabi-objdump -ldS OBJ/STM32_REG_TEST1.elf > STM32_REG_TEST1.asm", "problemMatcher": [], }, { "label": "GDBServer", "type": "shell", "command": "JLinkGDBServer -select USB -device STM32F103RC -endian little -if SWD -speed 4000 -noir -noLocalhostOnly", "problemMatcher": [], }, { "label": "Connect to JLink", "type": "shell", "command": "JLinkExe -device stm32f103rc -autoconnect 1 -if SWD -speed 4000", "dependsOn": "make", "problemMatcher": [], }, { "label": "JLink RTT log", "type": "shell", "command": "JLinkRTTClient", "problemMatcher": [], } ] }=》以上是个人的配置 留意几点:
"Program"设 “dependsOn”: “Build”,可以确保code烧录前已经先编译“Disassembly” 对elf文件(symbol)反编译生成汇编和C交叉码,辅助调试"GDBServer"是为launch任务准备的,需要先起GDB server,才能用调试“Connect to JLink” 是为JLinkRTTClient准备的,需要先连接上JLink才能启用当按下"F5"按键时,VS code会在WSL启动launch.json的任务。所以可以在launch.json定义GDB调试方式 参考官网 https://code.visualstudio.com/docs/editor/debugging
{ "version": "0.2.0", "configurations": [ { "name": "DGB debug", "type": "cppdbg", "request": "launch", "targetArchitecture": "arm", "program": "${fileDirname}/${fileBasenameNoExtension}", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", // 工作路径 "environment": [], "externalConsole": false, //"preLaunchTask": "Program", // 前置任务 //"postDebugTask": "...", // 后置任务 "MIMode": "gdb", "miDebuggerPath": "/Users/yuanziqi/toolchain/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-gdb", // GDB command路径 "launchCompleteCommand": "None", "miDebuggerServerAddress": "localhost:2331", // GDBSerevr IP:Port "customLaunchSetupCommands": [ { "text": "file /Users/yuanziqi/Desktop/WorkSpace/Code/vscode/STM32_REG_TEST1/OBJ/STM32_REG_TEST1.elf", "description": "Load symbol file", "ignoreFailures": false }, { "text": "target remote :2331", "description": "Connet to GDB server", "ignoreFailures": false }, { "text": "break main", "description": "Set breakpoints at main", "ignoreFailures": false }, { "text": "monitor reset", "description": "Reset the target", "ignoreFailures": false }, ] } ] }留意几点:
“preLaunchTask” 是在launch任务执行之前执行的任务。运行在tasks.json中定义的任务,后面带的名字要与任务label名一致“postDebugTask” 是launch任务退出后执行的任务,一样在tasks.json中定义“customLaunchSetupCommands” 就是在gdb client运行后做的几步动作,这几步是核心 file /*.elf :加载symbol,带入调试符号target remote :2331 :连接gdb serverbreak main :设置断点在main,reset平台后,就会停在main函数处monitor reset :平台reset,注意硬件上Jlink的RESET引脚要接上步骤:建立工程->导入相关.s/.ld/库文件->编写源码->编写Makefile->编写JLink烧录脚本
步骤:⌃⌥T 按键组合唤出任务栏,依次运行[Build]、[Program];或者执行⇧⌘B 按键组合直接执行【Program】(会先跑Build) =》终端控制台显示任务运行成功,可以看到开发板上已生效
步骤:⌃⌥T 按键组合唤出任务栏,依次运行[Connect to JLink]、[JLink RTT log] 该例子中,代码里就是用RTT来做printf功能的 注意:大家可以留意到,这两个task都是常驻任务,当退出时需要依次退出这两个task(两次Ctrl+C),这是比较麻烦的一个地方,同时也无法使用"dependsOn"来一次性启用两个任务。。。后续GDB调试中,Server和Client也是同样两个任务,有一样情况
步骤:⌃⌥T 按键组合唤出任务栏,运行[GDBServer],之后F5启用调试任务 另外我们可以看到左边栏的一些功能:变量、监视(变量跟踪)、调用堆栈(backtrace)、断点、寄存器、内存等 这时候GDB已经连接上了,并reset跑到main处,接下来我们做一些调试实验
=》当按第二下F5跑起来后,出现一处异常,从左边[变量Locals]和[调用堆栈]看出从main函数这一句调用下来"SEGGER_RTT_WriteString(0, “test \n”);" =》事实上读取寄存器这个功能还没有实现,无法看出内部发生的原因,所以这种情况下只能另外在终端挂GDB分析了。最后的解法如下: #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 1 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop
至此,通过vscode提供task功能,经过一系列配置,实现了类似keil IDE的功能,当然还有缺陷,比如无法查看寄存器、dump内存、反汇编调试等,但日常开发基本够用 在vscode插件中有看到一个Cortex-Debug,或许可以实现更完整的功能,找时间再试试啦