2. STM32MP开发环境搭建与启动链验证

STM32MP1 系列(如 STM32MP157、STM32MP135)与常见的“裸机 MCU”开发体验差异很大:它是一颗带 Cortex-A7 应用核 + Cortex-M4 实时核的异构处理器,Linux 运行在 A7 上,而启动过程要经过 ROM Code → TF-A → U-Boot → Linux Kernel 多级接力。因此,开发环境搭建的目标不是“装好一个 IDE”,而是建立一条可编译、可烧录、可观察、可回读的完整链路。本节围绕交叉编译工具链、OpenSTLinux SDK、STM32CubeProgrammer、串口与网络连接,以及 TF-A/U-Boot/Kernel 启动日志解读展开。

一、交叉编译工具链:为什么不能在本机直接 gcc

STM32MP1 的 A7 核运行 ARMv7-A 指令集,而开发主机通常是 x86_64。若直接用主机 gcc 编译,生成的是 x86 目标文件,无法在板端执行。交叉编译工具链的本质,是在 x86_64 主机上运行、但产出 ARM 目标代码的编译器集合,包含 arm-ostl-linux-gnueabi-gcc、ld、objcopy、gdb 等。

ST 官方推荐使用 OpenSTLinux 提供的工具链,其命名遵循 <arch>-<vendor>-<os>-<abi> 规则。以 STM32MP15 为例,典型前缀为 arm-ostl-linux-gnueabi-。验证工具链是否可用,可执行:

$ arm-ostl-linux-gnueabi-gcc -v
Target: arm-ostl-linux-gnueabi
Thread model: posix
gcc version 12.2.0 (GCC)

$ arm-ostl-linux-gnueabi-gcc -mcpu=cortex-a7 \
    -mfloat-abi=hard -mfpu=neon-vfpv4 hello.c -o hello
$ file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 ...

这里 -mcpu=cortex-a7 指定目标核,-mfloat-abi=hard 与 -mfpu=neon-vfpv4 启用硬件浮点与 NEON,与 STM32MP15 的 A7 特性匹配。若编译出的 file 结果显示 x86-64,说明调用的是主机 gcc,需检查 PATH 与工具链前缀。

二、OpenSTLinux SDK:把工具链、sysroot 与库一次装齐

单独安装工具链容易遗漏目标根文件系统中的头文件与库(sysroot)。OpenSTLinux SDK 通过一个自解压安装脚本,把交叉工具链、目标 sysroot、环境初始化脚本打包在一起。典型流程如下:

$ chmod +x st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-*.sh
$ ./st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-*.sh
$ source /opt/st/stm32mp1/4.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
$ echo $CC
arm-ostl-linux-gnueabi-gcc -mcpu=cortex-a7 -mthumb ... --sysroot=...

执行 source environment-setup-* 后,CC、CXX、PKG_CONFIG_PATH 等变量被自动设置,后续用 $CC 编译即可自动带上正确的 sysroot 与浮点参数。这一步是很多“编译能过、运行报 No such file or directory”问题的根因——动态链接器路径或库版本不匹配。

三、STM32CubeProgrammer:把镜像写进 eMMC/SD 卡

STM32MP1 支持通过 USB DFU 或 UART 进入 ROM Code 的串行下载模式。STM32CubeProgrammer(CLI 为 STM32_Programmer_CLI)配合 FlashLayout.tsv 分区表,把 TF-A、U-Boot、Kernel、rootfs 等按分区写入。典型命令:

$ STM32_Programmer_CLI -c port=usb1 -w flashlayout.tsv
   Partition 0x01 : fsbl1   -> tf-a-stm32mp157f-dk2.stm32
   Partition 0x02 : fsbl2   -> tf-a-stm32mp157f-dk2.stm32
   Partition 0x03 : fip     -> fip-stm32mp157f-dk2-optee.bin
   Partition 0x04 : bootfs  -> bootfs.ext4
   Partition 0x05 : rootfs  -> rootfs.ext4

其中 fsbl1/fsbl2 是 TF-A 的双备份,fip 是 U-Boot 与 OP-TEE 的打包镜像,bootfs 存放内核与设备树,rootfs 是根文件系统。烧录前需把 BOOT 拨码开关置于“串行下载”位置,烧录完成后再拨回“eMMC/SD 启动”。

四、串口与网络:两条观察通道

串口是启动链验证的“第一现场”。STM32MP157 DK2 默认使用 UART4,参数为 115200 8N1,无流控。Linux 主机可用 minicom 或 picocom:

$ picocom -b 115200 -d 8 -p n /dev/ttyUSB0
$ ip addr add 192.168.7.1/24 dev usb0   # 板端 USB RNDIS/CDC 网口
$ ssh root@192.168.7.2

网络通道用于传输文件、远程登录与 NFS 挂载根文件系统。调试阶段建议同时保留串口与网络:串口看启动日志,网络传文件与跑测试。

STM32MP1 启动链与开发环境验证路径 开发主机 (x86_64) OpenSTLinux SDK 交叉工具链 + sysroot STM32CubeProgrammer 串口终端 / SSH / NFS STM32MP1 板端启动链 ROM Code BOOT0/BOOT1 TF-A (BL2) fsbl1 / fsbl2 U-Boot (FIP) + OP-TEE Kernel bootfs rootfs (ext4) → systemd/init → 用户空间 串口输出启动日志,网络提供文件传输与远程登录 USB DFU 启动日志关键判读点 TF-A 阶段 NOTICE: BL2: v2.8 NOTICE: BL2: Booting BL31 NOTICE: BL31: Entrypoint NOTICE: BL33: U-Boot 判读:BL2/BL31/BL33 是否依次出现 U-Boot 阶段 U-Boot 2022.10 Board: stm32mp157f-dk2 Loading Kernel from bootfs Starting kernel ... 判读:板型、加载地址、跳转内核 Kernel 阶段 Booting Linux on CPU0 mmc0: SDHCI at 58005000 EXT4-fs (mmcblk0p5) mounted systemd[1]: Reached target 判读:存储、根文件系统、init 是否就绪

五、启动日志解读:从“能打印”到“能判断”

串口上电后,日志按 TF-A → U-Boot → Kernel 顺序输出。TF-A 阶段关注 BL2、BL31、BL33 是否依次出现;若卡在 BL2 之前,通常是 BOOT 拨码、供电或 DDR 初始化问题。U-Boot 阶段关注板型识别、Loading Kernel 与 Starting kernel ...;若停在 Starting kernel 后无输出,多为设备树或内核镜像地址不匹配。Kernel 阶段关注存储控制器、根文件系统挂载与 init 进程;出现 Kernel panic - not syncing: VFS: Unable to mount root fs 时,应检查 bootargs 中的 root= 与分区号是否与 FlashLayout 一致。

建议把每次上电的完整串口日志保存为文件(如 boot-2024xxxx.log),出现异常时与上一次正常日志逐段对比,比反复猜测更快定位。

六、环境自检清单

检查项命令/现象通过判据
工具链arm-ostl-linux-gnueabi-gcc -vTarget 为 arm-ostl-linux-gnueabi
SDK 环境echo $CC含 --sysroot 与 cortex-a7 参数
烧录STM32_Programmer_CLI -c port=usb1识别到 DFU 设备与分区
串口picocom -b 115200 /dev/ttyUSB0上电可见 TF-A 日志
网络ssh root@192.168.7.2可登录并执行 uname -a

完成以上验证后,开发环境才算真正可用:主机能交叉编译,板端能启动到用户空间,串口与网络两条通道都能观察和干预。后续的内核裁剪、驱动调试与产品交付,都建立在这条已验证的启动链之上。