
先别急着插线我先把一个关键概念理清楚不然你后面会被“烧录”这两个字坑到。STM32MP157F-DK2这块板子核心卖点是异构双核Cortex-A7跑LinuxCortex-M4做实时控制。A7侧网上教程多得是但M4核固件怎么部署尤其是怎么用STM32CubeProgrammer把固件“烧”进去很多人一上来就卡壳。这篇文章就拿STM32MP157F-DK2加STM32CubeProgrammer这条线把M4固件从编译到下载、从调试到量产的完整路径捋一遍适合刚入坑MP1系列、被A7和M4双核协作搞得有点懵的工程师朋友。先说一下结论STM32MP157的M4核没有内部Flash它本身不能独立上电启动。所谓“烧录M4固件”实际上是把M4的ELF/BIN文件放到A7 Linux能找得到的地方然后由remoteproc框架在启动时替你把M4拉起来。理解了这一点后面所有操作逻辑就都顺了。1. 先搞清楚这个M4核到底怎么“烧”进去的1.1 M4核没有内部Flash烧录其实是两回事用过普通STM32 MCU的人印象里“烧录”就是把代码写进芯片内部Flash掉电不丢上电直接跑。但STM32MP157F不是这个玩法。它内部的Cortex-M4是一个协处理器代码必须放在RAM或者DDR保留区里执行芯片内部并没有给M4准备独立的非易失存储。那M4的代码从哪来答案是靠A7侧的系统启动流程协同加载。所以“给M4烧录固件”实际上有两种完全不同的场景操作路径也完全不同第一种是开发调试场景。板子已经通电A7侧系统跑不跑都行你通过ST-LINK把M4固件直接下载到M4的RAM里运行。这种方式适合前期调试改代码、加断点、看变量都很方便但有一个致命问题掉电就没了。你不能指望拿这种方式给产线用。第二种是部署发布场景。你要把M4固件作为A7 Linux系统里的一个普通文件放进rootfs的/lib/firmware/目录下具体路径要看你的系统配置然后让Linux的remoteproc框架在启动时自动把固件加载到M4核并启动。这才是真正意义上“烧进板子”的持久化部署。STM32CubeProgrammer在这两种场景里都能干活但操作方式截然不同。很多人在论坛里问“用CubeProgrammer烧M4怎么烧不进去”多半是把这两种场景搞混了拿着部署期的思维去做调试期的操作或者反过来。1.2 为什么选STM32CubeProgrammer而不是直接拷文件部署M4固件其实有几种方式。最直观的就是A7 Linux已经跑起来的情况下直接把编译好的M4固件ELF文件拷贝到/lib/firmware/然后重启系统让remoteproc自动加载。这种方式在开发阶段很方便但前提是你手上已经有一块能启动Linux的板子。但如果板子是完全空白的状态SD卡里什么都没有或者你要给产线批量制作镜像这时候就得用STM32CubeProgrammer通过USB/UART把完整的系统镜像包含M4固件烧写到SD卡或eMMC里。再或者你用ST-LINK方式在空板上调试M4也需要CubeProgrammer这种级别的工具直接操作调试端口。所以选STM32CubeProgrammer的理由很简单它是ST官方维护的烧录工具既支持ST-LINK在线调试下载也支持通过ROM Bootloader整板镜像烧写工具链统一、文档齐全、踩坑的人多意味着你搜解决方案比较容易。相比之下自己写脚本用dd命令做镜像、手动改U-Boot环境变量虽然也能跑通但维护成本高换个版本就莫名其妙出问题。2. 烧录前的准备工具、连接和启动模式2.1 硬件与软件清单动手之前先把东西备齐省得到时候手忙脚乱。硬件上需要这几样STM32MP157F-DK2开发板一块废话板载ST-LINK通过USB线连接电脑用于调试下载和查看日志USB Type-C数据线一根用于整板镜像烧录时的USB连接如果从SD卡启动还需要一张质量可靠的Micro SD卡建议容量8GB以上如果有外接ST-LINK也可以备一个有时候板载ST-LINK状态异常时能救急软件方面STM32CubeProgrammer建议装2.10.0以上版本老版本对MP1系列支持不完整STM32CubeIDE或者STM32CubeMX用来生成和编译M4固件工程一个串口终端软件比如MobaXterm、PuTTY用来查看A7 Linux的启动日志安装STM32CubeProgrammer的时候驱动会被一并装上。Windows下如果发现设备管理器里ST-LINK设备有黄色感叹号手动指向安装目录下的Driver文件夹更新驱动即可。2.2 拨码开关和启动模式STM32MP157F-DK2板上有一组启动模式拨码开关控制着芯片从哪个介质启动。不同版本的板子丝印可能有差异但一般是BOOT2、BOOT1、BOOT0三个开关。这里要特别注意不同阶段你需要不同的拨码组合我列一个最常用的参考表场景BOOT2BOOT1BOOT0说明从SD卡正常启动000日常跑Linux也是大多数用户默认状态进入工程模式烧录模式100板子进入ROM Bootloader可通过USB/UART烧录不同批次板子的方向定义可能不一样最稳妥的做法是看板子丝印上的ON方向以及翻一下官方《Getting started with STM32MP157F-DK2》那篇文档。拨码拨好之后板子用USB线与电脑连好再上电。进入工程模式后Windows设备管理器里应该能看到一个“STM32 BOOTLOADER”或者类似的USB设备这就是ROM Bootloader暴露出来的DFU接口CubeProgrammer就是通过它来访问外部存储器的。3. 第一步把M4固件编译出来3.1 用STM32CubeMX生成M4工程现在你手上得有M4固件的ELF文件不然烧录无从谈起。最简单的方式是打开STM32CubeMX选择STM32MP157F-DK2对应的M4工程模板。CubeMX会生成一个完整的Cortex-M4工程里面初始化了时钟、串口、GPIO等基本外设。打开STM32CubeIDE导入这个工程编译会得到一个.elf文件。这里要提醒一下编译M4工程时最好养成看链接脚本的习惯。MP1系列的M4工程链接脚本后缀一般是.ld里面定义了代码和数据段放在哪个内存区域。你可以用文本编辑器打开看看通常会看到类似这样的定义MEMORY { RAM (xrw) : ORIGIN 0x10000000, LENGTH 64K RAM_D1 (xrw) : ORIGIN 0x30000000, LENGTH 64K RAM_D2 (xrw) : ORIGIN 0x30020000, LENGTH 128K RAM_D3 (xrw) : ORIGIN 0x30040000, LENGTH 64K DDR (xrw) : ORIGIN 0x2FFC0000, LENGTH 256K }不同示例工程的地址定义会不一样有的把M4固件放在内部SRAM40x10000000有的放在DDR保留区0x2FFC0000附近。这个地址不是随便定的它必须和A7侧remoteproc配置里预留的内存区域保持一致。如果你自己修改了链接脚本那就必须同步修改设备树里reserved-memory节点的地址否则Linux把M4固件加载到一个地址M4实际却在另一个地址执行指令跑飞是必然的。3.2 为什么链接脚本地址是“牵一发动全身”打个比方M4固件就像寄宿在A7家里的一个房客A7的Linux是这个家的主人。房客住哪个房间房东得提前给他腾出来而且双方要谈好在同一个房间碰头。链接脚本里M4的段地址就是房客的房间remoteproc配置里的内存保留区域就是房东预留的房间这两个地址对不上M4要么跑飞要么直接卡死。ST官方默认的示例工程里地址基本都是对齐好的。如果你只是拿官方示例来试直接编译就不会有问题。但如果你自己新建工程、改了链接脚本或者想用某个特定DDR区域那就要把下面这几样东西一起检查链接脚本里的ORIGIN地址、设备树里reserved-memory节点的reg属性、u-boot环境变量或Linux内核设备树里remoteproc的firmware-name配置。任何一个对不上都会出现“烧录成功但M4没反应”这种最令人抓狂的问题。4. 实操STM32CubeProgrammer烧录M4固件4.1 方式一ST-LINK在线调试下载这种方式最适合开发调试阶段。假设你的A7侧Linux正在跑或者还没跑起来都无所谓你只是想快速看看M4固件能不能在这个板子上跑通。打开STM32CubeProgrammer左上角接口选择ST-LINK然后点击Connect。连接成功后界面会显示当前通过ST-LINK访问到的内核信息。注意MP1的调试端口既可以访问A7核心也可以访问M4核心关键在右上角的Port下拉框选择MCU才能连到Cortex-M4上。连上M4之后左侧Firmware区域选择你刚才编译出来的M4固件.elf文件起始地址那里CubeProgrammer会自动从ELF的段信息里读取一般不需要手动填。然后点击Download按钮。下载完成后勾选Run按钮让M4复位并运行。我实测下来的效果是如果A7 Linux正在运行这种方式下载M4固件到SRAM或DDR保留区速度很快基本是秒级完成。但有两个限制一是下载到RAM里的固件掉电即失二是如果你下的固件和目标RAM区域有冲突例如A7 Linux已经在使用DDR的那段内存会导致系统崩溃或异常。所以在线调试时我习惯先把A7侧的内存分配挪开或者使用内部SRAM区域来跑M4调试版本。ST-LINK模式下最典型的报错是连接M4超时。原因是A7侧Linux或U-Boot已经占用了调试端口或者MPU在Secure模式下把调试口锁死了。遇到这种情况可以先复位板子在Linux启动早期快速Connect或者在CubeProgrammer的Mode里选择“Under reset”模式让工具控制复位信号再连接。4.2 方式二整板镜像烧写到SD卡这是“部署”正儿八经的方式也是标题里“Flashing”最常指的操作。操作流程大概是先把板子拨到工程模式再通过USB连接电脑用CubeProgrammer把整个OpenSTLinux镜像包含M4固件文件烧写到SD卡烧完后拨回SD启动模式上电整个系统起来M4固件由Linux自动加载。具体步骤第一步把SD卡通过读卡器连接电脑格式化或不管它都行反正最后会被整个覆写。再把SD卡插回板子上的卡槽。第二步板子拨码切到工程模式USB Type-C数据线连接板子的USB口和电脑。上电后Windows设备管理器里应该出现“STM32 BOOTLOADER”设备。第三步打开STM32CubeProgrammer接口选择USB点击Connect。连接成功后CubeProgrammer会识别到板子ROM Bootloader的版本号。第四步关键点来了。在左侧External Loader区域选择一个针对SD卡的外部加载器。STM32CubeProgrammer安装目录下自带了MP1系列的external loader类似“STM32MP1xx_SD_Card_Ext_Loader.elf”。选中它再去右侧烧录区域加载你要烧的镜像布局文件也就是官方OpenSTLinux镜像包里的flashlayout_stm32mp157f-dk2.tsv这种文件。第五步点击Download。CubeProgrammer会根据布局文件把各个分区依次烧写到SD卡上。整个镜像几个GB的话USB 2.0模式下大约要等十几分钟到半小时耐心等着别中途断掉。烧录完成后把拨码切回SD启动模式按一下复位键A7 Linux开始启动。你会看到串口终端里Linux内核启动日志刷屏过一会儿登录提示符出现。这时候查看/lib/firmware/目录应该能看到一个类似stm32mp157f-dk2-m4-fw.elf的文件这就是OpenSTLinux发行版里自带的M4固件。如果你的M4固件是自己编译的在Linux起来之后可以直接用scp或者U盘把它覆盖到/lib/firmware/再重启自己的固件就会被加载。4.3 别忘了还有命令行模式图形界面操作虽然直观但命令行模式在批量生产或脚本化操作时才是效率之王。STM32CubeProgrammer的CLI工具叫STM32_Programmer_CLI在安装目录下的bin文件夹里。ST-LINK下载M4固件的命令行大概是这样的STM32_Programmer_CLI -c portSWD modeUNDER_RESET -d /path/to/m4_firmware.elf -run如果是USB烧录整板镜像命令行要复杂一些通常会和指定的external loader以及分区布局文件配合。例如STM32_Programmer_CLI -c portUSB1 -w flashlayout_stm32mp157f-dk2.tsv注意不同版本的CLI参数略有差异建议先用-help查一下当前版本的帮助信息。命令行模式有几个好处一是方便集成到CI流程或出厂测试脚本里二是参数固定后可减少人为误操作三是可以和Windows批处理或Linux shell脚本组合实现一键烧录多块板子。5. M4固件地址、链接脚本与remoteproc的联动机制5.1 M4的RAM布局要彻底搞懂M4固件烧录后为什么能跑起来得知道M4核可用哪些内存区域。STM32MP157F内部有多个SRAM部分用于系统管理部分可以分配给M4。最常见的M4运行区域是以下这几块区域起始地址大小用途说明MCU_SRAM40x1000000064KBM4常用运行区很多示例默认用它DTCM0x3000000064KBCortex-M4紧耦合内存访问延迟低SRAM1/2/30x10020000 起共384KB部分保留给A7/M4共享DDR保留区0x2FFC0000 附近可变从DDR划出的一段专用区域容量大适合复杂固件内部SRAM虽然快但容量有限复杂一点的M4应用堆栈加起来就容易爆。DDR保留区容量大适合跑比较大的M4固件比如音频算法或者复杂的控制逻辑但要占用一部分DDR带宽。实践中我倾向于能用内部SRAM跑通的调试阶段就用内部SRAM到正式产品阶段如果M4固件规模超过64KB再把地址迁到DDR保留区同时改好设备树。5.2 remoteproc如何找到并加载固件STM32MP157F的Linux内核里remoteproc框架负责管理M4核的启停。它启动M4的过程大致是这样的内核初始化时remoteproc驱动读取设备树中配置的firmware-name属性拿到M4固件的文件名然后去/lib/firmware/目录下寻找这个文件。找到后内核将固件的各个段加载到设备树中指定的内存地址接着复位M4核设置程序入口M4就开始执行了。设备树里的片段大概长这样m4_rproc { memory-region retram, mcuram, mcuram2; firmware-name stm32mp157f-dk2-m4-fw.elf; status okay; };注意firmware-name这个属性它指定了固件文件名。如果你的固件不叫这个名字Linux启动时会报“Failed to request firmware”之类的错误。所以部署自己的M4固件时要么把固件命名为设备树里指定的文件名要么修改设备树重新编译二选一。另外OpenSTLinux的启动链路里U-Boot也会在早期阶段加载M4固件。U-Boot会先于Linux把M4拉起来这种方式叫“early boot”适合那些需要在Linux起来之前就要干活的M4任务。但不管U-Boot还是Linux负责加载M4固件文件本身都是存放在文件系统里CubeProgrammer整板烧录时一并写入并没有所谓的“单独烧到M4 Flash”这种操作。这个认知对排查问题特别重要。6. 验证M4是否真的跑起来了6.1 看启动日志烧录完成并正常启动后第一件事就是验证M4固件有没有被成功加载。打开串口终端波特率115200观察Linux启动日志。搜这几个关键词remoteproc、rproc、m4。如果一切正常你会看到类似这样的输出remoteproc remoteproc0: m4 is available remoteproc remoteproc0: loading stm32mp157f-dk2-m4-fw.elf remoteproc remoteproc0: registered as remoteproc0 remoteproc remoteproc0: powering up m4 remoteproc remoteproc0: Booting fw image stm32mp157f-dk2-m4-fw.elf, size 123456看到“Booting fw image”这一行说明Linux已经成功把M4固件加载到了指定内存并且把M4核启动起来了。6.2 用sysfs操作remoteproc除了看日志还可以通过sysfs接口实时查看和操作M4状态。登录Linux后执行cat /sys/class/remoteproc/remoteproc0/name cat /sys/class/remoteproc/remoteproc0/state cat /sys/class/remoteproc/remoteproc0/firmwarestate文件里显示“running”说明M4正在运行。如果M4因为某些原因挂了你可以手动重启它echo stop /sys/class/remoteproc/remoteproc0/state echo start /sys/class/remoteproc/remoteproc0/state这个操作在开发阶段非常实用。比如你改了M4固件先复制到/lib/firmware/然后执行stop再start新固件就会被重新加载不用重启整个Linux系统。注意要先stop再start直接重新start有时候不生效。6.3 M4侧打印与LED示例M4固件跑起来之后怎么确认它真的在工作最简单的方法是点灯。ST官方M4示例里有个GPIO点灯或串口回显的程序M4跑起来后串口会周期性打印消息或者某个LED按节奏闪烁。如果你看到板子上LED的变化符合预期那说明M4固件状态正常。但这里有个坑M4的调试串口和A7的Linux控制台可能共用同一个物理串口或虚拟串口。如果两边都在打印你会看到日志混在一起甚至互相干扰。解决方法是把M4的打印输出重定向到另一个串口或者在M4固件里不要频繁打印仅在状态切换时打印一次。7. 常见问题与避坑清单7.1 ST-LINK连接失败或连接超时这是个高频问题。我自己遇到最多的情况是A7 Linux已经占用了调试端口导致ST-LINK无法连接M4。解决办法是采用Under reset模式强制连接或者在板子复位后Linux还没完全起来的那个窗口期抢连。还有一种情况是ST-LINK固件版本太老用STM32CubeProgrammer或STM32CubeIDE里的固件升级功能刷一下就好。现象可能原因解决办法ST-LINK设备管理器不识别驱动没装好/线是充电线重装驱动、换数据线连接M4超时A7占用了调试端口用Under reset模式重试下载后M4没有运行地址与配置不匹配检查链接脚本、remoteproc配置7.2 USB模式识别不到板子整板烧录时USB模式连不上板子是另一个高发问题。排查顺序如下确认拨码开关确实切到了工程模式确认用的USB线是数据线而不是只有供电功能的线确认设备管理器里有没有“STM32 BOOTLOADER”设备。如果拔插后设备就是不出来换一个USB口或者重新上电试试。我遇到过几次是板子供电不足换一个供电能力强的USB口或者插到电脑后置USB口就解决了。7.3 M4固件加载后没反应这种情况最让人头疼因为从烧录流程看一切正常Linux日志里也显示“Booting fw image”但M4任务就是不动。我的排查顺序是先确认remoteproc加载的固件确实是你自己编译的那个版本因为Linux根文件系统里可能还留着另一个同名旧固件你用CubeProgrammer烧的镜像里的固件和后来手动拷进去的固件容易混淆。其次确认M4固件链接地址和remoteproc设备树里的内存保留区是否一致这是跑飞的元凶。最后确认时钟配置如果M4固件里初始化RCC时钟的代码和A7侧的电源/时钟管理器冲突M4会死锁或访问异常。7.4 资源冲突问题A7和M4共享大量外设和内存最常见的中断控制器、串口、GPIO、DMAC。如果A7设备树和M4工程里配置了同一个外设轻则功能异常重则死机。实践中有个原则外设归属要清晰要么给A7要么给M4不要两边都初始化。尤其要注意中断控制器M4的中断优先级和A7侧GIC是两套逻辑配置不好会出现中断风暴看起来就是系统随机死机。说实话M4核在STM32MP157F-DK2上的部署本质上就是搞明白“A7帮M4把代码搬进内存并启动”这一件事。搞懂之后你去看官方示例、源码、论坛帖子都会顺畅很多。我自己刚上手MP1时也踩过不少坑最深的体会就是不要只盯着CubeProgrammer怎么点而是要把链接脚本地址、设备树firmware-name、镜像打包这三条线串起来看。先抓主线再处理细节M4固件部署就不会再是个玄学问题。