十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32MP257F-EV1 SD卡启动失败排查:从FIP到flashlayout的实战指南

STM32MP257F-EV1 SD卡启动失败排查:从FIP到flashlayout的实战指南 如果构建产物本身没问题但板子死活不跑那大概率不是编译器的锅而是镜像没放对位置、启动链某环断掉或者板子根本没按你期望的方式去加载镜像。遇到“STM32MP257F-EV1 构建的 6.6.116 发行包无法从 SD 卡启动”这个问题我第一反应不是去怀疑内核源码而是先把“SD 卡启动”这件事本身拆开。嵌入式 Linux 开发里十次启动失败有八次出在启动链路上剩下的两次才轮到内核和根文件系统。STM32MP257F-EV1 是 ST 新一代 MP2 系列的核心板跑双核 Cortex-A35架构上跟老的 MP1 有很大区别启动流程、固件布局、烧写方式都有变化。如果你以前用的是 STM32MP157 那套经验直接套到 MP257 上大概率会踩坑。这篇内容就围绕“构建完成但 SD 卡启动失败”这个现象把整个排查链路走一遍从软件包里到底产出了哪些文件、SD 卡上应该怎么分区、U-Boot 和 FIP 到底该烧到哪个偏移到常见启动卡死位置的定位方法。适合正在做 MP2 平台 bring-up、或者刚接触 Distribution Package 构建流程的工程师参考。1. 问题定位先搞清楚“构建成功”和“能启动”之间差了几步1.1 6.6.116 发行包的产出物到底有哪些STM32MP2 系列的 Distribution Package 构建完成后生成的镜像文件远比你想象的多。在build-distro/deploy/images/stm32mp2目录下你会看到一堆名字非常接近的文件很多人就是在这里开始懵的。以stm32mp257f-ev1目标为例核心产出物包括fip-stm32mp257f-ev1.binFirmware Image Package这是整个启动链最重要的文件里面打包了 TF-A 的 BL2、BL32OP-TEE、U-Boot 本身以及 U-Boot 的设备树。MP2 系列从 SD 卡启动时BootROM 加载的就是这个 FIP。tf-a-stm32mp257f-ev1.stm32TF-A 的第一阶段镜像BL2通常也叫 FSBL。这个文件只会在某些特定启动模式下需要单独烧写SD 卡启动时它已经包含在 FIP 里了。u-boot-stm32mp257f-ev1.bin和u-boot-stm32mp257f-ev1.dtb单独拆出来的 U-Boot 二进制和设备树主要在调试时用不直接参与 SD 卡启动。st-image-weston-distro-stm32mp257f-ev1.rootfs.ext4根文件系统镜像是 Weston 图形化系统包含完整的基础用户空间。bootfs相关的st-image-bootfs-*.ext4这个分区上放的是内核镜像kernel或Image、内核设备树.dtb以及一些启动必需的配置文件。这里有个非常关键的设计差异在 MP1 时代U-Boot 是单独烧到 SD 卡某个固定偏移的内核是从 bootfs 分区直接读取的。但在 MP2 上U-Boot 被“焊”进了 FIPSD 卡上不再有独立的 U-Boot 二进制。如果你还在按 MP1 的习惯去找u-boot-sdmmc.stm32然后烧到偏移 0x8000那你烧进去的东西其实根本没被 BootROM 执行。1.2 为什么“烧写完整”仍然起不来我在排查这个问题时先按官方流程重新生成了一遍镜像然后dd到 SD 卡里插到板子上串口完全没输出。这时候第一反应是检查 FIP 的烧写位置和格式。MP2 系列的 BootROM 对 SD 卡上的 FIP 位置有严格限制。FIP 不是随便放哪都能被识别的它需要写在分区表里标记为fip的分区中或者写在特定的扇区偏移处。Distribution Package 生成的flashlayout文件通常在build-distro/deploy/images/stm32mp2/flashlayout/st-image-weston/flashlayout-st-image-weston/目录里定义了这些分区的具体偏移和大小。如果你不是用 STM32CubeProgrammer 烧写而是直接用dd手工写镜像最容易犯的错就是把 FIP 烧到了错误的位置。SD 卡上 FIP 分区如果偏移没对齐BootROM 会在加载阶段直接卡死串口连一个字符都不会输出。另外还要检查 TF-A 的日志输出阶段。MP2 的 BootROM 对启动媒体是有优先级顺序的并且这个顺序可以通过硬件拨码或 OTP fuse 调整。如果你的板子当前设置的启动源不是 SD 卡那么无论 FIP 写得多正确它都不会从 SD 卡加载任何东西。2. 构建环节的隐藏坑版本对齐比代码正确更重要2.1 Distribution Package 的版本号陷阱标题里提到了“6.6.116 distribution package”这里的 6.6.116 指的是 Linux 内核版本6.6 主线 116 个补丁。ST 的 Distribution Package 通常会把内核锁定在某个具体版本比如 v6.6.48然后用自己的内核补丁集去适配 STM32MP2 平台。如果你把这个版本号理解成“只要是 6.6.x 就能用”那后面大概率会出问题。ST 的 OpenSTLinux 内核补丁集跟上游 Linux 不是同步的。ST 会基于某个固定版本做自己的 BSPBoard Support Package适配包括 DMA 控制器、时钟树、GPU 驱动、以太网 PHY 驱动等改动。如果你用某个第三方或者自维护的内核 6.6.116 去替换 Distribution Package 默认的内核版本镜像确实能构建出来但这不意味着它能在这个板子上正常启动。2.2 设备树不匹配导致 U-Boot 阶段崩掉Distribution Package 的构建系统会自动生成一份 U-Boot 设备树和一份内核设备树它们之间是有配套关系的。U-Boot 设备树里定义了 DDR 初始化参数、电源管理 IC 的 I2C 地址、GPIO 扩展器配置等信息。如果 U-Boot 找不到对应的 PMIC或者 DDR 参数跟板载内存颗粒不匹配U-Boot 可能在 DDR 初始化阶段就卡死了。这个问题在 MP257F-EV1 上尤其隐蔽因为 EV1 板用的是 DDR4不是老的 DDR3。DDR4 的 training 流程比 DDR3 复杂得多如果 U-Boot 里内置的 DDR 配置参数和实际内存颗粒型号对不上可能表现为“有时候能起来有时候起不来”或者“复位偶尔失败”。我建议你在排查启动问题时先确认 U-Boot 阶段的ddr日志是否完整打印。实践中我的做法是# 在 U-Boot 阶段输入 # 查看 DDR 信息是否被正确识别 # 如果能够进入 U-Boot 命令行执行 # 注意DDR 配置有问题时往往执行到这里就会死机 printenv fdtfile如果实在进不了 U-Boot 命令行就把重点放到 TF-A 的日志上。TF-A 在初始化阶段会打印一些关键信息包括它从哪里加载镜像、DDR training 是否通过。这些日志对定位启动失败非常有用。3. 实战排查从“串口无输出”到找到根因的完整过程3.1 准备工作串口连接和日志抓取拿到一块启动失败的 MP257F-EV1第一步要接好串口。EV1 板上有两个重要的调试接口ST-Link 板载调试器通过 USB 线直接连接到开发板它会虚拟出一个串口通常叫ST-Link VCP同时在 STM32CubeProgrammer 中也可以把它用作烧写器。这个串口非常关键因为 BootROM、TF-A、U-Boot 的日志都会从这里输出。独立 UARTEV1 板上还有一组排针引出 UART4/8 之类的调试串口但用 ST-Link 自带的 VCP 就够了少接一堆杜邦线。连接完成后用screen、minicom或PuTTY打开串口波特率设为 1152008N1。在给板子上电之前就把串口打开这样会抓得更完整。然后准备一份“干净”的 SD 卡。注意这个“干净”指的不是格式化就完了而是指你需要用官方dd工具或者 STM32CubeProgrammer 将整个 SD 卡重新分区并写入镜像而不是在已有分区的基础上改来改去。3.2 逐层验证启动链路我的排查路线是BootROM 是否运行 - TF-A(FIP) 是否加载 - U-Boot 是否启动 - 内核是否解压 - 根文件系统是否挂载。第一层看串口有没有任何输出。如果接上串口板子上电后完全没有任何字符先检查烧写位置和启动拨码。MP2 开发板上面一般会有几个拨码开关或者跳线帽用来选择Boot Mode。EV1 板默认是从 SD 卡启动的但如果你插着 USB 线又有 EMMC或者曾经烧写过 OTP fuse启动顺序可能会变。第二层看有没有 TF-A 日志。如果能看到类似NOTICE: BL2: v2.x-stm32mp1之类的输出说明 FIP 已经被 BootROM 正确加载了。但是如果日志在DDR初始化相关的位置终止说明问题出现在 DDR training 或 PMIC 配置上。这种情况就要去核对 U-Boot 设备树里的st,mem-type参数和 PMIC 型号。第三层如果 TF-A 日志完整通过并且在最后出现了 U-Boot 的启动信息U-Boot 2023.xx-stm32mp1之类的 banner说明 FIP 里的内容没有问题。此时如果卡住不往下走大概率和 U-Boot 环境变量、bootargs、bootcmd 有关。在我遇到的案例中一个典型场景是NOTICE: BL2: v2.8-stm32mp1 NOTICE: BL2: Built : ... NOTICE: BL2: Booting BL32 ... U-Boot 2023.10-stm32mp1 ...然后 U-Boot 刷屏般打印环境变量最后停在某个mmc read或者load命令处不动说明 U-Boot 在尝试读取内核镜像时找不到文件或者压根没有匹配的文件名。3.3 根因之一FIP 分区与 flashlayout 不匹配这类问题最典型的症状就是FIP 烧了但串口一点输出都没有。原因往往出在 FIP 实际写入的位置跟 BootROM 期望的位置不一致。DFU 或 STM32CubeProgrammer 烧写时会按照flashlayout.tsv文件里的偏移写这个偏移是绝对可靠的。但如果你换用dd直接写很容易把 FIP 写到分区所在扇区的相对位置忘掉前面还有 GPT 头和保护性 MBR。拿 EV1 板来说SD 卡通常是这样排布的具体数值以你生成的flashlayout为准分区起始位置大小说明GPT 头017KB分区表fsbl117KB32KB第一份 TF-A BL2fsbl249KB32KB第二份 TF-A BL2备份fip81KB1024KBFIP 固件包bootfs1105KB64MB内核和 dtbrootfs65MB剩余根文件系统如果你用dd iffip-stm32mp257f-ev1.bin of/dev/sdX bs1M seek1相当于把 FIP 写到了 1M 偏移处。而 BootROM 期望它在 81KB 处或者它通过解析 GPT 分区来找名为fip的分区。结果就是 BootROM 读了错误区域的数据校验失败整个启动链路直接终止。正确做法是用 STM32CubeProgrammer 烧写或者严格按flashlayout.tsv里的偏移来dd。比如sudo dd iftf-a-stm32mp257f-ev1.stm32 of/dev/sdX bs1K seek17 convnotrunc sudo dd iffip-stm32mp257f-ev1.bin of/dev/sdX bs1K seek81 convnotrunc注意这里seek17和seek81的单位是 1KB因为bs1K。如果你的bs1M偏移就不是这么算了。很多人在这个单位换算上栽过跟头。3.4 根因之二bootfs 分区缺少内核或 dtb如果 FIP 加载成功了U-Boot 也启动了但在Loading kernel...之后卡住或者直接跳到Unknown command/No more devices问题就出在 bootfs 分区的内容上。MP2 的 U-Boot 启动流程通常是这样先根据fdtfile环境变量确认设备树文件名然后从 bootfs 加载Image内核镜像和对应的.dtb。如果 bootfs 里放的内核文件名和 U-Boot 期望的不一致它就会一直尝试然后超时失败。我在排查时发现一个很常见的坑Distribution Package 构建的内核文件名带了版本后缀比如Image-6.6.116而 U-Boot 启动脚本里写死的是Image。如果你手动用dd只写了 rootfs 和 bootfs 的分区但没有正确更新 bootfs 里的符号链接就会出这个问题。解决办法是检查 bootfs 分区里的文件结构确保有Image和stm32mp257f-ev1.dtb这两个标准文件名且内容是正确的版本。3.5 根因之三OTP fuse 或 PMIC 供电异常还有一个容易忽略的坑OTP fuse。MP2 芯片内部有一次性可编程存储器OTP里面可以烧录启动源配置、安全启动使能位等关键信息。如果之前尝试过烧写 eMMC 启动、或者做过安全启动相关的实验fuse 里可能已经指定了“不从 SD 启动”导致板子每次都尝试从 eMMC 启动根本没看 SD 卡一眼。这种现象的表现是其他板子同样的 SD 卡都能启动你的板子就是没反应。此时需要用 STM32CubeProgrammer 连接查看OTP相关寄存器确认有没有设置过影响启动顺序的 fuse。如果确认烧过了又没有备份原始值这块板子就可能很难再切换到 SD 卡启动了。所以强烈建议在开发初期不要随意烧写 OTP fuse。另一个因素是供电。EV1 板如果只通过 ST-Link 的 USB 供电有些 USB 口供电能力不足DDR 训练时瞬间电流比较大会触发 PMIC 的欠压保护导致板子启动途中复位或者直接死机。建议使用官方配套的 12V 电源适配器给 EV1 板供电调试时会省掉很多莫名其妙的故障。4. 常见问题速查表与避坑经验4.1 启动失败现象对照表现象可能原因排查方向串口无任何输出启动源不对、FIP 写错位置、OTP fuse 干扰检查拨码、检查 FIP 偏移、查看 OTP有 TF-A 日志但 DDR 初始化失败U-Boot 设备树与板卡 DDR 不匹配核对st,mem-type、PMIC 配置TF-A 正常U-Boot 卡在启动加载bootfs 分区缺文件/文件名不匹配检查分区内容确认Image与.dtbU-Boot 能启动内核 panic根文件系统类型或设备树不匹配确认 rootfs 分区是否正确挂载Kernel 启动后黑屏显示相关 dtb 或 GPU 驱动问题确认 dtb 是否正确检查 LCD 排线4.2 我在排查这个问题时的三个核心心得第一不要跳过flashlayout.tsv。很多工程师为了省事构建完镜像直接dd结果各种启动失败。ST 在flashlayout里的分区设计是有原因的FIP 需要冗余备份fsbl1 和 fsbl2 是两份分区间隔和扇区对齐也都考虑到了。最稳妥的方式永远是 STM32CubeProgrammer flashlayout.tsv文件它会自动处理偏移和对齐。第二日志是最诚实的“同事”。在嵌入式开发中没有比串口日志更好用的调试工具了。哪怕是 BootROM 阶段一点输出都没有这个“没有”本身就是重要信息。我习惯在排查启动问题时先分三段抓日志上电到 TF-A、TF-A 到 U-Boot、U-Boot 到 Linux。每段分开分析不要一次性追求看到完整启动输出。第三一个特别的调试技巧用 TF-A 的STM32MP_SDMMC调试宏或者 U-Boot 的bootdelay和preboot机制。在 U-Boot 阶段按任意键停住然后手动执行启动命令比看自动启动日志更直观。# 在 U-Boot 启动界面按任意键进入命令行后手动执行 # 查看当前 boot 设备 mmc list # 查看 bootfs 分区 ls mmc 1:4这里的mmc 1:4表示 MMC 控制器 1 的第 4 个分区不同板子可能不同以实际为准。通过这条命令能快速确认 bootfs 里到底有什么文件避免瞎猜。4.3 如果仍然启动失败怎么办如果你把 FIP 写对了、启动拨码也对、电源也够稳但板子依然没有任何反应那就要往这两个方向查一个是trusted启动链的签名校验。如果你曾经编译过带签名功能的 TF-A或者板子上的 fuse 被设置了强制校验那么普通未签名的 FIP 会被 BootROM 拒绝。此时需要重新构建一个不带签名功能的 FIP或者用正确的签名工具签名后再烧写。另一个是硬件本身的问题。MP257F-EV1 板载的 SD 卡槽有时候接触不良尤其是某些第三方 SD 卡的厚度公差较大插入后并没有真正到位。换一张高速卡至少 Class 10 或 A1 级别试试顺便确认 SD 卡没有被写保护锁住。别笑这种低级问题在实际工作中出现的频率并不低。5. 构建前就该做好的三件事让排查省一半时间5.1 固定版本锁死环境在开启一个 MP2 项目之前第一件事就是冻结工具链和发行包的版本。Distribution Package 的构建对宿主机的 GCC 版本、make版本、python3版本都有隐含依赖。如果你用 Ubuntu 24.04 去构建一套为 Ubuntu 22.04 准备的 SDK构建过程大概率会报错或者产出的二进制在某些环节有微妙的行为差异。我个人的建议是使用官方推荐的 Ubuntu 版本然后直接下载 ST 提供的 Docker 镜像来构建把环境不一致的问题彻底隔离开。SDK 和 Distribution Package 都放进 Docker 里宿主机的任何变动都不会影响构建结果。5.2 烧写前先备份原始镜像EV1 板出厂时SD 卡或 eMMC 上通常已经有一套官方烧好的 Demo 镜像。在格式化或覆写这张卡之前先把它完整备份一份。sudo dd if/dev/sdX ofbackup-sd.img bs4M statusprogress这个备份在遇到“我自己构建的镜像起不来但不确定是硬件问题还是软件问题”的时候特别有用。把备份镜像重新烧回去如果板子能正常启动说明硬件没问题问题确定在我们的镜像上如果备份镜像也起不来那要么是你的烧写流程有问题要么是板子/卡本身有问题。5.3 记录拨码和跳线状态这个看似简单的步骤很多时候会成为救命的记录。不同跳线状态下EV1 板的启动行为完全不一样。我建议拿到板子后先把所有拨码、跳线的默认位置拍照存档并且在维修或排查时保持记录。很多时候所谓“板子突然坏了”其实只是某个跳线帽被碰到了。6. 这次问题排查后我对构建流程的调整经历过这次 6.6.116 发行包构建后无法从 SD 卡启动的排查我现在构建完镜像之后的第一件事不是直接烧卡测试而是先做一次“镜像自检”。我会先检查flashlayout文件里的偏移和分区名然后用fdisk -l /dev/sdX看实物镜像的分区表是否和flashlayout一致。这个步骤大概只要一分钟但能过滤掉大半的烧写问题。接下来我会检查 FIP 文件本身的内容是否完整。用strings命令在 FIP 里搜索U-Boot和stm32mp257f-ev1.dtb关键字确认 U-Boot 和设备树都打进了 FIP。如果strings输出里看不到 U-Boot banner 相关的字符串说明 FIP 本身可能不是从正确的构建产物里拿的或者构建过程出了问题。strings fip-stm32mp257f-ev1.bin | grep -i U-Boot strings fip-stm32mp257f-ev1.bin | grep -i stm32mp257f-ev1.dtb如果这两条命令都有输出那么 FIP 基本可以判定为正常。如果只有一条有输出就要重新审视构建产物了。最后再啰嗦一句STM32MP2 的启动链路跟 MP1 真的不一样不要拿老经验硬套。认真地读一遍你生成的那份flashlayout.tsv把它当作启动排查的第一份参考资料你会少走很多弯路。我希望这篇排查记录能帮你把“构建成功”和“能启动”之间的距离缩短到一次正确的flashlayout烧写这么短。
返回列表