1. ARM Linux 驱动开发环境搭建
做 ARM Linux 驱动开发,第一件事就是把环境搭好。我见过不少新手,代码写得挺漂亮,结果卡在环境配置上,一卡就是好几天。说白了,环境就是你的工具箱——工具不称手,活就干不顺。
这一章,我们重点搞定三件事:交叉编译工具链、内核源码树、NFS 根文件系统挂载。这三样配齐了,你就能在 PC 上编译、在开发板上跑,调试效率翻倍。
1.1 交叉编译工具链配置
ARM 开发板和 PC 的 CPU 架构不同。PC 是 x86,ARM 板是 ARM。你不能直接在 PC 上编译出 ARM 能跑的程序——除非你用交叉编译。
交叉编译工具链,说白了就是一套能在 x86 上生成 ARM 可执行文件的工具集。里面包含编译器、链接器、库文件等等。
1.1.1 工具链的选择
市面上常见的 ARM 交叉编译工具链有几种:
| 工具链名称 | 适用场景 | 我的建议 |
|---|---|---|
| arm-linux-gnueabihf- | ARM Cortex-A 系列,硬件浮点 | 大多数 ARM 板首选 |
| arm-linux-gnueabi- | ARM Cortex-A 系列,软浮点 | 老内核或特殊板子用 |
| aarch64-linux-gnu- | ARM64 (Cortex-A53/A72 等) | 64 位 ARM 板必选 |
| arm-none-eabi- | 裸机开发,无操作系统 | 驱动开发一般不用 |
我个人习惯用 arm-linux-gnueabihf-。为什么?因为现在主流的 ARM 板(比如 i.MX6、AM335x、STM32MP1)都带硬件浮点单元,用 hf 版本性能更好。我在项目中遇到过有人用错工具链版本,结果内核启动到一半就崩了——查了两天才发现是浮点指令不兼容。
1.1.2 安装与验证
以 Ubuntu 系统为例,安装命令很简单:
sudo apt-get install gcc-arm-linux-gnueabihf
sudo apt-get install g++-arm-linux-gnueabihf
装完后验证一下:
arm-linux-gnueabihf-gcc --version
能看到版本号就说明装好了。嗯,这里要注意:有些教程会让你从 Linaro 官网下载压缩包手动解压。我个人觉得没必要——apt 源里的版本足够稳定,除非你有特殊需求。
export PATH=$PATH:/usr/bin 就行——其实 apt 安装的默认就在 /usr/bin,一般不用加。
1.1.3 测试编译
写个简单的 hello.c 试试:
#include <stdio.h>
int main() {
printf("Hello ARM Linux!\n");
return 0;
}
编译:
arm-linux-gnueabihf-gcc -o hello hello.c
用 file 命令看看生成的文件:
file hello
# 输出: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
看到 "ARM" 字样就对了。我曾经犯过一个低级错误——在 PC 上直接跑这个 hello 文件,结果报 "cannot execute binary file"。废话,ARM 的程序在 x86 上当然跑不了。
1.2 内核源码树构建
驱动开发离不开内核源码。你写的驱动模块,需要依赖内核头文件和编译规则。所以你得先有一套完整的内核源码树。
1.2.1 获取内核源码
有两种方式:
- 从 kernel.org 下载主线内核:版本新,但可能和你的板子不完全匹配
- 从芯片厂商获取 BSP 内核:比如 NXP 的 Linux BSP、TI 的 Processor SDK——这些是定制好的,开箱即用
我建议新手直接用厂商的 BSP。为什么?因为主线内核需要你自己打补丁、配设备树,厂商 BSP 已经帮你做好了。我在项目中用过几次主线内核,每次都要花一两天适配板级支持,得不偿失。
以 NXP i.MX6 为例,下载 BSP 后解压:
tar -xvf linux-imx.tar.bz2
cd linux-imx
1.2.2 配置内核
内核配置有三种方式:
| 命令 | 说明 | 适用场景 |
|---|---|---|
| make menuconfig | 文本菜单界面 | 最常用,推荐 |
| make xconfig | 图形界面 | 需要 Qt 库,不常用 |
| make defconfig | 默认配置 | 快速开始,但可能缺模块 |
我个人习惯用 make menuconfig。先加载厂商的默认配置:
make ARCH=arm imx_v7_defconfig
make ARCH=arm menuconfig
在 menuconfig 里,你可以按需开关驱动模块。比如你要写一个 I2C 驱动,就确保 Device Drivers → I2C support 是选中的。
ARCH=arm 这个参数不能少。我见过有人忘了指定架构,结果编译出来的内核是 x86 的——烧到板子上当然起不来。
1.2.3 编译内核
配置好之后,开始编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 modules
-j4 表示用 4 个线程并行编译,能快不少。编译完成后,在 arch/arm/boot/ 下会生成 zImage——这就是我们要的内核镜像。
编译内核模块:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=./modules
模块会安装到 ./modules 目录下,后面挂载 NFS 时会用到。
1.3 NFS 根文件系统挂载
驱动开发最烦什么?反复烧写文件系统。每次改个驱动都要重新烧写、重启,一天下来大半时间都在等。NFS 挂载能解决这个问题——开发板通过网络,把 PC 上的目录当作根文件系统来用。
1.3.1 为什么用 NFS
你想想看,传统方式是这样的:
- 在 PC 上编译驱动
- 把驱动拷贝到 SD 卡或烧写到 Flash
- 插卡、重启开发板
- 测试、发现问题
- 回到第 1 步
用 NFS 之后:
- 在 PC 上编译驱动
- 驱动直接出现在开发板的文件系统里
- 立即测试
省掉了烧写和重启的步骤。我在项目中用过 NFS 之后,就再也不想回到烧写模式了——效率提升不是一点半点。
1.3.2 搭建 NFS 服务器
在 PC 上安装 NFS 服务器:
sudo apt-get install nfs-kernel-server
创建一个目录作为根文件系统的导出点:
sudo mkdir -p /srv/nfs/rootfs
把你之前编译好的根文件系统(比如用 Buildroot 或 Yocto 生成的)解压到这个目录:
sudo tar -xvf rootfs.tar -C /srv/nfs/rootfs
配置 NFS 导出:编辑 /etc/exports,添加一行:
/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)
参数说明:
rw:读写权限sync:同步写入,保证数据一致性no_subtree_check:禁用子树检查,提高性能no_root_squash:允许开发板以 root 权限访问——这个很重要,驱动开发经常需要 root 权限
重启 NFS 服务:
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
sudo mount -t nfs localhost:/srv/nfs/rootfs /mnt。能成功就说明 NFS 服务器没问题。
1.3.3 配置开发板启动参数
开发板通过 U-Boot 启动时,需要告诉内核用 NFS 作为根文件系统。在 U-Boot 命令行中设置:
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs ip=192.168.1.10:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off'
saveenv
boot
参数拆解:
root=/dev/nfs:告诉内核使用 NFS 根文件系统nfsroot=192.168.1.100:/srv/nfs/rootfs:NFS 服务器 IP 和导出路径ip=192.168.1.10:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off:开发板 IP、服务器 IP、网关、掩码
嗯,这里要注意:IP 地址要和你 PC 的网络环境匹配。我建议用静态 IP,别用 DHCP——万一 DHCP 分配了不同的 IP,NFS 就挂不上了。
1.3.4 常见问题排查
我曾经遇到过 NFS 挂载失败,卡在 "VFS: Unable to mount root fs" 的错误。排查步骤:
- 先确认网络通不通——在 U-Boot 里 ping 一下 PC 的 IP
- 检查 PC 的防火墙——有时候防火墙会拦截 NFS 端口
- 确认 /etc/exports 配置正确——特别是 no_root_squash 有没有加
- 查看 PC 上的 NFS 日志:
sudo tail -f /var/log/syslog
大部分问题都是网络或权限导致的,按这个顺序查,基本都能解决。
1.4 本章知识体系
下面这张图把本章的核心逻辑串起来了:
核心要点:
- 交叉编译工具链选 arm-linux-gnueabihf-,匹配硬件浮点
- 内核源码用厂商 BSP,省去适配时间
- NFS 挂载是驱动开发调试的利器,必须掌握