尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32MP1 eMMC启动PANIC及CubeProgrammer连不上解决

STM32MP1 eMMC启动PANIC及CubeProgrammer连不上解决 1. 从一次“连不上的PANIC”说起我盯着串口终端里的日志最后一行是Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,10)。那一刻我反倒松了口气——至少说明U-Boot已经跑起来了问题出在后面。然后我习惯性打开STM32CubeProgrammer想用ST-LINK重新烧一版镜像进eMMC结果点了Connect之后软件卡在连接界面过了几秒直接报错“Error: No STM32 target found”。再试几次还是一样。这个场景太熟悉了。很多折腾STM32MP1系列的朋友估计都经历过板子从SD卡启动一切正常一旦切到eMMC启动要么PANIC要么直接“变砖”最难受的是CubeProgrammer也连不上连救回来的手段都没有。我这次用的是STM32MP135DAF这颗单核Cortex-A7芯片配合自己基于Yocto定制的machine整个过程从“看起来很简单”到“差点以为板子报废”最终花了差不多一个晚上才彻底摸清问题链路。这篇就把整个排查过程、根因、恢复步骤和Yocto层面的根治方案都写清楚给正在踩同款坑的人一个可以直接抄作业的参考。先说结论省得你看一半着急eMMC启动PANIC大概率是分区表、设备树或内核cmdline三者之一出了问题而CubeProgrammer连不上绝大多数时候不是调试器坏了而是芯片在eMMC启动模式下被“拉”进了一个CubeProgrammer难以稳定复位连接的状态。两个问题叠在一起才造成了“变砖”的假象。2. eMMC启动PANIC的根因链路从ROM到rootfs逐个排查要搞清楚为什么PANIC不能只看最后那一行。STM32MP135的启动链是一层套一层的片上ROM先根据BOOT引脚选择启动源然后加载FSBL也就是TF-A BL2或者U-Boot SPLFSBL再加载FIP镜像里面包含BL31和U-Boot properU-Boot再去bootfs里读设备树和内核最后内核挂载rootfs。任何一环出错表现都是“启动失败”但日志停的位置完全不同。2.1 串口日志每一行对应的“排错地图”我习惯先把U-Boot完整日志拉下来然后一行一行对照判断是卡在哪一环。下面这个表格是我这次排查时的快速定位方式日志关键特征所在阶段常见根因完全没有输出或者卡在DDR:之前ROM / FSBL初期eMMC boot分区里没有有效FSBL或BOOT引脚配置不对DDR: 512 MiB之后无进展FSBL到FIP之间FIP镜像未放在eMMC boot分区或FIP里的DTB与硬件不匹配MMC: sdmmc1: 0, sdmmc2: 1U-Boot枚举MMC设备eMMC被识别为哪个设备号直接决定后面root参数怎么写switch to partitions #0/mmc1 is current deviceU-Boot访问eMMC分区表损坏或boot partition未切换Failed to mount root fs/VFS: Unable to mount root fs内核挂载rootfsroot设备节点写错或rootfs分区类型/位置不对Kernel panic - not syncing: No working FDT found内核启动早期DTB没加载或FIT镜像里DTB路径不对这次我的日志停在了VFS: Unable to mount root fs on unknown-block(179,10)。179,10这个设备号对应的其实是mmcblk0p10。也就是说内核在试图挂载/dev/mmcblk0p10这个分区但这个分区要么不存在要么类型不对。2.2 实际定位到的“元凶”排查到最后问题出在两个方面叠加。第一个是U-Boot把eMMC枚举成了mmc1而不是mmc0。STM32MP135上通常sdmmc1接SD卡、sdmmc2接eMMC但U-Boot的设备号并不一定按这个顺序来。它在启动时根据设备树别名aliases里的mmc0、mmc1定义来编号。我自定义的Yocto machine里设备树没有把sdmmc2设为mmc0结果eMMC变成了mmc1SD卡是mmc0。而我在内核cmdline里写的却是root/dev/mmcblk0p10内核自然找不到这个设备。第二个问题是eMMC本身的分区布局。ST的官方flashlayout工具烧录时会把FSBL写进eMMC的boot partition 1把bootfs、rootfs这些写进UDA用户数据区的指定偏移。我基于Yocto定制的machine时为了省事直接改了官方WKS分区脚本把rootfs从第6分区挪到了第10分区但U-Boot的bootcmd里读uEnv.txt的路径还是老的mmc 1:4内核cmdline也是旧的。这一套“不配套”组合下来eMMC启动时连FSBL都勉强跑起来了但到了内核挂载rootfs阶段设备和分区完全对不上PANIC就成了必然。2.3 用U-Boot命令行快速验证不用反复烧录当时我为了确认到底是U-Boot阶段还是内核阶段的问题做过一个很有效的操作在U-Boot倒计时期间按任意键打断自动启动然后手动执行几条命令。# 查看U-Boot枚举到的MMC设备 mmc list # 查看当前eMMC设备是否有合法分区表 mmc dev 1 mmc part # 列出分区内容确认bootfs里到底有什么 ls mmc 1:4 # 查看当前环境变量里的bootcmd和bootargs printenv bootcmd printenv bootargs env print这几条命令能在不重烧的情况下直接告诉你eMMC到底被编号成几号、分区表在不在、bootfs里的文件名对不对、环境变量指向哪个分区。我当时就是靠mmc list发现sdmmc2被枚举成mmc1然后又靠ls mmc 1:4发现bootfs其实在第4分区而不是我记忆里的位置瞬间就确定了根因方向。这套“三板斧”比反复烧录试错高效得多。3. CubeProgrammer为什么连不上它比想象中更依赖“复位行为”现在回到最让人崩溃的问题为什么改完eMMC启动之后STM32CubeProgrammer就再也连不上目标板了我最初怀疑是ST-LINK线坏了换了一根线不行怀疑驱动掉了重装CubeProgrammer不行怀疑板子电源不稳用外部稳压源单独供电还是不行。踩完这一串弯路之后我才意识到问题压根不在调试器而在“目标板当前的启动状态”和“CubeProgrammer默认的复位连接方式”之间的冲突。3.1 三根BOOT引脚决定了CubeProgrammer能不能“看懂”芯片STM32MP135上有专门配置启动源的BOOT引脚具体编号组合要看板卡原理图常见的是BOOT0/BOOT1/BOOT2拨码开关。芯片每次复位或上电时片上ROM都会采样这几根引脚的电平决定从哪个设备加载第一段启动代码。问题在于如果你把BOOT拨码拨到了eMMC启动那么CubeProgrammer通过ST-LINK连接时默认会去复位目标芯片。复位释放的一瞬间芯片立刻进入eMMC启动流程。我的eMMC里虽然FSBL能跑但到了U-Boot阶段板子已经初始化了DDR、MMC控制器、时钟树甚至ETZPC扩展TrustZone外围控制器可能把调试接口相关的总线访问权限改成了secure-only。这种情况下调试器再去扫描SWD内核可能会发现CPU核心被“锁”在了一个无法正常halt的状态或者干脆扫描不到任何core于是报“No STM32 target found”。更麻烦的是如果U-Boot或内核里开启了独立看门狗IWDG而系统在FIP加载或内核启动阶段反复panic看门狗会周期性复位芯片导致CubeProgrammer每次尝试连接时都正好撞上芯片在复位-启动-PANIC-复位的循环里。从软件角度看这就是一个永远抓不到稳定目标的状态。连接时BOOT引脚状态芯片复位后的行为CubeProgrammer大概率能看到什么拨到SD卡启动从SD卡正常加载不会锁调试口能看到核心连接成功拨到eMMC启动系统正常正常进入Linux但调试权限可能受限有时能连有时只能看到core0拨到eMMC启动系统PANIC反复启动/复位可能触发看门狗扫描不到稳定target连接失败拨到USB DFU/UART工程模式ROM代码停在那里等待DFU命令不跑用户代码一定能连接通过USB或UART识别这就是为什么“之前SD卡启动时能连一切到eMMC启动就再也连不上”的现象如此普遍不是板子烧了是你的BOOT引脚一直锁定在eMMC模式而eMMC里的代码一出问题整个系统就被困在异常循环里调试器连不进去。3.2 CubeProgrammer的复位模式一个关键参数解决大半问题很多人不知道STM32CubeProgrammer连接ST-LINK时复位连接方式是可以选的。GUI界面的“Connect”按钮旁边通常有设置命令行下对应的是mode参数。模式说明适用场景modeNORMAL默认先复位目标板再连接目标板当前运行状态正常时可用modeUNDER_RESET拉低NRST并保持在复位期间抓住内核目标板启动代码异常、反复跑飞时非常有效modeHOTPLUG不控制复位直接扫描SWD目标板由外部电源独立供电或复位线路异常时使用我最开始一直用默认的NORMAL模式怎么都连不上。后来换成UNDER_RESET模式CubeProgrammer在芯片被按住复位的瞬间去扫描内核这时候芯片还没有机会跳到eMMC的异常启动流程里自然就能连上了。命令行下的操作方式是这样的# 使用ST-LINK SWD在复位期间连接 STM32_Programmer_CLI -c portSWD modeUR # 如果芯片被锁死了先做整片擦除注意这会清掉eMMC/UDA所有数据 STM32_Programmer_CLI -c portSWD modeUR -e allmodeUR这个参数建议所有折腾STM32MP1系列的人先记下来。它可能就是你从“变砖”到“救活”之间最短的一条路。3.3 还有一个总被忽略的调试接口是否被安全机制封锁我在排查过程中还发现了另一种导致“连不上”的情况U-Boot/FIP里如果启用了TrustZone相关的总线过滤配置ETZPC、TZC400而对应的外设包括DBGMCU调试单元被配置成secure访问权限那么非安全世界的调试器工具扫描SWD时会一无所获。这种情况通常不会因为你换一个modeUR就解决因为它不是复位状态问题而是访问权限问题。这时候最干净的办法就是把BOOT引脚切换到USB DFU或UART工程模式让芯片根本不去执行eMMC里那段会锁总线的代码然后通过USB DFU接口重新烧录。这个方法也是我最终的选择。4. 完整抢救步骤从“疑似变砖”恢复到可烧录状态如果你现在板子症状和我一样——eMMC启动PANICCubeProgrammer连不上——不要慌下面这套流程是我实测有效的恢复路径。前提是你手上还有原厂或自己构建的烧录镜像以及一块能正常工作的ST-LINK或者一条能进USB DFU模式的USB线。4.1 第一步把芯片从错误的启动循环中“摘”出来这个步骤听起来简单但最容易忽略。先断开所有供电包括ST-LINK的3V3供电、外部电源、USB线。然后把板子上的BOOT拨码开关拨到“工程模式”也就是进USB DFU或UART下载模式。具体哪一组拨码对应哪个模式务必查你手上的板卡用户手册或原理图别凭记忆猜。我用的板子上是三位拨码其中一组组合是USB DFU另一组是UART还有一组是eMMC。拨好之后先用USB线连接板子上标注为“USB DFU”或“OTG”的接口不是ST-LINK那个USB口再接供电。上电后在设备管理器里观察是否出现一个STM32 BOOTLOADER设备。如果出现了说明芯片已经停在了ROM的DFU等待状态没有去执行eMMC里的代码接下来就很好办了。4.2 第二步用CLI而不是GUI连不上时命令行才给反馈图形界面看起来直观但出了问题它只会弹一个笼统的报错框。我建议在恢复阶段直接用命令行工具反馈信息更详细也更容易定位。先试ST-LINK SWD连接STM32_Programmer_CLI -c portSWD modeUR如果这一步成功了你会看到目标芯片的IDR信息比如STM32MP135的设备ID。如果还不行转到USB DFU方式# 先确认系统识别到了STM32 BOOTLOADER设备 STM32_Programmer_CLI -l usb # 通过USB DFU连接 STM32_Programmer_CLI -c portUSB1USB DFU方式下芯片是ROM状态不依赖任何flash里的代码所以几乎不会失败。这也是为什么我强烈建议设计板卡时一定要把USB DFU的BOOT拨码引出来否则遇到芯片锁死的情况只能拆flash或者用ST-LINK硬扛。4.3 第三步用flashlayout重新烧录eMMC镜像恢复连接之后直接看Yocto构建产物目录。STM32MP1的Yocto BSP通常会生成一堆tf-a-stm32mp13*.stm32、fip.bin、u-boot.stm32以及一个flashlayout文件夹里面有.tsv分区描述文件。STM32CubeProgrammer烧录eMMC时就是靠这个TSV文件告诉它“哪些数据写到eMMC的哪个位置”。我这次用的是自己改过的flashlayout_emmc.tsv关键内容大致如下#Opt Id Name Type IP Offset Binary - 0x01 fsbl1-boot Binary mmc0-boot1 0x0 tf-a-stm32mp135da-fsbl.stm32 - 0x03 fip-boot Binary mmc0-boot1 0x0 fip.bin P 0x04 bootfs System mmc0p4 0x0 bootfs P 0x05 vendorfs System mmc0p5 0x0 vendorfs P 0x06 rootfs FileSystem mmc0p6 0x0 rootfs.ext4在执行烧录前有几件事必须确认mmc0-boot1意味着数据要写进eMMC的内部boot分区1而不是用户数据区。很多自定义Yocto镜像会在这一步出错因为某些build流程默认把FSBL写到了UDA开头ROM code根本不去那里找。后面的mmc0p4、mmc0p6是指UDA里的第4分区、第6分区这个编号必须和WKS分区脚本一致。我前面PANIC的根因之一就是TSV里写的第10分区和WKS里的实际布局不一致。如果你不确定当前的TSV分区布局先用U-Boot的mmc part查看在线eMMC分区表再比对TSV别急着写。烧录命令如下STM32_Programmer_CLI -c portUSB1 -w flashlayout_emmc.tsv如果想顺便把整块eMMC备份出来可以在烧录前先读# 读取eMMC UDA全部内容到本地文件注意容量大小别把磁盘塞满 STM32_Programmer_CLI -c portUSB1 -r8 0x00000000 0x2000000 emmc_backup.bin0x2000000对应256MB如果你的rootfs较大自行调整大小。4.4 烧录后的验证别急着断电烧录完成后先不要急着重启看结果。我建议在CubeProgrammer里做一次“校验”操作确认写入的数据没问题然后再断电把BOOT拨码拨回eMMC启动模式上电看串口日志。验证阶段我会按这个顺序检查串口是否出现DDR初始化信息。是否枚举到MMC设备mmc1还是mmc0。是否成功加载FIP和U-Boot。内核是否挂载到正确的rootfs设备。只有看到系统进到登录提示符才算真正救活。5. 从Yocto层面根治自定义machine的第二次机会把板子救回来之后你一定会问怎么改才能让下一次构建出来的镜像直接能eMMC启动不再PANIC这就得回到Yocto的machine配置上。既然你是自定义的machine说明你不想一直用ST官方现成的配置那就要把自定义的部分和eMMC启动链路对齐。5.1 Machine配置里与eMMC启动强相关的三处第一处是machine conf里的boot设备定义。ST的Yocto BSP里stm32mp13common.inc这类公共配置通常定义了一系列默认变量包括MACHINE特性、PREFERRED_PROVIDER_u-boot、内核设备树列表等。如果你自定义的machine没有正确继承这些公共配置或者覆盖了其中和MMC顺序有关的变量U-Boot生成时就会用错设备树别名。第二处是设备树本身。sdmmc2节点必须配置正确的pinctrl和电压设置特别是eMMC通常需要1.8V I/O如果引脚mux成3.3V逻辑eMMC在高速模式下会连续CRC错误。这个错误在SD卡启动时完全看不出来因为SD卡走的是sdmmc1跟sdmmc2无关。第三处是内核cmdline。U-Boot的默认环境变量或者uEnv.txt里的bootargs必须包含正确的root参数。我这里以实际配置为例# 如果你的eMMC被U-Boot枚举为mmc1且rootfs在UDA第6分区 setenv bootargs consolettySTM0,115200 root/dev/mmcblk1p6 rootwait rw注意是mmcblk1p6不是mmcblk0p6。这个“设备号分区号”的组合是eMMC启动能否成功的关键。5.2 WKS分区脚本和TSV必须“对齐”差一个数字都不行自定义machine时最常见的问题就是改了WKS分区脚本但没有同步修改flashlayout TSV。Yocto在构建镜像时会用WKS脚本生成最终的.wic镜像但STM32CubeProgrammer烧录时看的是TSV里的偏移。如果两者不一致就像寄快递时收件人地址写错一个小区快递永远送不到正确的人手里。我现在的做法是在machine conf里固定一个明确的eMMC分区方案让WKS和TSV都从同一份定义读取。下面是我的WKS脚本片段part /boot --source bootimg-partition --ondisk mmcblk1 --fstypeext4 --label bootfs --active --align 4096 part / --source rootfs --ondisk mmcblk1 --fstypeext4 --label rootfs --align 4096对应的TSV就是P 0x04 bootfs System mmc0p4 0x0 bootfs P 0x06 rootfs FileSystem mmc0p6 0x0 rootfs.ext4这里0x04对应WKS里的第一个分区0x06对应第二个分区中间空出来的0x05可以留给vendorfs之类。分区编号一旦定下来就不要乱动。5.3 U-Boot环境变量和boot.scr让内核自动找到正确设备另一个非常隐蔽的坑来自boot.scr或uEnv.txt。ST官方镜像里U-Boot会去bootfs分区找一个启动脚本里面定义了bootcmd、kernel_addr_r、fdt_addr_r这些变量。如果你自定义machine时生成的bootfs里包含的还是官方默认的启动脚本它会按照官方分区布局去加载内核而你的自定义布局可能完全不同。我的建议是在machine conf里用IMAGE_BOOT_FILES显式指定bootfs里放哪些文件同时确保U-Boot的bootcmd能找到这个脚本IMAGE_BOOT_FILES \ uImage \ stm32mp135da-custom.dtb \ boot.scr \ boot.scr的内容我一般会在U-Boot源码目录下维护一个boot.cmd生成后编译进镜像。关键就是设置正确的root设备setenv bootargs consolettySTM0,115200 root/dev/mmcblk1p6 rootwait rw fatload mmc 1:4 ${kernel_addr_r} uImage fatload mmc 1:4 ${fdt_addr_r} stm32mp135da-custom.dtb bootm ${kernel_addr_r} - ${fdt_addr_r}注意这里加载路径写的是mmc 1:4代表第1个MMC设备eMMC的第4分区bootfs。如果你的U-Boot把eMMC枚举成了mmc0这段脚本要相应改成mmc 0:4否则又会回到“设备号写错”的老路上。5.4 一个可靠的验证顺序先在U-Boot里手动测再固化到脚本不管你怎么改Yocto配置我建议第一次不要直接信任自动生成的启动流程。烧录成功并把BOOT拨回eMMC模式后在U-Boot命令行里手动执行一遍启动命令确认每个地址、每个分区号都是对的再改成boot.scr固化。顺序是mmc list确认eMMC设备号。mmc dev 1切换到eMMC。mmc part确认分区布局。fatload mmc 1:4 ${kernel_addr_r} uImage测试能否读到内核。fatload mmc 1:4 ${fdt_addr_r} stm32mp135da-custom.dtb测试设备树。bootm手动启动。这套命令全部通过说明硬件、分区、DTB、内核镜像都没问题然后把同样的内容固化到boot.scr里你的Yocto镜像才算真正“eMMC-ready”。6. 折腾之后的几条硬经验板子救回来之后我把这次踩坑的过程整理成了几条以后不再犯的清单也分享给你。第一条改动Yocto machine之前先备份一份原厂或当前可用镜像。备份不花多少时间真到了CubeProgrammer连不上的时候你才知道有个后备镜像有多重要。最好是连eMMC UDA完整dd一份出来放移动硬盘里吃灰。第二条板卡的BOOT拨码组合必须第一时间写进硬件调试笔记里尤其是“USB DFU工程模式”对应哪几根引脚。这次CubeProgrammer连不上的时候我就是靠着这个记忆才快速切到USB DFU模式恢复的。如果板子上没引BOOT引脚建议飞线也要引出来。第三条eMMC启动的PANIC根因多数不在“eMMC烧录”本身而在“分区布局”和“设备号”。U-Boot里手动执行一遍mmc list、mmc part、ls mmc x:y能帮你把问题从“玄学”变成“数学”。第四条CubeProgrammer连不上时第一个要改的不是线不是驱动而是连接模式。命令行modeUR、modeHOTPLUG挨个试再不行就切BOOT到DFU模式。绝大多数“连不上”都是启动状态和复位方式不匹配不是硬件损坏。最后一条也是我这次体会最深的Yocto自定义machine最怕的不是改错而是改了A却忘了同步B。分区表、U-Boot环境变量、设备树里的MMC alias、内核cmdline、TSV文件这几个文件必须被当作一份完整的“启动契约”来维护。任何一个环节私自变了eMMC启动的某一环就会静默失败最终变成屏幕上那个让你血压升高的PANIC。
返回列表