进阶:Flash 编程与批量烧录脚本

知识库
知识库文档
/tech-stacks/openocd/examples/进阶:Flash 编程与批量烧录脚本.md

文档

OpenOCD 进阶:Flash 编程与批量烧录脚本

目标

掌握 OpenOCD 的 Flash 分区操作、选项字节编程、多设备并行烧录和自动化脚本。

一、Flash 分区擦写

读取 Flash 内容

# read_flash.tcl
set FLASH_START 0x08000000
set FLASH_SIZE  0x00100000   ; # 1MB (STM32F407)

halt
flash read_bank 0 flash_dump.bin 0 $FLASH_SIZE
puts "Flash 已导出到 flash_dump.bin ($FLASH_SIZE bytes)"
resume
exit
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -f read_flash.tcl

解锁/锁定 Flash

# unlock.tcl
halt
stm32f4x unlock 0        ; # 解锁 bank 0
puts "Flash 解锁成功"
resume
exit

选项字节编程(读写保护)

# 设置读保护 Level 1
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \
    -c "init" \
    -c "halt" \
    -c "stm32f4x lock 0" \
    -c "reset run" \
    -c "exit"

# 查看选项字节
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \
    -c "init" \
    -c "halt" \
    -c "stm32f4x options_read 0" \
    -c "exit"

二、批量烧录自动化脚本

#!/bin/bash
# batch_flash.sh — 批量烧录多板

INTERFACE="interface/stlink.cfg"
TARGET="target/stm32f4x.cfg"
FIRMWARE="build/firmware.hex"
SERIAL_FILE="devices.txt"        # 每行一个 ST-Link 序列号
LOG_DIR="logs/$(date +%Y%m%d_%H%M%S)"

mkdir -p "$LOG_DIR"

flash_device() {
    local serial=$1
    local log="$LOG_DIR/${serial}.log"

    echo "────────────────────────────"
    echo "烧录设备: $serial"
    echo "────────────────────────────"

    openocd \
        -f "$INTERFACE" \
        -c "hla_serial $serial" \
        -f "$TARGET" \
        -c "init" \
        -c "halt" \
        -c "flash write_image erase $FIRMWARE" \
        -c "verify_image $FIRMWARE" \
        -c "reset run" \
        -c "exit" \
        &;> "$log"

    if [ $? -eq 0 ]; then
        echo "✅ $serial — 成功"
    else
        echo "❌ $serial — 失败!查看日志: $log"
        return 1
    fi
}

# 遍历设备
TOTAL=0
SUCCESS=0

while IFS= read -r serial || [ -n "$serial" ]; do
    [ -z "$serial" ] &;& continue
    TOTAL=$((TOTAL + 1))
    if flash_device "$serial"; then
        SUCCESS=$((SUCCESS + 1))
    fi
done <; "$SERIAL_FILE"

echo ""
echo "===================================="
echo "烧录完成: $SUCCESS / $TOTAL"
echo "日志目录: $LOG_DIR"
echo "===================================="

三、结合 CMake 构建后自动烧录

# CMakeLists.txt 末尾添加烧录目标
add_custom_target(flash
    COMMAND openocd
        -f ${OPENOCD_SCRIPTS}/interface/stlink.cfg
        -f ${OPENOCD_SCRIPTS}/target/stm32f4x.cfg
        -c "program $<TARGET_FILE:${PROJECT_NAME}> verify reset exit"
    DEPENDS ${PROJECT_NAME}
    COMMENT "Flashing firmware..."
)

# 使用
# cmake --build . --target flash

四、多核调试(CM4 + CM0 异构系统)

# STM32H745 (CM7 + CM4 双核)
openocd -f interface/stlink.cfg -f target/stm32h7x_dual_bank.cfg

# 新开 GDB 终端
arm-none-eabi-gdb cm7_firmware.elf
(gdb) target extended-remote localhost:3333    # 连接 CM7

# 另一个 GDB 终端
arm-none-eabi-gdb cm4_firmware.elf
(gdb) target extended-remote localhost:3334    # 连接 CM4

五、实用 TCL 函数库

# utils.tcl — 可复用的 OpenOCD 辅助函数
proc wait_halt {timeout_ms} {
    set start [clock milliseconds]
    while {[expr {[clock milliseconds] - $start}] < $timeout_ms} {
        if {[capture "halted"] == ""} {
            sleep 10
        } else {
            return 1
        }
    }
    error "等待暂停超时"
}

proc dump_regs {} {
    set regs {r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 sp lr pc xPSR}
    foreach r $regs {
        puts [format "%-6s: 0x%08X" $r [reg $r]]
    }
}

proc flash_erase_all {} {
    flash erase_sector 0 0 last
    puts "Flash 已全部擦除"
}

在启动时加载:

openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -f utils.tcl

关键点

  • verify_image 烧录后自动校验,确保数据完整性
  • hla_serial 用于多 ST-Link 并行烧录时区分设备
  • 选项字节操作需谨慎:错误的写保护设置可能导致芯片"变砖"
  • TCL 脚本支持条件、循环,可实现复杂自动化流程

信息

路径
/tech-stacks/openocd/examples/进阶:Flash 编程与批量烧录脚本.md
更新时间
2026/5/31