近年来,异构多核 SoC 在嵌入式领域越来越常见,其中 STM32MP157 凭借其** Cortex-A7 + Cortex-M4 双核架构** 和良好的开源生态,成为许多开发者进行 Linux 系统移植和定制的理想平台;
相比传统的裸机 MCU 开发,STM32MP157 的启动流程更为复杂,涉及 BootROM → FSBL(如 TF-A)→ U-Boot → 内核 → 根文件系统 多个阶段,每一步都可能出现问题,每一步也都值得理解与掌控;
本系列文章将以实战为核心,记录我在 STM32MP157 平台上进行完整 Linux 移植的过程:包括 U-Boot 编译与调试、设备树配置、内核裁剪与驱动适配、根文件系统构建与挂载 等等;本篇作为第一篇,将重点放在 U-Boot 的获取、配置、编译、启动与串口调试,为后续系统启动打下基础;
本系列内容主要参考自 华清远见的嵌入式 Linux 教程,并结合我自己的实操经验进行补充、优化和归纳,力求贴近真实开发场景,便于读者实践与扩展;
如果你也在迈入 STM32MP1 系列的世界,希望本博客能帮你少走一些弯路,快速搭建起属于自己的 Linux 开发环境;
环境准备
本次移植所使用的环境基于 Ubuntu 18.04 LTS,配套的是较旧版本的 SDK 与源码(20 年),即便版本偏旧,但在 STM32MP1 系列开发中仍具代表性,适合入门与学习;
本文采用 Docker 容器方式搭建开发环境(Ubuntu 18.04 LTS),优点是可快速部署、便于还原;如果你不熟悉 Docker,也可以选择直接在虚拟机或实体机中安装 Ubuntu 18.04 环境;
容器采用 bind 挂载本地 SDK 和源码目录,便于调试与编译;建议通过 –privileged 启动容器,并开启 /dev、/proc 等挂载;
在进行 U-Boot 编译之前,请先确保以下必要工具链已安装:
1 | sudo apt update |
TF 卡分区准备
为实现 TF 卡启动,我们需要手动对 TF 卡进行分区和格式化,确保各阶段引导程序能被正确识别与加载;
- 清除原有分区表并建立新的 MSDOS 分区表:
1 | sudo parted -s /dev/sdX mklabel msdos |
- 使用 sgdisk 对 TF 卡重建分区表(含启动及根文件系统):
1 | sudo sgdisk --resize-table=128 -a 1 \ |
执行成功如下所示:

请将 /dev/sdX 替换为实际的 TF 卡设备名,如 /dev/sdb,确保避免误操作破坏其他磁盘数据;
SDK 与源码获取
SDK 与源码
提取密码: Tac3I
文件为 tar.xz 格式,请使用 tar -xvf 命令解压,解压之后,可进入 stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24 查看文件,其中 sdk 就是 SDK 安装文件所在文件夹,source 就是源码所在文件夹;
SDK 安装
该 SDK 是 ST 官方构建的交叉编译工具链(Toolchain),提供了用于构建 U-Boot、Linux 内核、Buildroot 系统和用户空间程序所需的编译器、头文件与库文件;
后续进行 STM32MP157 架构相关的编译工作时,均需依赖该 SDK 环境;
SDK 在解压时需要选择一个目录,作为 SDK 的安装目录,在这里我就把 sdk 文件夹改名为 sdk_installer ,然后新建一个名为 sdk 的文件夹,作为 SDK 的实际安装目录;
1 | mv sdk sdk_installer && mkdir sdk |
执行之后文件结构如下:
1 | stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/ |
进入 sdk_installer 的目录,执行名为 st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-openstlinux-5.4-dunfell-mp1-20-06-24.sh 的文件,接下来会提示你输入安装目录,输入我们刚刚创建的 sdk 目录,继续根据提示输入 y ,然后等待安装完成即可,整个过程提示如下:

根据提示,我们只需要执行下面的命令,就可以使用 SDK 了:
1 | . /root/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sdk/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi |
每次手动执行 source 命令略显繁琐,我们可以将它加入 .bashrc 文件,让终端在启动时自动加载,提升开发效率:
1 | nano ~/.bashrc |
在文件末尾添加下面这条命令,然后保存退出:
1 | . /root/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sdk/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi |
再执行 . ~/.bashrc 命令,使配置生效;
配置成功之后,执行 echo $CC 和 echo $ARCH 命令,如果输出如下,则表示 SDK 配置成功:

提示:安装 SDK 的意义不只是配置 $CC 和 $ARCH,更重要的是自动设置了交叉工具链、动态库路径、头文件路径等编译参数,使得我们可以一条命令完成 U-Boot、内核、应用程序等的 ARM 架构编译;
sdk_installer 以及 tar.xz 文件可以删除,后续编译过程中不再需要;
源码获取
进入 source 目录,可以看到里面包含多个源码文件夹,其中 u-boot、kernel、buildroot 是我们移植过程中需要用到的,其他文件夹可以忽略;
1 | cd sources/arm-ostl-linux-gnueabi && ls |
可以看到,u-boot、kernel、buildroot 等源码文件夹都在这里:

U-Boot 编译
源码准备
上一步看到的源码仍然是压缩包,我们进入 U-Boot 的目录,在目录下能看到 README.HOW_TO.txt 文件,里面介绍了依赖的安装和源码的解压,我们按照文件操作即可;
安装依赖
1 | sudo apt install libncurses5-dev libncursesw5-dev |
- SDK 环境加载,这一步和之前 SDK 安装时一样,不再赘述;
源码解压与补丁
1 | tar xfz u-boot-stm32mp-2020.01-r0.tar.gz |
配置与编译
复制默认配置文件
首先,基于 ST 官方的 trusted 配置,我们复制一份作为我们板子的基础配置:
1 | cp configs/stm32mp15_trusted_defconfig configs/stm32mp15_emtime_trusted_defconfig |
板级设备树修改
ST 的默认设备树不包含我们自定义的板卡信息,因此需要在 arch/arm/dts/ 中添加我们自己的设备树文件,设备树可以参考 arch/arm/dts/ 目录下的其它配置,甚至可以先直接用官方的(只要你的硬件契合),主要涉及以下几个文件(以官方文件为例):
1 | arch/arm/dts/stm32mp15xx-dkx.dtsi |
可以将文件复制一份,自己定义一个名字,然后修改文件,添加自己板子的硬件信息:
1 | cp arch/arm/dts/stm32mp15xx-dkx.dtsi arch/arm/dts/stm32mp15xx-emtime.dtsi |
修改其中的文件,修改文件引用相关的信息,如下:
- 将 arch/arm/dts/stm32mp157a-emtime.dts 的 #include “stm32mp15xx-dkx.dtsi” 改为 #include “stm32mp15xx-emtime.dtsi”
- 修改 arch/arm/dts/Makefile,在 stm32mp157 (dtb-$(CONFIG_STM32MP15x)) 中加入我们自己刚刚添加的文件,即加上 stm32mp157a-emtime.dtb \
注意:这一部分必须按照你实际情况进行修改(比如修改电源配置、增加 SD 卡支持、增加 eMMC 驱动、添加网卡驱动等),否则会导致无法正常引导或者无法正常驱动的问题;
之后有机会,我会专门写一篇关于设备树的文章,介绍如何编写设备树;
虽然我现在还没有编写这一部分的文章,但是设备树是 Linux 内核中非常重要的一部分,也是嵌入式开发中非常重要的一部分,所以建议有时间的话,一定要去学习一下;
bootcmd 修改
- 若要进行bootcmd的修改,则可以修改 include/configs/stm32mp1.h 文件,在 #ifdef CONFIG_BOOTCOMMAND 之后添加如下代码:
1 |
这里采用了偷懒的方法,在判断 CONFIG_BOOTCOMMAND 宏定义的地方,直接将 CONFIG_BOOTCOMMAND 宏定义取消,然后重新定义了 CONFIG_BOOTCOMMAND 宏定义,这样在编译的时候,就会使用我们重新定义的宏定义,而不会使用默认的宏定义;
为什么我要重写 bootcmd?因为他们设计的这一版板子,boot 拨码开关有问题,无论怎么拨,都会进入 USB 烧录模式,但 如果是 USB 烧录的情况,那么是不会正常加载eMMC的,所以我使用了 ext4ls 命令判断 eMMC 是否正常挂载,如果正常挂载,则加载内核和设备树,然后启动,否则执行默认的 bootcmd_stm32mp 进入下载模式;
后续找到了 bootcmd 和 bootargs 的定义,在 include/env_default.h 文件下,可以自行去修改;
U-Boot 配置
执行 make menuconfig 命令,进入配置界面:
1 | make menuconfig |

其实大部分我们都不用修改,因为我们复制的是官方的配置,官方的配置已经包含了我们需要的配置,而且因为是 U-Boot 的配置,并不需要配置太多驱动相关的东西,这里提一嘴 bootcmd value 吧,在这里我们也可以修改 bootcmd,如果这里修改了,那么上面代码中的操作是可以省略的;
配置完之后记得保存,然后就可以退出 menuconfig 界面了;
如果修改了配置,那么记得更新配置文件:
1 | cp .config configs/stm32mp15_emtime_trusted_defconfig |
编译
修改上一个目录中的 Makefile 文件:
1 | nano ../Makefile.sdk |
对文件进行如下操作:
- 在UBOOT_CONFIGS中添加stm32mp15_emtime_trusted_defconfig,trusted,u-boot.stm32
- 在DEVICE_TREE中添加stm32mp157a-emtime
然后进行编译即可:
1 | make distclean |
可以通过 cat error.log 查看编译错误,如果编译成功,那么会在 ../build-trusted 目录下会生成对应的文件,比如我们这里就是如下图框住的 u-boot-stm32mp157a-emtime-trusted.stm32 文件;

使用 sudo dd if=../build-trusted/u-boot-stm32mp157a-emtime-trusted.stm32 of=/dev/sdXY bs=1024 seek=8 conv=fsync,notrunc 命令将生成的文件烧录到 SD 卡中,然后就可以正常引导了;
未完待续…