1. 准备工作:认识你的工具和材料
第一次接触STM32MP135开发板时,我完全被各种专业术语搞晕了。经过几次实战后才发现,只要理清几个关键点,烧录系统镜像其实比想象中简单得多。首先你需要确认手头有以下几样东西:
- 硬件部分:STM32MP135开发板(带eMMC存储)、USB Type-C数据线(注意必须是支持数据传输的,不是所有Type-C线都能用)、一台Windows/Linux电脑
- 软件工具:STM32CubeProgrammer(建议用最新版,我实测2.12.0版本最稳定)
- 系统镜像文件:包括TF-A(Trusted Firmware-A)、OP-TEE(安全执行环境)和U-Boot(引导加载程序)的编译输出文件
特别提醒新手朋友:开发板上的拨码开关非常重要!烧录时需要设置为"000"模式(全部拨到0位置),这个细节很多教程都没强调,我第一次就栽在这里,折腾了半天才发现问题。
2. 文件准备:别漏掉关键组件
编译好的系统文件通常存放在FIP_artifacts文件夹内,这里我整理了一份完整的文件清单和说明:
| 文件路径 | 作用说明 | 是否必须 |
|---|---|---|
| arm-trusted-firmware/tf-a-stm32mp135-atk-usb.stm32 | USB模式下的初始引导程序 | 是 |
| fip/fip-stm32mp135-atk-optee.bin | 包含TF-A、OP-TEE和U-Boot的FIP包 | 是 |
| arm-trusted-firmware/tf-a-stm32mp135-atk-emmc.stm32 | eMMC模式下的引导程序 | 是 |
| arm-trusted-firmware/metadata.bin | 元数据文件 | 是 |
实际项目中我发现一个常见问题:有些开发者会漏掉metadata.bin文件,导致烧录后系统无法正常启动。这个文件虽然小,但作用关键,它包含了eMMC分区的布局信息。
3. 编写TSV烧录脚本:细节决定成败
创建stm32mp135-atk-emmc-optee.tsv文件时,我踩过不少坑。这个脚本本质上是一个制表符分隔的文本文件,但有几个细节必须注意:
- 必须使用TAB键而不是空格进行分隔(这个坑我踩过三次!)
- 文件路径是相对于FIP_artifacts目录的
- 每个字段的含义要理解清楚
这是我验证过可用的脚本内容:
#Opt Id Name Type IP Offset Binary - 0x01 fsbl1-boot Binary none 0x0 arm-trusted-firmware/tf-a-stm32mp135-atk-usb.stm32 - 0x03 fip-boot FIP none 0x0 fip/fip-stm32mp135-atk-optee.bin P 0x04 fsbl1 Binary mmc1 boot1 arm-trusted-firmware/tf-a-stm32mp135-atk-emmc.stm32 P 0x05 fsbl2 Binary mmc1 boot2 arm-trusted-firmware/tf-a-stm32mp135-atk-emmc.stm32 P 0x06 metadata1 Binary mmc1 0x00080000 arm-trusted-firmware/metadata.bin P 0x07 metadata2 Binary mmc1 0x00100000 arm-trusted-firmware/metadata.bin P 0x08 fip-a FIP mmc1 0x00180000 fip/fip-stm32mp135-atk-optee.bin PED 0x09 fip-b FIP mmc1 0x00580000 none PED 0x0A u-boot-env Binary mmc1 0x00980000 none新手最容易犯的错误是在文本编辑器中不小心把TAB替换成了空格。建议使用Notepad++或VS Code这类专业编辑器,在状态栏可以看到空白字符的显示。
4. 实战烧录:一步步带你操作
现在来到最关键的烧录环节,跟着我的步骤走,保证不迷路:
硬件连接:
- 确保开发板断电
- 拨码开关设置为"000"(全部拨到0位置)
- 用USB线连接开发板的USB Type-C接口和电脑
软件操作:
- 打开STM32CubeProgrammer
- 点击左上角的"+"按钮,选择你创建的TSV脚本文件
- 点击"Browse"按钮,选择FIP_artifacts目录作为工作目录
- 按下开发板上的复位按钮(这一步很多人会忘!)
开始烧录:
- 点击"Download"按钮开始烧录
- 观察软件界面和开发板上的LED指示灯:
- 红色LED常亮表示供电正常
- 绿色LED闪烁表示正在烧录
- 蓝色LED常亮表示烧录完成
烧录过程中我建议同时打开串口终端(波特率115200),可以看到详细的烧录日志。正常情况应该会看到类似这样的输出:
[INFO] TF-A v2.6-stm32mp1-r2.1 [INFO] OP-TEE version: 3.18.0 [INFO] U-Boot 2021.10-stm32mp-r2.1如果遇到USB初始化失败的问题(就像原始文章中提到的),别慌。我实测发现这是正常现象,系统会尝试多次初始化,最终能成功就行。
5. 验证与排错:确保系统正常运行
烧录完成后,需要验证系统是否真的可以正常工作:
切换启动模式:
- 断电后,将拨码开关改为"010"(从eMMC启动)
- 重新上电
观察启动日志: 通过串口终端应该能看到完整的启动流程,包括:
- TF-A初始化信息
- OP-TEE安全环境加载
- U-Boot启动过程
- 最后进入U-Boot命令行或直接启动内核(取决于你的配置)
常见问题排查:
- 问题1:烧录过程中断
- 检查USB线是否接触不良
- 尝试更换USB端口(建议使用主板原生USB接口)
- 问题2:烧录完成后无法启动
- 确认拨码开关设置正确
- 检查TSV脚本中的路径是否正确
- 验证metadata.bin文件是否完整
- 问题3:USB初始化警告
- 这是已知现象,不影响正常使用
- 可以尝试更新TF-A版本
- 问题1:烧录过程中断
我在实际项目中遇到过最棘手的问题是烧录后eMMC无法识别,后来发现是metadata.bin文件损坏导致的。建议每次编译后都校验下这个文件的MD5值是否一致。
6. 进阶技巧:提升烧录效率
经过多次实践,我总结出几个提升效率的小技巧:
- 批量烧录脚本: 对于需要烧录多块开发板的情况,可以使用STM32CubeProgrammer的命令行模式:
STM32_Programmer_CLI -c port=USB1 -w stm32mp135-atk-emmc-optee.tsv -d FIP_artifacts- 校验烧录结果: 烧录完成后可以读取eMMC内容进行校验:
STM32_Programmer_CLI -c port=USB1 -r 0 0x200000 verify.bin- 快速恢复出厂设置: 创建一个只包含基础引导程序的精简TSV脚本,用于快速恢复系统:
#Opt Id Name Type IP Offset Binary P 0x04 fsbl1 Binary mmc1 boot1 arm-trusted-firmware/tf-a-stm32mp135-atk-emmc.stm32 P 0x05 fsbl2 Binary mmc1 boot2 arm-trusted-firmware/tf-a-stm32mp135-atk-emmc.stm32- 日志分析技巧: 在串口终端中,重点关注以下几个关键信息:
- "Boot chain validated"表示安全启动验证通过
- "DRAM init"后面的内存大小是否正确(STM32MP135应该是512MB)
- "Starting kernel..."表示系统即将进入Linux环境
7. 深度解析:理解烧录背后的原理
很多教程只教怎么做,却不解释为什么。这里我想分享一下烧录过程中的关键技术点:
TF-A的作用:
- 第一阶段引导程序,负责最基本的硬件初始化
- 建立安全环境,验证后续组件的完整性
- 我实测发现,如果TF-A版本不匹配,经常会出现莫名其妙的启动失败
FIP包的结构: FIP(Firmware Image Package)实际上是一个容器格式,内部包含:
- BL2(TF-A的第二阶段)
- BL32(OP-TEE)
- BL33(U-Boot) 使用
fiptool工具可以查看FIP包内容:
fiptool info fip-stm32mp135-atk-optee.bineMMC的分区布局: STM32MP135的eMMC有特殊的分区安排:
- boot1/boot2:存放FSBL(First Stage Boot Loader)
- 0x00080000:metadata1
- 0x00180000:FIP镜像 这种布局是为了支持A/B系统更新和回滚机制
USB烧录模式的工作原理: 当拨码开关设置为"000"时,芯片内部的ROM代码会:
- 检测USB连接
- 进入DFU(Device Firmware Upgrade)模式
- 等待主机发送烧录指令 这个过程完全不需要任何预先烧录的程序,是芯片出厂时就固化的功能
理解这些原理后,遇到问题时就能更快定位原因。比如我曾经遇到烧录到一半失败的情况,通过分析发现是USB供电不足导致的,后来改用带外接电源的USB Hub就解决了。