1.STM32MP135入门级环境搭建
1.STM32MP135入门级环境搭建
一、这套环境中一共有四个“系统”
Windows 主机
↓ 运行 VMware
Ubuntu 虚拟机
↓ 编译 ARM Linux 内核
STM32MP135 开发板 Linux
↓ 把新内核保存到 eMMC
STM32MP135 U-Boot
↓ 把新内核加载到 DDR 并启动
它们的作用不同:
|
环境 |
提示符或界面 |
作用 |
|
Windows |
文件资源管理器、PowerShell、VMware |
保存资料、运行虚拟机、运行TFTP服务器 |
|
Ubuntu虚拟机 |
|
解压源码、交叉编译内核 |
|
开发板Linux |
|
接收新内核、写入eMMC boot分区 |
|
U-Boot |
|
加载、校验并启动新内核 |
最容易混淆的是:
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
参数作用:
|
参数 |
含义 |
|
|
目标是32位ARM |
|
|
使用ARM交叉编译器 |
|
|
编译结果放在out目录 |
|
|
设置uImage内部内核加载地址 |
|
|
使用两个并行编译任务 |
|
|
生成U-Boot使用的内核镜像 |
|
|
生成带调试符号的内核ELF |
|
|
编译设备树 |
|
|
编译配置为模块的驱动 |
|
|
把错误输出合并到标准输出 |
|
|
屏幕显示的同时保存到日志 |
编译过程中会出现:
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负责加载和启动新内核
更多推荐

所有评论(0)