0 前言
因为研究单片机的半主机模式,一直深入挖掘到OpenOCD工具的使用,看的内容较多,且有点杂乱,为整理思路,特写此文。
1 OpenOCD是什么
OpenOCD,全称为The Open On-Chip Debugger (片上调试器),是Dominic Rath在2005年发起的一个开源项目,来自他的毕业论文。如今已经成为一个活跃的开源项目。其主要的作用是就是嵌入式设备的调试,可以在有调试器(如DAP-Link和ST-Link)的前提下,实现设备的调试,其结构框图如下图所示。

所以这个本质上只是一个连接调试设备的工具,JTAG Module用来支持JTAG协议,Target Module用来支持多种型号的芯片,Flash Module用来给芯片擦写Flash,GDB Server用来给GDB Client提供连接,实现代码调试。
这里有一个问题,一般在PC上写代码需要调试都是直接使用GDB就行,那为什么这里需要有一个Server呢?这是因为代码是在外部的嵌入式芯片运行的,必须要增加一道转接,来翻译指令和传输数据,而TCP协议又非常简单易用,自然就采用这种Client-Server的结构了。这里所谓的Client其实就是基于GNU下的GDB工具改造得到。
其实,除了OpenOCD,常用调试器的官方也为自家的调试器开发了一套适配自家设备的调试工具,如ST-Link有ST-Link GDB Server:

J-LINK安装的驱动也带有GDB Server:

OpenOCD和上述差不多,但它是开源的,支持多种设备,所以目前使用最为广泛。
2 STM32CubeIDE中如何使用OpenOCD
如果想先体验一下OpenOCD,最好的选择就是STM32CubeIDE,因为该IDE集成了ST-Link GDB Server(默认选择)和OpenOCD,当然也有J-LINK对应的SEGGER,在项目属性的配置里面:



其实STM32CubeIDE就已经集成了这些软件工具,所以不需要像网上的各种教程那样,先下载一个OpenOCD,CubeIDE本身就可以直接使用,即上面那里选择启动本地GDB服务器:

所以,总结来说,如果想体验一下OpenOCD,直接使用ST-Link,然后找一个写好的CubeIDE项目,在属性中,将上述的“调试探头”切换一下就行,其他的都不用动。
配置好之后,先试试下载,和原来的方式一样,直接点击工具栏中的三角形按钮。然后ST-LINK的指示灯就开始闪烁,同时可以看到控制台输出一堆红色的字:

不要觉得都是红色的字就是报错,要看内容,比如左侧是info就没事,如果出现error就要关注了。如果不放心,可以先写一个简单的串口输出的程序测试一下。
但是在这一步可能会遇到一个问题:

查看日志,可以发现显示芯片没有halt,超时:

关于这个,插一句:网上有人提到这一问题可能是CubeIDE更新导致的,因为原先的版本是可以的,但升级之后就不行了,我使用的版本是1.15.1,有点新,但也不想为了这个问题就回退到很老的版本,所以这个说法未验证。
然后我觉得可能是没有按照网上所要求的一样:先下载一个OpenOCD,添加到环境变量之后再使用远程连接,也就是在项目属性中选择这个:

照做之后,又出现了另一个报错:

对于这一报错,STM32 Community中官方人员的答复是因为使用了盗版芯片:

然而,在StackOverflow上的一个提问强调自己使用的是正版芯片仍然遇到这个问题,然后有回答说这个可能是因为盗版ST-Link。emmmm,好吧,可能我用的都不是正版。。。
但是很奇怪的是,我看到的另一篇文章里面有提到如果想要避开ST官方对芯片ID的检查,就是要使用远程连接,也就是自己下载一个原版的OpenOCD。【看这意思好像CubeIDE自带的OpenOCD是修改过的?】那为什么我使用外置的OpenOCD反而报版本问题了呢?
正当我要放弃的时候,无意间看到一篇文章提到设置OpenOCD时还要设置复位模式:

确实,我用的bluepil,没接复位按钮,所以这里选择None,尝试了一下,使用CubeIDE也能正常下载或仿真了,OK,问题解决!
3 单独使用OpenOCD
在解决上述问题时,也查了一些其他的资料,让我对OpenOCD有了一个简单的认识,发现其实它其实本身可以独立使用,CubeIDE只是提供了图形化的界面而已,内部的功能还是OpenOCD原本的功能,完全可以自己下载安装包来搞。
OpenOCD预编译包下载——目前官方只提供源码,不想自己编译的还是直接从这下载吧
基本的安装和使用比较简单,就是找个地方解压,然后把bin路径添加到环境变量即可。
如果只是想体验一下,不想改环境变量,那也可以定位到bin文件所在目录进行运行,都是可以的。
首先,是OpenOCD的基本使用:开启GDB Server,提供调试,指令如下:
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg
其中,第一个cfg文件为调试器配置,在安装目录下的interface文件夹,如果是其他的调试器,可根据自己需要进行选择;第二个cfg文件为芯片型号,我使用的是f103c8t6,根据自己的情况选择。
注意,如果没有添加到环境变量,要注意后面两个配置文件的路径
运行之后,可以看到GDB Server已经启动,默认监听3333端口,也可以自己设置其他端口,具体方法查看help文档。
注意,这里要连接ST-Link或其他调试器,否则会报错自动退出
再来说说如何使用OpenOCD下载程序,毕竟这个需求还是很正常的
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c init -c "reset halt; wait_halt; flash write_image erase C:/Users/Zeoy/Desktop/Project.bin 0x08000000" -c reset -c shutdown
其实就是在上述开启调试的基础上加上了一些指令,也就是参数-c后面的那些,这里需要注意bin文件路径不带空格。
除此之外,OpenOCD还可以结合编译工具链实现更多功能,即编译再下载,这里使用的工具链是arm-gnu-toolchain,下载链接,具体的使用有兴趣的可以自行百度。这种做法比较适用于Linux系统下的开发需求,或者想自己构建一个IDE。
4 半主机模式
回到最开始的目的,就是这个半主机模式到底是个啥,相信大部分人第一次知道这个东西应该都是在STM32串口重定向的时候知道的,简单来说,就是考虑到单片机没有输入输出终端,比如鼠标键盘和显示屏这些,就想利用主机的输入输出设备来调试芯片程序。这个是ARM内核的芯片特有的模式。这样说其实很抽象,因为很多人很难想象单片机怎么访问主机的设备,而这里的玄机,就是上面提到的调试器以及对应的连接调试器的软件工具(GDB Server),即单片机通过调试器将指令通过TCP协议发给GDB Server,然后由GDB Server调用主机上的输入输出设备,完成调试。
可惜的是,中文互联网上基本所有的教程都是在教如何关闭半主机模式,那有没有什么办法可以开启这个呢?毕竟只看这些文字描述其实还是不够直观,自己亲身实践一下体会肯定更加深刻。
于是我在ST的社区里找到一篇使用半主机模式,实现通过单片机的代码对PC主机内文件的写入和读取的教程,基于STM32CubeIDE,使用的硬件是ST-Link+Bluepill的经典组合(都是某宝便宜货),调试探针使用的是STM32CubeIDE自带的OpenOCD(ST-Link GDB Server不支持这个半主机模式),记得设置复位模式的选项。
-
首先需要有一个工程,随便配置些晶振,SWD这些即可,确定编译通过,可下载。
-
其次删除工程中的
syscalls.c文件,此时再编译会发现工程竟然没有报错,只是多了几个warnings -
然后就可以开始修改代码了,只改main.c即可:
第一部分:增加头文件调用和半主机模式初始化声明 /* USER CODE BEGIN Includes */ #include <stdio.h> extern void initialise_monitor_handles(void); /* USER CODE END Includes */ 第二部分:main函数后面紧接着调用半主机模式初始化函数和一些文件读写的变量声明(后面有用) int main(void) { /* USER CODE BEGIN 1 */ initialise_monitor_handles(); char s[50]; char *p; FILE *fp; p=s; /* USER CODE END 1 */ 第三部分:读写文件测试 /* USER CODE BEGIN WHILE */ printf("Hello, World!\n"); fp=fopen("C:\\Users\\Zeoy\\Desktop\\mytest.txt", "w"); //具体路径根据实际情况修改 while (1) { printf("Enter string:\n"); scanf("%s", p); printf("\nReceived string: "); printf(p); printf("\n"); fprintf(fp,p); fprintf(fp,"\n"); fclose(fp); HAL_Delay(500); fp=fopen("C:\\Users\\Zeoy\\Desktop\\mytest.txt", "a");//具体路径根据实际情况修改 /* USER CODE END WHILE */ -
然后还要对项目进行配置,都在项目属性里面
在Libraries中增加rdimon:
在Miscellaneous中添加-specs=rdimon.specs:
修改debug config:
和前面提到的设置openocd的方式一致:

在初始化指令中增加monitor arm semihosting enable:

-
最后,点击编译(正常应该是0 error,0 warning),再debug,就可以像正常调试主机上的c语言代码了,终端的输入输出都会显示:

这里连scanf不接收空格后的内容都和标准C语言一模一样。然后可以看到桌面上确实多了一个mytest.txt的文件:

和终端的输入输出的一致的。
5 总结
总结一下,本文从研究半主机模式出发,大致介绍了OpenOCD这个工具的定位和作用以及最基本的使用方式,之后在STM32CubeIDE中通过OpenOCD实际体验了一下半主机模式的使用,发现这个确实可行,而且确实可以在调试时提供一点帮助。当然,最明显的问题就是这个模式的使用需要有调试器,当单片机安装在设备上之后就不太方便了。
通过这一次的调研加实践,让我对调试器的工作原理和这个半主机模式有了一个更深入的理解,算是学有所得。

377

被折叠的 条评论
为什么被折叠?



