前言
- 1)上一节中,我们知道 parse_config_file() 函数会边解析配置文件,边执行其中的命令,那么接下来我们将主要学习一下 OpenOCD 配置文件中涉及到的命令。
- 2)我们知道,要编写一个 OpenOCD 驱动,除了要实现烧录算法外,还要编写关于 MCU 的配置文件。OpenOCD 主要有 3 类配置文件(具体内容见官方文档第 6 节 配置文件参考),这里我们简单看一下。
3)<font color="red">interface</font>:指定调试器的适配器驱动。
- (1)该驱动实现 OpenOCD 为调试器们定义的统一接口,将来自 OpenOCD 的操作,转换为调试器的操作。
- (2)常用的调试器都有对应的驱动,如 jlink、st-link、cmsis-dap、ftdi 等。
- (3)当你根据公有(或私有)的调试协议设计出了自已的调试器,就需要在此为其添加一个驱动。如沁恒 WCHLink 的调试器适配驱动为 wlinke。
(4)可以通过以下命令来查看一下 OpenOCD 支持调试器的适配器驱动:
grep -rn "adapter driver " | awk -F ':' '{print $3}' | uniq -u adapter driver ftdi adapter driver cmsis-dap adapter driver jlink adapter driver rlink adapter driver st-link adapter driver hla adapter driver ulink ......
- 4)<font color="red">board</font>:指定开发板特定的初始化项。比如,同样的 MCU 内核,但 SRAM 和 FLASH 的大小、起始地址可能不同,此时可以在 board 配置文件中指定这些不同项。不过大部分情况下,只是在该配置文件中指定引用的 interfact 和 target 配置文件及其它选项,然后在烧录时指定该配置文件。
- 5)<font color="red">target</font>:指定 MCU 中需要交由 OpenOCD 控制的测试访问端口(Test Access Port, TAP)。
6)还有一些其它的配置文件,用于指定一些公共的调用过程,芯片信息等。本文主要是对配置文件中用到的命令(如下图)进行解析,以在命令行运行如下命令的结果为准:
openocd -d3 -f board/airm2m_air001.cfg -d3 也作 --debug-level=3。即指定输出日志级别。 -f 也作 --file。这里指定开发板为合宙 air001 芯片。
7)参考链接:
1 adapter driver
1.1 前置知识
1.1.1 struct adapter\_driver
- 1)在解析 adapter driver 命令之前,让我们先来了解一些前置知识。
2)在 interfaces.c 文件中,OpenOCD 会根据编译选项来引入一些 struct adapter\_driver。比如说我们通过以下命令使能 ftdi,将在生成的 config.h 文件中声明 “#define BUILD\_FTDI 1” 宏定义,最终使 interfaces.c 文件中的 ftdi\_adapter\_driver 生效(当然有些 adapter 是自动使能的,如 cmsis\_dap)。
../configure --enable-ftdi
- (1)adapter\_driver 既实现了对调试器的驱动,又是 OpenOCD 与调试器交互的适配器。
- (2)每个调试器都有自已支持的传输方式,初始化、退出、复位过程,以及设置速度等功能,所以 OpenOCD 提供一个接口(interface,struct adapter\_driver),来定义出 .transports, .init, .quit, .reset, .speed 等接口函数指针,让不同的调试器自己去实现,而 OpenOCD 上层只需要调用这些接口函数,即为适配器模式。
- (3)最后,OpenOCD 支持多少种调试器,interfaces.c 文件中就会有多少 adapter\_driver。
- 3)cmsis-dap 的 adapter\_driver 实现如下:
struct adapter_driver cmsis_dap_adapter_driver = {
.name = "cmsis-dap",
.transports = cmsis_dap_transport,
.commands = cmsis_dap_command_handlers,
.init = cmsis_dap_init,
.quit = cmsis_dap_quit,
.reset = cmsis_dap_reset,
.speed = cmsis_dap_speed,
.khz = cmsis_dap_khz,
.speed_div = cmsis_dap_speed_div,
.config_trace = cmsis_dap_config_trace,
.poll_trace = cmsis_dap_poll_trace,
.jtag_ops = &cmsis_dap_interface,
.swd_ops = &cmsis_dap_swd_driver,
};
1.1.2 transport
- 1)上一小节中,我们知道 cmsis\_dap\_adapter\_driver 的 .transports 指定了 swd 和 jtag 传输方式(如下),这一小节我们来看一下 transport 的相关内容。
static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
struct adapter_driver cmsis_dap_adapter_driver = {
.name = "cmsis-dap",
.transports = cmsis_dap_transport,
......
}
/************** 分隔线 **********************************************/
static struct transport jtag_transport = {
.name = "jtag",
.select = jtag_select,
.init = jtag_init,
};
static struct transport swd_transport = {
.name = "swd",
.select = swd_select,
.init = swd_init,
};
2)在 transport.c 中有一个 transport\_register() 函数,顾名思义——注册 transport。接下来,我们看一下哪些地方调用了这个函数,就可以知道 OpenOCD 支持哪些传输方式了。
3)最终,我们可以知道 OpenOCD 支持这些传输方式(官方文档 8.3 Transport Configuration):
- jtag
- swd
- hla\_jtag
- hla\_swd
- dapdirect\_jtag
- dapdirect\_swd
- swim
- 4)swd 和 jtag 分别是通用的传输方式;而 hla\_jtag 和 hla\_swd 则是来自于使用了一些高级抽象 API 的 hla\_adapter\_driver;dapdirect\_jtag 和 dapdirect\_swd 则提供了仅支持 ST-Link 的直接访问 ADIv5 DAP 方式。
- 5)注:以下代码结构表示,在 GCC 中,项目启动时调用该函数,所以在 OpenOCD 启动时,这些 transport 将会被注册:
static void swd_constructor(void) __attribute__((constructor));
static void swd_constructor(void)
{
transport_register(&swd_transport);
}
1.2 adapter driver cmsis-dap
- 1)上一小节前置知识中,我们知道 OpenOCD 在编译期加载调试器的驱动适配器(adapter\_driver),在启动时注册所有的传输(transport)。下面我们来看一下 “adapter driver cmsis-dap” 命令的执行逻辑。
2)adapter driver cmsis-dap 命令的执行逻辑如下:
- (1)首先执行该命令将会回调到 handle\_adapter\_driver\_command() 函数。在该函数中将遍历所有的 adapter\_driver,并根据该命令指定的驱动名(这里为 cmsis-dap)找到对应的 adapter\_driver。
- (2)然后,注册该 adapter\_driver 定义的命令,并设置其允许的传输方式(transport)
- (3)最后,如果该 adapter\_driver 只支持一种传输方式,则直接调用该传输方式的 select() 函数来选择传输方式;如果支持多种,则 OpenOCD 使用 allowed\_transports 记录所有支持的传输(等待用户后续选择)。
- 3)在前置知识小节中我们知道,cmsis-dap 驱动支持 swd 和 jtag 两种传输,所以上图中虚线框的内容不会执行,即这里不会直接确定传输方式。
2 transport select
- 1)顾名思义,transport select 命令即为传输选择。在前置知识中我们知道,transport 目前一共有 7 种:swd、jtag、swim、hla\_swd、hla\_jtag、dapdirect\_jtag、dapdirect\_swd。
2)transport select 命令执行逻辑:
- 根据指定的传输方式不同,将进行不同的选择逻辑。不过殊途同归,最终的逻辑都是注册与指定传输方式相关的命令。
- 2)transport 相关的命令见官方文档:https://openocd.org/doc-release/html/Debug-Adapter-Configurat...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。