1. 驱动开发环境搭建:Linux内核源码获取、交叉编译工具链配置、最小系统编译与烧录
做嵌入式驱动开发,第一件事不是写代码,而是把环境搭好。我见过太多新手卡在环境上,代码写好了却编译不过,或者烧进去系统起不来。说白了,环境搭建就像打地基,地基不稳,后面全是坑。
这一章,我带你把整个流程走一遍。从内核源码怎么拿,到交叉编译工具链怎么配,再到最小系统怎么编译、怎么烧到板子上。每一步我都会说说我踩过的坑,你照着做就行。
1.1 整体流程概览
先看一张图,把整件事串起来。你心里有个谱,后面每一步都知道自己在干什么。
1.2 获取Linux内核源码
内核源码怎么拿?两种主流方式:
- 从官方仓库git clone:适合长期开发,方便切换分支和打补丁
- 下载稳定版tar包:适合快速上手,不用等git拉取历史
我个人习惯用git clone,因为后面调试驱动时经常需要查内核源码的历史提交。你想想看,一个bug查了两天,最后发现是内核某次提交引入的——这时候git blame就救命了。
具体操作:
# 方式一:git clone(推荐)
git clone --depth=1 -b linux-5.10.y \
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
# 方式二:下载tar包
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.200.tar.xz
tar -xf linux-5.10.200.tar.xz
--depth=1 这个参数我特别提一下。它只拉取最新一次提交,不下载完整历史。我第一次没加这个参数,等了快半小时才下完。加上它,几秒钟就搞定了。
1.3 配置交叉编译工具链
交叉编译,说白了就是在你的x86电脑上编译出ARM架构能运行的二进制文件。你不可能在板子上直接编译内核——那得等到天荒地老。
工具链的选择,我列个表给你参考:
| 工具链 | 适用平台 | 安装方式 | 我的评价 |
|---|---|---|---|
| arm-linux-gnueabihf- | Cortex-A系列(如IMX6ULL、STM32MP1) | apt install / 源码编译 | 最常用,资料最多 |
| aarch64-linux-gnu- | ARM64位(如树莓派3B+、RK3399) | apt install / 官方下载 | 64位首选 |
| arm-none-eabi- | Cortex-M裸机(如STM32F4) | ARM官网下载 | 不带Linux,别搞混 |
安装步骤(以Ubuntu 22.04为例):
# 安装ARM32位交叉编译工具链
sudo apt update
sudo apt install gcc-arm-linux-gnueabihf
# 验证安装
arm-linux-gnueabihf-gcc --version
# 设置环境变量(写入 ~/.bashrc 永久生效)
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
环境变量设好之后,你编译内核时就不用每次都敲一长串参数了。我习惯把这两行写到 ~/.bashrc 里,source一下,一劳永逸。
1.4 编译最小系统
环境搭好了,接下来编译三样东西:内核、设备树、根文件系统。这三样凑齐了,你的板子就能跑起来。
1.4.1 编译内核与设备树
先进入内核源码目录,配置一下:
cd linux-5.10.200
# 使用默认配置(以IMX6ULL为例)
make imx_v7_defconfig
# 或者手动配置
make menuconfig
make menuconfig 这个界面你以后会经常打交道。它是个图形化的配置菜单,你可以在这里打开或关闭内核功能。比如你要加一个I2C驱动,就在 Device Drivers → I2C support 里勾上。
配置好之后,开始编译:
# 编译内核镜像
make zImage -j4
# 编译设备树
make dtbs -j4
-j4 表示用4个线程并行编译。我建议你设成CPU核心数的1.5倍左右。比如4核CPU就用 -j6,编译速度能快不少。
编译完成后,在 arch/arm/boot/ 下会生成 zImage,在 arch/arm/boot/dts/ 下会生成 .dtb 文件。这两个就是你要烧录的东西。
imx6ull-14x14-evk.dtb。如果你用错了设备树,内核启动时会卡在"Unsupported device tree"或者直接黑屏。我刚开始就犯过这个错,折腾了一下午才发现是dtb文件搞错了。
1.4.2 制作根文件系统
根文件系统,说白了就是板子启动后能看到的 / 目录。里面要有 /bin、/sbin、/etc 这些基本目录,还要有 init 程序。
最快的方式是用Busybox:
# 下载Busybox
wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2
tar -xf busybox-1.36.0.tar.bz2
cd busybox-1.36.0
# 配置
make menuconfig
# 在 Settings → Build static binary (no shared libs) 勾上
# 这样编译出来的二进制是静态链接的,不依赖动态库
# 编译并安装
make -j4
make install
# 安装后会生成 _install 目录
# 把它做成根文件系统镜像
cd _install
mkdir proc sys dev etc etc/init.d
# 创建最简单的 init 脚本
cat > etc/init.d/rcS << EOF
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Hello from embedded Linux!"
EOF
chmod +x etc/init.d/rcS
然后打包成镜像:
# 制作ext4格式的根文件系统镜像
dd if=/dev/zero of=rootfs.ext4 bs=1M count=64
mkfs.ext4 rootfs.ext4
mkdir /tmp/rootfs
sudo mount -o loop rootfs.ext4 /tmp/rootfs
sudo cp -r _install/* /tmp/rootfs/
sudo umount /tmp/rootfs
这样你就得到了一个64MB的 rootfs.ext4 镜像。虽然简陋,但足够让板子启动到shell了。
1.5 烧录与启动验证
烧录方式取决于你的板子。我以最常用的SD卡启动为例:
# 假设SD卡设备是 /dev/sdb(用 lsblk 确认)
# 先分区:一个FAT分区放内核和设备树,一个ext4分区放根文件系统
# 格式化FAT分区
sudo mkfs.vfat /dev/sdb1
# 复制内核和设备树
sudo mount /dev/sdb1 /mnt
sudo cp arch/arm/boot/zImage /mnt/
sudo cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /mnt/
sudo umount /mnt
# 烧录根文件系统到第二个分区
sudo dd if=rootfs.ext4 of=/dev/sdb2 bs=1M status=progress
lsblk 确认三次设备名。我曾经有一次把 /dev/sda(我的系统盘)当成SD卡写了进去……嗯,那次之后我养成了拔掉所有不相关USB设备的习惯。
烧录完成后,把SD卡插到板子上,上电。串口终端应该能看到内核启动日志:
U-Boot 2020.04
...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.10.200
...
[ 1.234567] VFS: Mounted root (ext4 filesystem) on device 179:2.
[ 1.345678] Freeing unused kernel memory: 1024K
[ 1.456789] Run /sbin/init as init process
Hello from embedded Linux!
/ #
看到这个 / # 提示符,恭喜你,最小系统跑起来了。你现在可以敲 ls、cat /proc/cpuinfo 这些命令,验证系统是否正常。
1.6 常见问题与避坑
- 编译报错"arm-linux-gnueabihf-gcc: not found":工具链没装或者环境变量没设。检查
echo $CROSS_COMPILE是否为空。 - 启动卡在"Starting kernel ...":设备树不匹配或者内核配置不对。先确认dtb文件名和板子型号一致。
- 根文件系统挂载失败"VFS: Unable to mount root fs":内核没有编译对应文件系统的支持。比如你用ext4,但内核没开
CONFIG_EXT4_FS。 - 串口没有输出:检查串口波特率、接线、以及内核的早期串口打印是否开启(
CONFIG_DEBUG_LL和CONFIG_EARLY_PRINTK)。
环境搭建这一步,说白了就是耐心活。我第一次搭环境用了整整两天,各种报错。但只要你每一步都验证通过,后面写驱动的时候就会特别顺畅。别急,慢慢来。