1
头图

前言

  • 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)引脚图:
  • image.png
  • 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)的地址:

      • image.png
      • 由此可得,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)通用寄存器:

    • image.png

4.1 数据处理指令

  • 1)数据传输指令
助记符操作数操作含义影响标志位测试
MOV{S}Rd, Rm传送 R~d~ 数据到 R~m~N,Zmovs r0, #0x1
movs R1,R0
mov R1,R0
MVN{S}Rd, RmR~m~ 位取反后,传送到 R~d~N,Zmvns r7, r6
MRS(略)
MSR(略)
  • 2)算术运算指令
助记符操作数操作含义影响标志位测试
ADD{S}{Rd,} Rn, <Rm\#imm>N,Z,C,Vadd 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,Vsubs r2, #1
subs r2, r3
subs r2, r2, #1
subs r2, r2, r3
SBC{S}{Rd,} Rn, Rm带符号减N,Z,C,V
RSB{S}{Rd,} Rn, #0逆向减法N,Z,C,V
MULSRd, Rn, Rm乘法N,Z
  • 3)逻辑运算指令

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

    助记符操作数操作含义影响标志位测试
    ASRS{Rd,} Rm, <Rs\#imm>算术右移N,Z,Casrs 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,Crors r2, r3
    rors r2, r2, r3
  • 5)比较与测试指令

    助记符操作数操作含义影响标志位测试
    CMPRn, <Rm\#imm>比较N,Z,C,Vcmp r2, #1
    cmp r2, r3
    CMNRn, Rm比较负值N,Z,C,V
    TST{S}Rn, Rm逻辑与测试N,Ztst r2, r3
    tsts r2, r3
  • 6)位域操作指令(无)
  • 7)跳转指令

    助记符操作数操作含义影响标志位测试
    B{cc}label跳转{有条件}跳转,
    BLlabel带链接的分支跳转跳转,且保存 PC 到 R14 中。
    BLXRm带链接的间接跳转跳转,并将处理器的工作状态在 ARM 状态和 Thumb 状态之前切换,且保存 PC 到 R14 中。
    BXRm间接跳转跳转,并将处理器的工作状态在 ARM 状态和 Thumb 状态之前切换。
    BEQRm间接跳转
    BNERm间接跳转

4.2 存储器访问指令

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

    助记符操作数操作含义影响标志位测试
    ADRRd, label将基于PC相对偏移的地址读到寄存器
    LDRRt, label从基于PC相对偏移地址上加载寄存器
    LDRRt, [Rn, <Rm\#imm>]以字加载寄存器
    LDRBRt, [Rn, <Rm\#imm>]以字节加载寄存器
    LDRHRt, [Rn, <Rm\#imm>]以半字加载寄存器
    LDRSBRt, [Rn, <Rm\#imm>]以有符号字节加载寄存器
    LDRSHRt, [Rn, <Rm\#imm>]以有符号半字加载寄存器
    STRRt, [Rn, <Rm\#imm>]将寄存器作为字来存储
    STRBRt, [Rn, <Rm\#imm>]将寄存器作为字节来存储
    STRHRt, [Rn, <Rm\#imm>]将寄存器作为半字来存储
  • 2)批量加载/存储数据指令

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

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

4.3 其它指令

助记符操作数操作含义影响标志位测试
BKPT#imm断点
NOP空操作
REVRd, Rm按字节反转
REV16Rd, Rm按半字反转
REVSHRd, 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:项目源码


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

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