头图

前言

  • 1)上一节我们学习了 adapter 与 transport 命令,这一节我们接着学习配置文件中的其它命令。本文主要是对配置文件中用到的命令(如下图)进行解析,以在命令行运行如下命令的结果为准:

    openocd -d3 -f board/airm2m_air001.cfg
    -d3 也作 --debug-level=3。即指定输出日志级别。
    -f  也作 --file。这里指定开发板为合宙 air001 芯片。
  • 2)这一节主要是学习 air001.cfg 文件的内容。这里简单提一下加载的两个文件:swj-dp.tcl 和 mem_helper.tcl。

    • swj-dp.tcl 文件首先执行了 transport select 命令(这个已经在 cmsis-dap.cfg 中执行过,所以无影响)。然后定义了 swj_memdap 调用过程。
    • mem_helper.tcl 文件则定义了操作 memory 的多个调用过程:

      • mrw/mrh/mrb 分别是 memory read word/halfword/byte,读取 memory。
      • mmw 则是 memory modify word,修改 memory。
  • 3)参考链接:

1 swj\_newdap

  • 1)完整的 swj_newdap 命令如下:

    swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
    # 替换掉变量后为:
    swj_newdap air001     cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x2ba01477
  • 2)其中使用的 swj_newdap 命令是一个定义在 /tcl/target/swj-dp.tcl 文件中的 proc 可调用过程,其实现为:

    # /tcl/target/swj-dp.tcl
    proc swj_newdap {chip tag args} {
     if [using_jtag] {
         eval jtag newtap $chip $tag $args
     } elseif [using_swd] {
         eval swd newdap $chip $tag $args
     } else {
         echo "Error: transport '[ transport select ]' not supported by swj_newdap"
         shutdown
     }
    }
    
    # /src/target/startup.tcl
    proc using_jtag {} {
        set _TRANSPORT [ transport select ]
        expr { [ string first "jtag" $_TRANSPORT ] != -1 }
    }
    • (1)transport select 命令当未指定传输方式时,OpenOCD 会在自动选择一种传输方式的同时,并通过 Jim_SetResultString() 函数会将当前选择的传输方式作为结果返回。
  • 3)创建名为 air001.cpu 的 Tap 过程如下(尽管该命令名叫 swj_newdap,实际上却是创建的 Tap):

    • 最终的结果是创建了 struct jtag_tap 对象,并追加到名为 __jtag_all_taps 的 Tap 链表中。

2 dap create

  • 1)真正的创建 dap 过程如下:

  • 2)dap create 命令:

    • 首先通过 dap_name 指定待创建的 dap 名称;
    • 其次通过 -chain-position tap_name 选项将上一小节中创建的 Tap 赋值给该 dap。
    • 然后验证 dap 的合法性
    • 最后会将 dap 的子命令复制给新创建的 dap(这里为 air001.dap) 一份,因此你既可以使用如 dap info 的命令,也可以使用 air001.dap info 命令。
  • 3)最终的结果是创建 struct arm_dap_object 对象,并追加到名为 all_dap 的 dap 链表中。

3 target create

  • 1)创建 target。

    target create <name> <target_type> [<target_options> ...]
    • (1)target\_type:可取 arm7tdmi、cortex\_m、arm11、esp32、stm8、riscv 等
    • (2)target\_options 可取:这些选项也可以后续通过 \<target\_name> configure 命令设置

      -type                   -endian    
      -event                  -coreid    
      -work-area-virt         -chain-position   
      -work-area-phys         -dbgbase      
      -work-area-size         -rtos         
      -work-area-backup       -defer-examine    
      -gdb-port               -gdb-max-connections                
  • 2)执行逻辑:

    • 通过给定的 target_type 找到对应的 target 类型,这里为 cortexm_target
    • 通过 target_configure() 函数处理该命令指定的选项
    • 注册 target_type 的内置命令
    • 重写并注册 air001.cpu 命令

4 <target_name> configure

  • 1)创建完名为 air001.cpu 的 target 后,还需要进行配置:

    target_name configure [options]
    • (1)target\_name:一般可以通过 target create 命令创建
    • (2)options:

      -type             :一般指 MCU 架构,如 arm7tdmi、arm9tdmi、cortexm、 riscv 等
      -event            
      -work-area-virt   
      -work-area-phys   :工作空间的物理起始地址
      -work-area-size   :工作空间的大小
      -work-area-backup :工作空间是否备份 
      -endian           :大小端
      -coreid           
      -chain-position   
      -dbgbase          
      -rtos             
      -defer-examine    
      -gdb-port         
      -gdb-max-connections
  • 2)target 配置逻辑:

    • 这里有一个疑问,如果使用 -chain-position 选项指定 air001.dap,则启动时报错;可如果使用要求的 -dap 选项,target_configure() 函数又不支持该选项。

5 flash bank

  • 1)flash bank 一般用来声明芯片的 bank。

    flash bank <name> <driver> <base> <size> <chip_width> <bus_width> <target>
    
    参数:
    - name:bank name,一般可以自定义为 “芯片.flash”
    - driver:driver name,声明在 /src/flash/nor/drivers.c 文件中的,struct flash_driver 类型的芯片驱动。用户需要实现其中的读、写、擦除、探测等方法。
    - base:base address,芯片 flash 的起始地址
    - size:size bytes,芯片 flash 的大小。如果可以从芯片的某个寄存器中读取,建议在 flash_driver 中实现,则这里默认写 0 即可;否则需要填写芯片的准确大小,单位为:字节。
    - chip\_width:默认为 0
    - bus\_width:默认为 0
    - target:通过 target create 命令创建的目标名称
  • 2)flash bank 执行逻辑:

    • 根据给定的 target 名称找到通过 target create 命令创建的 target
    • 根据给定的 flash_driver 名称找到用户编写的 flash 驱动,并注册该驱动中的相关命令
    • 创建 flash_bank 对象,并为其 name、target、driver 等属性赋值
    • 调用 flash_driver 的 flash_bank_command() 函数指针
    • 最后将该 flash_bank 对象添加到全局 flash_banks 链表中

总结

  • 1)至此,我们基本掌握了配置文件中的相关命令,其实主要是创建了几个对象:

    对象类型对象名称联系
    struct adapter_drivercmsis-dap
    st-link
    jlink
    ulink
    struct transportswd/jtag
    dapdirect_swd/dapdirect_jtag
    hla_swd/hla_jtag
    swim
    adapter_driver->transports
    struct jtag_tapair001.cpu——
    struct arm_dap_objectair001.dapdap->dap.tap = air001.cpu
    struct targetair001.cputarget->tap = air001.cpu(-dap 选项,存疑)

送南阳马生序
7 声望1 粉丝

余之业有不精、德有不成,非天质之卑,则心不若他之专耳,岂他人之过哉!