1.STM32MP135入门级环境搭建

一、这套环境中一共有四个“系统”

Windows 主机
    ↓ 运行 VMware
Ubuntu 虚拟机
    ↓ 编译 ARM Linux 内核
STM32MP135 开发板 Linux
    ↓ 把新内核保存到 eMMC
STM32MP135 U-Boot
    ↓ 把新内核加载到 DDR 并启动

它们的作用不同:

环境

提示符或界面

作用

Windows

文件资源管理器、PowerShell、VMware

保存资料、运行虚拟机、运行TFTP服务器

Ubuntu虚拟机

wwj@wwj-virtual-machine:~$

解压源码、交叉编译内核

开发板Linux

[root@ATK-DLMP135 /]#

接收新内核、写入eMMC boot分区

U-Boot

STM32MP>

加载、校验并启动新内核

最容易混淆的是:

Ubuntu虚拟机 ≠ STM32MP135开发板Linux

Ubuntu运行在你的电脑上,CPU通常是x86-64。

STM32MP135运行的是ARM架构,所以Ubuntu不能直接用普通gcc编译,必须使用ARM交叉编译器。


二、虚拟机到底是什么

VMware在Windows里模拟了一台独立电脑,包括:

虚拟CPU
虚拟内存
虚拟硬盘
虚拟网卡
虚拟显示器

你当前虚拟机配置大致是:

Ubuntu 18.04
内存:8GB
处理器:2核
虚拟硬盘:20GB
网络:NAT

Ubuntu虽然运行在Windows里,但它拥有自己的:

文件系统
IP地址
终端
软件包
用户账户
编译环境

所以在Ubuntu中执行:

pwd
ls
cd
make
gcc

与真实Linux电脑基本一样。


三、为什么要使用Ubuntu虚拟机

Linux内核源码依赖很多Linux特性:

GNU Make
Shell脚本
符号链接
Linux文件权限
文件名大小写
交叉编译工具链
设备树编译器

所以不适合直接在Windows文件系统里编译。

Ubuntu虚拟机的主要用途就是:

Windows保存原始资料
        ↓
共享给Ubuntu
        ↓
Ubuntu在Linux文件系统中解压和编译
        ↓
生成uImage、DTB和.ko模块

四、我们首先解决了虚拟机网络

最初虚拟机不能联网,后来确认网卡为:

ens33

获取到地址:

192.168.88.170/24

查看网卡命令:

ip -br addr

作用:

简洁显示所有网卡、状态和IP地址。

你看到:

ens33 UP 192.168.88.170/24

说明虚拟网卡已启用并获取IP。


查看路由

ip route

输出中有:

default via 192.168.88.2 dev ens33

作用:

查看Ubuntu访问其他网段和互联网时走哪个网关。

其中:

192.168.88.2

是VMware NAT网关。


测试网络

正确命令是:

ping -c 4 8.8.8.8

参数含义:

ping     测试网络连通性
-c 4     发送4个数据包
8.8.8.8 目标IP

之前输入过:

ping -c 4.8.8.8

这是错误的,因为-c后面应该先写次数。

不过后来执行:

sudo apt update

成功下载了软件包索引,说明网络已经正常。

apt update的作用是:

从Ubuntu软件源更新可安装软件的软件包列表。

它不会直接升级整个系统。


五、安装了open-vm-tools

执行过:

sudo apt install -y open-vm-tools open-vm-tools-desktop

两个软件包的作用:

open-vm-tools
提供Ubuntu与VMware之间的后台通信

open-vm-tools-desktop
提供桌面复制粘贴、分辨率适配、共享文件夹等功能

检查版本:

vmtoolsd --version

你得到:

VMware Tools daemon, version 10.3.23.676

检查服务:

systemctl is-active open-vm-tools.service

输出:

active

查看详细状态:

systemctl status open-vm-tools.service --no-pager

显示:

Active: active (running)

说明安装和运行都正常。

之前使用:

systemctl is-active open-vm-tool

少写了最后的s,所以错误显示为inactive


六、处理中途出现的apt锁问题

安装软件时曾出现:

无法获得锁 /var/lib/dpkg/lock-frontend

原因是Ubuntu后台自动更新程序占用软件包管理器。

查看是谁占用:

sudo fuser -v /var/lib/dpkg/lock-frontend

发现进程:

unattended-upgr

这表示Ubuntu自动更新服务正在使用apt/dpkg

之后停止相关进程或等待锁释放,再重新执行安装。

这里的经验是:

不要看到锁文件就直接删除。必须先确认是否有apt或dpkg进程正在运行。


七、配置了Windows和Ubuntu共享文件夹

Windows共享目录是:

D:\2@WWJ\MP135_SHARE

Ubuntu中挂载为:

/mnt/hgfs/MP135_SHARE

查看共享文件夹:

ls /mnt/hgfs

输出:

MP135_SHARE

查看里面文件:

ls -lh /mnt/hgfs/MP135_SHARE

你已经确认里面有:

linux-5.15.24-g291bfd5bc-v1.2.tar.bz2
gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz
atk-dlmp135-sdk-buildroot...
atk-dlmp135-toolchain...

其中当前编译内核主要使用:

linux-5.15.24-g291bfd5bc-v1.2.tar.bz2
gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz

八、为什么不能直接在共享目录编译

/mnt/hgfs实际上还是Windows文件系统映射。

直接在这里编译可能出现:

权限异常
符号链接异常
文件名大小写问题
编译速度慢
时间戳异常

所以我们创建了Ubuntu本地工作目录:

mkdir -p ~/mp135

其中:

~

表示当前用户的主目录:

/home/wwj

所以:

~/mp135

实际是:

/home/wwj/mp135

九、安装了ARM交叉编译工具链

STM32MP135使用ARM Cortex-A7,Ubuntu电脑通常是x86-64,因此需要交叉编译。

交叉编译器文件:

gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz

解压后放在:

/home/wwj/toolchains/

加入环境变量:

export PATH=$HOME/toolchains/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin:$PATH

作用:

告诉Shell去这个目录中查找编译器命令。

检查编译器位置:

which arm-none-linux-gnueabihf-gcc

输出类似:

/home/wwj/toolchains/.../bin/arm-none-linux-gnueabihf-gcc

检查版本:

arm-none-linux-gnueabihf-gcc --version

输出:

arm-none-linux-gnueabihf-gcc 10.3.1

说明交叉编译器安装成功。


永久保存PATH

执行:

echo 'export PATH=$HOME/toolchains/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin:$PATH' >> ~/.bashrc

作用:

把环境变量配置追加到用户Shell启动文件中。

再执行:

source ~/.bashrc

作用:

不重启终端,立即重新加载.bashrc配置。

以后每次打开Ubuntu终端,都能直接使用:

arm-none-linux-gnueabihf-gcc

十、解压了Linux内核源码

先创建目录:

mkdir -p ~/mp135/src

作用:

创建内核源码存放目录;如果上级目录不存在,也一并创建。

解压:

tar -xjf \
~/mp135/linux-5.15.24-g291bfd5bc-v1.2.tar.bz2 \
-C ~/mp135/src

参数含义:

tar    压缩包工具
-x     解压
-j     使用bzip2格式
-f     后面指定压缩包文件
-C     解压到指定目录

源码最终位于类似:

/home/wwj/mp135/src/linux-5.15.24-g291bfd5bc-v1.2/linux-5.15.24

或者你当前实际进入的是:

/home/wwj/mp135/src/linux-5.15.24

判断标准是目录中存在:

arch/
drivers/
include/
kernel/
net/
scripts/
Makefile
Kconfig

十一、查找了正点原子默认配置文件

执行过:

DEFCONFIG=$(find ~/mp135/src \
-path '*/arch/arm/configs/stm32mp1_atk_defconfig' \
| head -n 1)

这条命令分为几部分:

find ~/mp135/src
在源码目录中搜索文件

-path '*/arch/arm/configs/stm32mp1_atk_defconfig'
只匹配这个具体路径

head -n 1
如果找到多个,只取第一个

DEFCONFIG=$(...)
把结果保存到变量DEFCONFIG

查看变量应该使用:

echo "$DEFCONFIG"

查看文件:

ls -lh "$DEFCONFIG"

之前误输入:

$DEFCONFIG

Shell就把路径当成程序运行,所以提示:

权限不够

这个配置文件不是程序,不应该直接执行。


十二、进入Linux内核源码根目录

通过配置文件路径计算源码目录:

SRC_DIR="${DEFCONFIG%/arch/arm/configs/stm32mp1_atk_defconfig}"

作用:

从完整配置文件路径中删除后面的固定部分,只保留Linux内核源码根目录。

然后进入:

cd "$SRC_DIR"

查看当前位置:

pwd

查看文件:

ls

十三、设置内核编译目标

执行:

export ARCH=arm

作用:

告诉Linux内核构建系统,目标架构是32位ARM。

执行:

export CROSS_COMPILE=arm-none-linux-gnueabihf-

作用:

告诉内核构建系统,所有交叉编译工具使用这个前缀。

例如:

gcc    → arm-none-linux-gnueabihf-gcc
ld     → arm-none-linux-gnueabihf-ld
objcopy→ arm-none-linux-gnueabihf-objcopy

检查:

echo "$ARCH"
echo "$CROSS_COMPILE"

应该分别显示:

arm
arm-none-linux-gnueabihf-

十四、创建独立输出目录

执行:

mkdir -p out

作用:

把编译结果放到out目录,而不是直接混在源码目录里。

好处:

源码保持干净
方便清理
方便比较
方便重新编译

十五、生成内核配置

执行:

make O=out stm32mp1_atk_defconfig

它的作用是:

读取:
arch/arm/configs/stm32mp1_atk_defconfig

生成:
out/.config

stm32mp1_atk_defconfig是正点原子为该开发板准备的默认配置。

配置中决定:

哪些驱动编进内核
哪些驱动编成.ko模块
哪些功能关闭
是否启用I2C、CAN、网卡、USB等

你已经看到:

configuration written to .config

这说明配置生成成功。

由于使用了:

O=out

真正生成的文件是:

out/.config

检查命令:

ls -lh out/.config

十六、这里曾经出现的误操作

你输入过:

arch/arm/configs/stm32mp1_atk_defconfig

Shell提示:

权限不够

原因是它是配置文本,不是程序。

又输入过:

chomd 777 ...

这里有两个问题:

chomd拼写错误,正确是chmod
但即使拼写正确,这里也不需要修改权限

还输入过:

stm32mp1_atk_defconfig

Shell提示:

未找到命令

因为它只能作为make的目标使用:

make O=out stm32mp1_atk_defconfig

不能单独运行。


十七、下一步真正的内核编译命令

当前配置已经生成,接下来执行:

make ARCH=arm \
CROSS_COMPILE=arm-none-linux-gnueabihf- \
O=out \
LOADADDR=0xC2000040 \
-j2 \
uImage vmlinux dtbs modules

也建议保存完整日志:

make ARCH=arm \
CROSS_COMPILE=arm-none-linux-gnueabihf- \
O=out \
LOADADDR=0xC2000040 \
-j2 \
uImage vmlinux dtbs modules \
2>&1 | tee build.log

参数作用:

参数

含义

ARCH=arm

目标是32位ARM

CROSS_COMPILE=...

使用ARM交叉编译器

O=out

编译结果放在out目录

LOADADDR=0xC2000040

设置uImage内部内核加载地址

-j2

使用两个并行编译任务

uImage

生成U-Boot使用的内核镜像

vmlinux

生成带调试符号的内核ELF

dtbs

编译设备树

modules

编译配置为模块的驱动

2>&1

把错误输出合并到标准输出

tee build.log

屏幕显示的同时保存到日志

编译过程中会出现:

CC
LD
AR
DTC
MODPOST

分别表示:

CC       编译C源文件
LD       链接文件
AR       生成静态目标集合
DTC      编译设备树
MODPOST  处理内核模块信息

十八、编译完成后会生成什么

1. Linux内核

out/arch/arm/boot/uImage

这是开发板U-Boot加载的内核。

检查:

ls -lh out/arch/arm/boot/uImage

2. 原始压缩内核

out/arch/arm/boot/zImage

uImage通常可以理解为:

U-Boot头部
+
zImage

你的STM32MP135原厂启动流程使用:

uImage + bootm

3. 设备树

out/arch/arm/boot/dts/*.dtb

查找命令:

find out/arch/arm/boot/dts \
-name "stm32mp135d-atk*.dtb"

可能包括:

stm32mp135d-atk.dtb
stm32mp135d-atk-hdmi.dtb
stm32mp135d-atk-wifi-bluetooth.dtb

4. 内核模块

后缀是:

.ko

查找:

find out -type f -name "*.ko" | head -n 20

5. 调试文件

out/vmlinux

它包含符号信息,主要用于:

GDB调试
崩溃地址分析
addr2line定位

它不是直接给开发板启动使用的文件。


十九、如何检查生成的uImage

执行:

mkimage -l out/arch/arm/boot/uImage

作用:

读取uImage头部信息。

正常应显示:

Image Type: ARM Linux Kernel Image
Load Address: c2000040
Entry Point: c2000040

计算MD5:

md5sum out/arch/arm/boot/uImage

作用:

生成文件校验值,后面传输到Windows和开发板后用于比较。


二十、为什么要把文件命名为uImage.test

编译成功后执行:

cp out/arch/arm/boot/uImage ~/mp135/uImage.test

我们不直接覆盖原厂文件,而是命名为:

uImage.test

这样开发板中可以同时保存:

uImage       原厂内核
uImage.test  新测试内核

如果新内核不能启动,重新上电仍可自动运行旧的uImage


二十一、将新内核复制回Windows

执行:

cp ~/mp135/uImage.test /mnt/hgfs/MP135_SHARE/
sync

Windows中就会看到:

D:\2@WWJ\MP135_SHARE\uImage.test

这里:

sync

作用是:

把系统缓存中的文件数据真正写入存储设备或共享目录。


二十二、之后怎样传到开发板

Windows运行Tftpd64,并把:

uImage.test

放在TFTP目录中。

开发板Linux配置网口:

ifconfig eth1 down
ifconfig eth1 192.168.10.50 netmask 255.255.255.0 up

Windows有线网卡:

192.168.10.100

测试:

ping -c 4 192.168.10.100

下载:

busybox tftp -g \
-r uImage.test \
-l /tmp/uImage.test \
192.168.10.100

参数含义:

-g
下载文件

-r uImage.test
TFTP服务器中的远端文件名

-l /tmp/uImage.test
开发板上的保存路径

192.168.10.100
Windows TFTP服务器IP

检查:

ls -lh /tmp/uImage.test
md5sum /tmp/uImage.test

MD5必须和Ubuntu中的一致。


二十三、怎样写入开发板eMMC

你的开发板中:

/dev/mmcblk1p4

挂载到了:

/lib/modules

所以复制:

cp /tmp/uImage.test /lib/modules/uImage.test.tmp
sync

然后检查:

md5sum /lib/modules/uImage.test.tmp

无误后改名:

mv /lib/modules/uImage.test.tmp /lib/modules/uImage.test
sync

这样实际就是把新内核写入:

eMMC第4分区boot

Linux中看到:

/lib/modules/uImage.test

U-Boot中看到的是:

mmc 1:4 /uImage.test

它们是同一个文件。


二十四、U-Boot如何测试新内核

开发板Linux执行:

sync
reboot

重启时按回车进入:

STM32MP>

先查看:

ext4ls mmc 1:4 /

加载新内核:

ext4load mmc 1:4 ${kernel_addr_r} /uImage.test

含义:

eMMC第4分区/uImage.test
        ↓
加载到DDR的kernel_addr_r地址

你的地址是:

kernel_addr_r=0xC2000000

检查镜像:

iminfo ${kernel_addr_r}

必须看到:

Verifying Checksum ... OK

加载原设备树:

ext4load mmc 1:4 ${fdt_addr_r} /stm32mp135d-atk.dtb

加载原uInitrd:

ext4load mmc 1:4 ${ramdisk_addr_r} /uInitrd

设置启动参数:

setenv bootargs 'root=/dev/mmcblk1p5 rootwait rw console=ttySTM0,115200'

启动:

bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}

不要执行:

saveenv

因为当前只是临时测试。


二十五、新内核启动后怎样确认

启动完成进入:

[root@ATK-DLMP135 /]#

执行:

uname -a

作用:

查看当前运行内核版本、架构和编译信息。

再执行:

cat /proc/version

作用:

查看详细内核版本、编译器和编译时间。

原内核编译日期是2023年,新编译内核应显示新的编译日期。

检查驱动:

dmesg | grep -Ei "i2c|stm32f7-i2c"
dmesg | grep -Ei "can|m_can"
dmesg | grep -Ei "eth|phy|dwmac"

二十六、当前已经完成到哪里

目前已经完成:

1. VMware虚拟机可以正常启动
2. Ubuntu网络已经恢复
3. apt软件源可以正常访问
4. open-vm-tools安装并运行正常
5. Windows共享目录已经挂载
6. ARM 10.3.1交叉编译器已经安装
7. PATH环境变量已经保存
8. Linux 5.15.24源码已经解压
9. 已找到stm32mp1_atk_defconfig
10. 已成功生成out/.config

目前还没有最终确认完成的是:

完整编译uImage、DTB和modules
将新内核传到开发板
在U-Boot中启动测试内核
正式替换原内核

二十七、你现在接着执行的命令

当前位于内核源码根目录时,先检查:

ls -lh out/.config

然后执行完整编译:

make ARCH=arm \
CROSS_COMPILE=arm-none-linux-gnueabihf- \
O=out \
LOADADDR=0xC2000040 \
-j2 \
uImage vmlinux dtbs modules \
2>&1 | tee build.log

编译成功后执行:

ls -lh out/arch/arm/boot/uImage
mkimage -l out/arch/arm/boot/uImage
md5sum out/arch/arm/boot/uImage
find out/arch/arm/boot/dts -name "stm32mp135d-atk*.dtb"

整个流程最核心的一句话是:

Windows负责保存和传输
Ubuntu负责交叉编译
开发板Linux负责写入eMMC
U-Boot负责加载和启动新内核

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐