1066 字
5 分钟
pyocd调用flm格式的下载算法
pyocd 调用 FLM 格式的外部下载算法
记录如何通过 pyocd 调用 Keil 使用的 .FLM 格式外部下载算法,将程序烧录到 STM32H7 系列微控制器的 QSPI Flash 中。
Waiting for api.github.com...
项目背景
| 项目 | 内容 |
|---|---|
| 开发板 | 反客STM32H750XHB6 |
| 参考工程 | Peakors/STM32H750XBH6_Template |
| 下载算法 | FK750M6_XBH6_V0.FLM (由开发板资料提供) |
| 测试环境 | Fedora 42 (经验可跨平台通用) |

前置依赖
确保已安装以下工具链:
pyocdcmakeninja或makearm-none-eabi-gcc
编译流程
# 生成 Ninja/Make 构建文件cmake -S . -B build -G Ninja
# 执行编译cmake --build build/原理说明
通过在项目根目录创建 pyocd_user.py 脚本,可以自定义 pyOCD 的连接行为。pyOCD 在启动时会自动检测并加载该文件。
我们在脚本中定义一个 will_connect 函数,该函数会在 pyOCD 连接目标板之前被调用。通过这个函数,我们可以向 pyOCD 的内存地图中添加外部 Flash 的信息(如 QSPI Flash),并指定其使用的 .FLM 下载算法。
这种机制使得 pyOCD 能够在不修改内置目标支持的情况下,扩展对外部存储器的烧录能力。
1. 目录结构
- 将下载算法文件
FK750M6_XBH6_V0.FLM存放到项目下的.config文件夹中。 - 在项目根目录创建
pyocd_user.py文件。
2. pyocd_user.py 脚本
from pyocd.core.memory_map import FlashRegionimport logging
# --- 定义外部 QSPI Flash 的参数 ---FLM_FILE = ".config/FK750M6_XBH6_V0.FLM" # 存放下载算法的相对路径QSPI_FLASH_START = 0x90000000QSPI_FLASH_SIZE = 32 * 1024 * 1024QSPI_FLASH_BLOCKSIZE = 0x1000
def will_connect(board): """ 这是一个 pyOCD 代理函数,会在连接前被自动调用。
""" target = board.target
# 定义外部 Flash 区域 external_flash = FlashRegion( name="qspi_flash", start=QSPI_FLASH_START, length=QSPI_FLASH_SIZE, blocksize=QSPI_FLASH_BLOCKSIZE, is_boot_memory=False, flm=FLM_FILE )
# 将其添加到内存地图 target.memory_map.add_region(external_flash)
logging.info(f"用户脚本:成功添加外部 QSPI Flash 区域 '{external_flash.name}'")具体定义参考/home/hao/.local/lib/python3.13/site-packages/pyocd/core/memory_map.py(pyocd安装路径)

烧录指令
使用以下指令将编译生成的 .bin 文件烧录到 QSPI Flash 的起始地址 0x90000000。
--target stm32h750xx:指定目标芯片型号。-O connect_mode=under-reset:设置连接模式为复位下连接。./build/STM32H750XBH6_Template.bin@0x90000000:指定固件路径和烧录地址。
pyocd flash --target stm32h750xx -O connect_mode=under-reset ./build/STM32H750XBH6_Template.bin@0x90000000日志参考
1. 简洁版日志
❯ pyocd flash --target stm32h750xx -O connect_mode=under-reset ./build/STM32H750XBH6_Template.bin@0x900000000000447 I Loading /home/hao/projects/stm32_projects/STM32H750XBH6/CMake/STM32H750XBH6_Template/build/STM32H750XBH6_Template.bin at 0x90000000 [load_cmd][==================================================] 100%0002722 I Erased 65536 bytes (1 sector), programmed 65536 bytes (8 pages), skipped 0 bytes (0 pages) at 28.14 kB/s [loader]2. 详细版日志 (-v 参数)
❯ pyocd flash --target stm32h750xx -v -O connect_mode=under-reset ./build/STM32H750XBH6_Template.bin@0x900000000000346 I Target type is stm32h750xx [board]0000349 I 用户脚本:成功添加外部 QSPI Flash 区域 'qspi_flash' [pyocd_user]0000349 I Asserting reset prior to connect [coresight_target]0000352 I DP IDR = 0x6ba02477 (v2 rev6) [dap]0000366 I CR: 0x0070003f [target_STM32H750xx]0000370 I AHB-AP#0 IDR = 0x84770001 (AHB-AP var0 rev8) [discovery]0000373 I AHB-AP#1 IDR = 0x84770001 (AHB-AP var0 rev8) [discovery]0000376 I APB-AP#2 IDR = 0x54770002 (APB-AP var0 rev5) [discovery]0000379 I AHB-AP#0 Class 0x1 ROM table #0 @ 0xe00fe000 (designer=020:ST part=450) [rom_table]0000381 I [0]<e00ff000:ROM class=1 designer=43b:Arm part=4c7> [rom_table]0000381 I AHB-AP#0 Class 0x1 ROM table #1 @ 0xe00ff000 (designer=43b:Arm part=4c7) [rom_table]0000383 I [0]<e000e000:SCS v7-M class=14 designer=43b:Arm part=00c> [rom_table]0000385 I [1]<e0001000:DWT v7-M class=14 designer=43b:Arm part=002> [rom_table]0000386 I [2]<e0002000:FPB v7-M class=14 designer=43b:Arm part=00e> [rom_table]0000387 I [3]<e0000000:ITM v7-M class=14 designer=43b:Arm part=001> [rom_table]0000389 I [1]<e0041000:ETM M7 class=9 designer=43b:Arm part=975 devtype=13 archid=4a13 devid=0:0:0> [rom_table]0000391 I [2]<e0043000:CTI CS-400 class=9 designer=43b:Arm part=906 devtype=14 archid=0000 devid=40800:0:0> [rom_table]0000393 I APB-AP#2 Class 0x1 ROM table #0 @ 0xe00e0000 (designer=020:ST part=450) [rom_table]0000396 I [2]<e00e3000:SWO CS-400 class=9 designer=43b:Arm part=914 devtype=11 archid=0000 devid=ea0:0:0> [rom_table]0000398 I [3]<e00e4000:Trace Funnel CS-400 class=9 designer=43b:Arm part=908 devtype=12 archid=0000 devid=32:0:0> [rom_table]0000399 I [4]<e00e5000:TSGEN class=15 designer=43b:Arm part=101> [rom_table]0000400 I [5]<e00f0000:ROM class=1 designer=020:ST part=001> [rom_table]0000401 I APB-AP#2 Class 0x1 ROM table #1 @ 0xe00f0000 (designer=020:ST part=001) [rom_table]0000404 I [0]<e00f1000:CTI CS-400 class=9 designer=43b:Arm part=906 devtype=14 archid=0000 devid=40800:0:0> [rom_table]0000406 I [2]<e00f3000:Trace Funnel CS-400 class=9 designer=43b:Arm part=908 devtype=12 archid=0000 devid=34:0:0> [rom_table]0000408 I [3]<e00f4000:ETF class=9 designer=43b:Arm part=961 devtype=32 archid=0000 devid=380:0:0> [rom_table]0000410 I [4]<e00f5000:TPIU CS-400 class=9 designer=43b:Arm part=912 devtype=11 archid=0000 devid=a0:0:0> [rom_table]0000415 I CPU core #0: Cortex-M7 r1p1, v7.0-M architecture [cortex_m]0000415 I Extensions: [DSP, FPU, FPU_DP, FPU_V5, MPU] [cortex_m]0000415 I FPU present: FPv5-D16-M [cortex_m]0000416 I 4 hardware watchpoints [dwt]0000419 I 8 hardware breakpoints, 1 literal comparators [fpb]0000431 I Deasserting reset post connect [coresight_target]0000433 I Creating flash algo for region qspi_flash from: /home/hao/projects/stm32_projects/STM32H750XBH6/CMake/STM32H750XBH6_Template/.config/FK750M6_XBH6_V0.FLM [flm_region_builder]0000448 I Loading /home/hao/projects/stm32_projects/STM32H750XBH6/CMake/STM32H750XBH6_Template/build/STM32H750XBH6_Template.bin at 0x90000000 [load_cmd][==================================================] 100%0002723 I Erased 65536 bytes (1 sector), programmed 65536 bytes (8 pages), skipped 0 bytes (0 pages) at 28.14 kB/s [loader]实现效果
-
Bootloader 日志 (运行于片内 Flash)
- 程序启动后,首先运行片内 Flash 中的 Bootloader,通过串口打印启动日志。
- Bootloader 日志截图 (乱码系中文编码问题)

-
主程序日志 (运行于外部 QSPI Flash)
- Bootloader 跳转到 QSPI Flash 中执行主程序,主程序通过 USB 虚拟串口打印运行日志。
- USB 虚拟串口日志截图

串口波特率115200
pyocd调用flm格式的下载算法
https://hyrsoft.github.io/posts/tools/pyocd调用flm格式的下载算法/