文档
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 脚本支持条件、循环,可实现复杂自动化流程