OpenOCD 添加 Air001

前言

  • 1)AIR001 简介:

    • (1)采用 PY32F003 的 TSSOP20 封装的 MCU

    • (2)采用 Cortex-M0+ 内核

    • (3)内置 32KB 的 Flash、4KB 的 RAM

    • (4)芯片集成多路 USART、IIC、SPI 等通讯外设

    • (5)5 个 16 位定时器、1 路 ADC、2 路比较器。

    • (6)最重要的是只要 7 毛多一片。

  • 2)SWD 下载接口:

    • SWDIO:PA13
    • SWCLK:PA14
  • 3)引脚图:

  • 4)本文介绍了两种烧录算法来实现 OpenOCD 对 Air001 芯片的支持。

1 烧录算法——寄存器

  • 1)所谓寄存器烧录,即是使用 OpenOCD 通过 MEM-AHP 控制 FLASH 所在的 AHB 总线,进而控制 FLASH 读写相关寄存器来进行烧录。

  • 2)优点就是实现比较简单,但一个 32KB 的 image 烧录用了 90 多秒,呵呵。该方式可以用来熟悉 OpenOCD 代码,以及在不了解 ARM 汇编指令下使用。当对 OpenOCD 代码以及汇编指令有一定了解后,就可以实现同/异步烧录算法了。

1.1 air001.cfg 文件说明

  • 1)在 /tcl/target 目录下,添加 air001.cfg 文件。

  • 2)因为 AIR001 采用 Cortex-M0+ 内核,所以这里复制 tcl/target/stm32l0.cfg 一份,并重命名为 air001.cfg

  • 3)修改:

    # 第 14 行,修改芯片名称。
    # set _CHIPNAME stm32l0
    set _CHIPNAME air001
    
    # 第 38 行,修改芯片 ID。(可能需要等首次下载时获取到)
    # set _CPUTAPID 0x0bc11477
    set _CPUTAPID 0x0bc11477
    
    # 第 51 行,设置 FLASH 大小。air001 芯片只有 32KB 大小,即 0x00008000
    # flash bank $_FLASHNAME stm32lx 0x08000000 0 0 0 $_TARGETNAME
    flash bank $_FLASHNAME air001 0x00008000 0 0 0 $_TARGETNAME
    
    # 有一个 stm32l0_enable_HSI16() 的函数,不知道干嘛的,删掉
    
    # 最下边有一个配置 DEBUG 寄存器的功能,这个就需要根据芯片的寄存器手册来进行修改了
    $_TARGETNAME configure -event examine-end {
        # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
        mmw 0x40015804 0x00000002 0
    
        # Stop watchdog counters during halt
        # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP
        mmw 0x40015808 0x00001800 0
    }
    
  • 4)关于修改 air001.cfg 文件最后的 DBGMCU_CR 配置:

    • (1)DBGMCU_CR 寄存器(地址偏移 0x04)的地址:
      • 由此可得,DBGMCU_CR = 0x4001 5804

    • (2)air001 芯片只有 DEBUG_CR 的 DBG_STOP(位于 bit1)
  • 5)关于修改 air001.cfg 文件最后的 DBGMCU_APB1_FZ 配置:

    • (1)DBGMCU_APB1_FZ 寄存器偏移地址为 0x08,DBG_IWDG_STOP 和 DBG_WWDG_STOP 分别位于其 bit12 和 bit11 位。

1.2 air001.c 文件说明

  • 1)在 /src/flash/nor 目录下,添加 air001.c 文件。用于告知 openocd 芯片的 flash 烧录流程。

  • 2)air001.c 文件中的宏定义、函数等均围绕以下内容来建立:

    const struct flash_driver air001_flash = {
            .name = "air001",
            .commands = air001_command_handlers,
            .flash_bank_command = air001_flash_bank_command,
            .erase = air001_erase,
            .write = air001_write,
            .read = default_flash_read,
            .probe = air001_probe,
            .auto_probe = air001_auto_probe,
            .erase_check = default_flash_blank_check,
            .protect_check = air001_protect_check,
            .info = air001_get_info,
            .free_driver_priv = default_flash_free_driver_priv,
    };
    
  • 3)接下来,按照 air001_flash 结构中定义的函数顺序,依次实现

1.3 drivers.c 文件说明

  • 1)drivers.c 文件位于 /src/flash/nor 目录下,该文件主要用于根据驱动名称查找驱动。 这里根据 1.2 中的驱动名称添加一下就可以了:
    ......
    extern const struct flash_driver air001_flash;
    ......
    
    static const struct flash_driver * const flash_drivers[] = {
            ......
            &air001_flash,
            ......
    

1.4 Makefile.am 文件说明

  • 1)这里的 Makefile.am 文件位于 /src/flash/nor 目录下,指明了该目录下源文件的编译规则。因此这里需要修改让 openocd 编译时引用到上述新增的文件。
    ......
    NOR_DRIVERS = \
        %D%/air001.c \
    ......
    

2 烧录算法——异步烧录

2.1 异步烧录算法

  • 1)烧录程序:主要就是在 RAM 中分配两块工作空间

    • 一块用来运行 air001.inc 文件内的汇编代码(该代码实现 image 从 RAM 到 FLASH 的搬运工作)
    • 一块尽可能大,用来作为一个循环的 FIFO,可以在 OpenOCD 将 image 写进来的同时,AIR001 通过上述的汇编代码读取数据并写入 FLASH。
  • 参考:https://zhuanlan.zhihu.com/p/593389551

    • 大佬这篇文章写的非常非常好,清晰明了地说明异常烧录的原理。

2.2 关于汇编代码

  • 1)汇编代码位于 /contrib/loaders/flash/airm2m/air001.inc 文件中。

  • 2)这里可以参考 stm32f1x.S 文件,不同点在于:

    • (1)stm32f1x.s 中,每次只能写入半字(2 个字节)
    • (2)air001 芯片需要在每 31 个字写入后,将 FLASH_CR->PGSTRT(bit19) 置 1,最后再写入第 32 个字。
  • 3)汇编文件编写完成后,在 air001.S 文件所在目录直接 make,即可生成 air001.inc 文件。前提是需要仿照 /contrib/loaders/flash/stm32/Makefile创建自已的 Makefile

3 编译与测试

3.1 编译 OpenOCD

# 启动项测试
./bootstrap

# 创建编译目录
mkdir openocd-clion-build
cd openocd-clion-build

# 配置
../configure --enable-ftdi

# 编译
make -j4 && make install

3.2 测试日志

  • 1)首先在 MSYS2 中输入:openocd -d3 -f interface/cmsis-dap.cfg -f target/air001.cfg 以启动 OpenOCD。

  • 2)通过 telnet 127.0.0.1 4444 连接到 OpenOCD 服务端:

    $ telnet 127.0.0.1 4444
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    Open On-Chip Debugger
    > halt
    [air001.cpu] halted due to debug-request, current mode: Thread
    xPSR: 0x21000000 pc: 0x080071f8 msp: 0x20000ff0
    > flash write_image erase "D:\\_Workspace\\11_MCU\\07_LuatOS\\Air001\\Air001_001_GCCTemplate\\cmake-build-debug\\Air001_000_GCCTemplate.hex"
    device id = 0x60001000
    AIR001 flash size is 32kb, base address is 0x08000000
    auto erase enabled
    wrote 32768 bytes from file D:\_Workspace\11_MCU\07_LuatOS\Air001\Air001_001_GCCTemplate\cmake-build-debug\Air001_000_GCCTemplate.hex in 3.767980s (8.493 KiB/s)
    
    > reset
    > halt
    [air001.cpu] halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0x080071f4 msp: 0x20000ff0
    > flash write_image erase "D:\\_Workspace\\11_MCU\\07_LuatOS\\Air001\\Air001_001_GCCTemplate\\cmake-build-debug\\Air001_000_GCCTemplate.hex"
    auto erase enabled
    wrote 16384 bytes from file D:\_Workspace\11_MCU\07_LuatOS\Air001\Air001_001_GCCTemplate\cmake-build-debug\Air001_000_GCCTemplate.hex in 2.048985s (7.809 KiB/s)
    
    > reset
    > shutdown
    shutdown command invoked
    Connection closed by foreign host.
    
    • 可以发现,32 KB 写入只需要 3.767980s (8.493 KiB/s);16 KB 写入则需要 2.048985s (7.809 KiB/s)。

4 附录1:ARM Cortex-M0+ 汇编指令

  • 1)以下测试结果基于 arm-none-eabi-gcc 和 Cortex-M0+ 平台。根据《STM32F0系列Cortex-M0原理与实践》、《嵌入式系统设计基础及应用——基于ARM Cortex-M4微处理器》整理。

  • 2)ARM Cortex-M0+ Thumb 指令集只能使用前8个(R0-R7)寄存器。

  • 3)N、Z、C、V 标志位是什么

    • Negative:表示结果为负数时 N 标志位置 1。如 cmp 指令相减时小于 0
    • Zero:表示结果为零时 Z 标志位置 1。如 cmp 指令比较两个数相等时,可通过 beq 跳转;比较两个数不相等时,可通过 bne 跳转。
    • Carry:表示加减法运算导致最高位有进位或借位时 C 标志位置 1。而 bcc 指令在 C = 0 时跳转
    • oVerflow:表示有符号数运算时超出表示范围则 V 标志位置 1。
  • 4)通用寄存器:

4.1 数据处理指令

  • 1)数据传输指令

    助记符 操作数 操作含义 影响标志位 测试
    MOV Rd, Rm 传送 Rd 数据到 Rm N,Z movs r0, #0x1
    movs R1,R0
    mov R1,R0
    MVN Rd, Rm Rm 位取反后,传送到 Rd N,Z mvns r7, r6
    MRS(略)
    MSR(略)
  • 2)算术运算指令

    助记符 操作数 操作含义 影响标志位 测试
    ADD {Rd,} Rn, <Rm|#imm> N,Z,C,V add r2, r3
    add r2, r2, r3
    adds r2, #1
    adds r2, r3
    adds r2, r2, #1
    adds r2, r2, r3
    ADCS {Rd,} Rn, Rm 带进位加 N,Z,C,V
    SUBS {Rd,} Rn, <Rm|#imm> 减法 N,Z,C,V subs r2, #1
    subs r2, r3
    subs r2, r2, #1
    subs r2, r2, r3
    SBC {Rd,} Rn, Rm 带符号减 N,Z,C,V
    RSB {Rd,} Rn, #0 逆向减法 N,Z,C,V
    MULS Rd, Rn, Rm 乘法 N,Z
  • 3)逻辑运算指令

    助记符 操作数 操作含义 影响标志位 测试
    ANDS {Rd,} Rn, Rm 位与计算 N,Z ands r2, r3
    ands r2, r2, r3
    ORRS {Rd,} Rn, Rm 逻辑或 N,Z orrs r2, r3
    orrs r2, r2, r3
    EORS {Rd,} Rn, Rm 异或 N,Z eors r2, r3
    eors r2, r2, r3
    BICS {Rd,} Rn, Rm 位清除 N,Z bics r2, r3
    bics r2, r2, r3
  • 4)移位指令

    助记符 操作数 操作含义 影响标志位 测试
    ASRS {Rd,} Rm, <Rs|#imm> 算术右移 N,Z,C asrs r2, #1
    asrs r2, r3
    asrs r2, r2, #1
    asrs r2, r2, r3
    LSLS {Rd,} Rn, <Rs|#imm> 逻辑左移 N,Z,C 同上
    LSRS {Rd,} Rn, <Rs|#imm> 逻辑右移 N,Z,C 同上
    RORS {Rd,} Rn, Rs 循环右移 N,Z,C rors r2, r3
    rors r2, r2, r3
  • 5)比较与测试指令

    助记符 操作数 操作含义 影响标志位 测试
    CMP Rn, <Rm|#imm> 比较 N,Z,C,V cmp r2, #1
    cmp r2, r3
    CMN Rn, Rm 比较负值 N,Z,C,V
    TST Rn, Rm 逻辑与测试 N,Z tst r2, r3
    tsts r2, r3
  • 6)位域操作指令(无)

  • 7)跳转指令

    助记符 操作数 操作含义 影响标志位 测试
    B label 跳转 跳转,
    BL label 带链接的分支跳转 跳转,且保存 PC 到 R14 中。
    BLX Rm 带链接的间接跳转 跳转,并将处理器的工作状态在 ARM 状态和 Thumb 状态之前切换,且保存 PC 到 R14 中。
    BX Rm 间接跳转 跳转,并将处理器的工作状态在 ARM 状态和 Thumb 状态之前切换。
    BEQ Rm 间接跳转
    BNE Rm 间接跳转

4.2 存储器访问指令

  • 1)存储器访问常用指令

    助记符 操作数 操作含义 影响标志位 测试
    ADR Rd, label 将基于PC相对偏移的地址读到寄存器
    LDR Rt, label 从基于PC相对偏移地址上加载寄存器
    LDR Rt, [Rn, <Rm|#imm>] 以字加载寄存器
    LDRB Rt, [Rn, <Rm|#imm>] 以字节加载寄存器
    LDRH Rt, [Rn, <Rm|#imm>] 以半字加载寄存器
    LDRSB Rt, [Rn, <Rm|#imm>] 以有符号字节加载寄存器
    LDRSH Rt, [Rn, <Rm|#imm>] 以有符号半字加载寄存器
    STR Rt, [Rn, <Rm|#imm>] 将寄存器作为字来存储
    STRB Rt, [Rn, <Rm|#imm>] 将寄存器作为字节来存储
    STRH Rt, [Rn, <Rm|#imm>] 将寄存器作为半字来存储
  • 2)批量加载/存储数据指令

    助记符 操作数 操作含义 影响标志位 测试
    LDM Rn{!}, reglist 加载多个寄存器,访问之后会递增地址
    STM Rn!, reglist 批量存储寄存器, Rn递减
  • 3)进栈/出栈指令

    助记符 操作数 操作含义 影响标志位 测试
    POP reglist 寄存器出栈
    PUSH reglist 寄存器压栈

4.3 其它指令

  • 1)
    助记符 操作数 操作含义 影响标志位 测试
    BKPT #imm 断点
    NOP 空操作
    REV Rd, Rm 按字节反转
    REV16 Rd, Rm 按半字反转
    REVSH Rd, Rm 按有符号半字反转
    WFE 等待事件
    WFI 等待中断

5 附录2:OpenOCD 命令

  • 1)probe 以及 info 命令:获取芯片的大致信息
> halt
[air001.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x08000418 msp: 0x20000ff0
> flash probe 0
device id = 0x60001000
AIR001 flash size is 32kb, base address is 0x08000000
flash 'air001' found at 0x08000000

> flash info 0
#0 : air001 at 0x08000000, size 0x00008000, buswidth 0, chipwidth 0
        #  0: 0x00000000 (0x1000 4kB) protected
        #  1: 0x00001000 (0x1000 4kB) protected
        #  2: 0x00002000 (0x1000 4kB) protected
        #  3: 0x00003000 (0x1000 4kB) protected
        #  4: 0x00004000 (0x1000 4kB) protected
        #  5: 0x00005000 (0x1000 4kB) protected
        #  6: 0x00006000 (0x1000 4kB) protected
        #  7: 0x00007000 (0x1000 4kB) protected
AIR001 (Cat.1 - Low/Medium Density) - Rev: A

  • 2)除了可以通过 flash write_image erase {"/path/to/image.hex" | "/path/to/image.bin" address} 命令可以烧录镜像外,我们还可以使用以下命令来测试自已的驱动是否正常:
> flash erase_check 0
successfully checked erase state
        #  0: 0x00000000 (0x1000 4kB) not erased

> flash fillw 0x08003000 0xcafebaba 32
wrote 128 bytes to 0x08003000 in 0.602882s (0.207 KiB/s)

> flash mdw 0x08003000 48
0x08003000: cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba
0x08003020: cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba
0x08003040: cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba
0x08003060: cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba cafebaba
0x08003080: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x080030a0: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff

> flash erase_sector 0 3 4
erased sectors 3 through 4 on flash bank 0 in 0.199937s

> flash mdw 0x08003000 48
0x08003000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x08003020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x08003040: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x08003060: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x08003080: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
0x080030a0: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff

  • 实际测试过程中,fillw 偶尔会出现失败的情况,未找到原因。

6 附录3:项目源码

posted @ 2024-01-19 17:09  送南阳马生序  阅读(21)  评论(0编辑  收藏  举报