3. 开发环境搭建:交叉编译工具链配置、TFTP/NFS 网络启动环境搭建
说实话,嵌入式开发的第一步往往最劝退。很多新手拿着开发板,第一周全耗在「环境没配好,代码跑不起来」上。我自己带团队时,新人入职第一件事就是搭环境——不是折腾他们,而是这步不过关,后面全是白费。
这一章,咱们就把交叉编译工具链、TFTP 和 NFS 这三个核心工具彻底搞定。你跟着我的步骤走,半小时内应该能跑通第一个网络启动。
3.1 交叉编译工具链:为什么非它不可?
你的 PC 是 x86 架构,开发板是 ARM(或 RISC-V、MIPS)。PC 上编译出的程序,开发板不认识。反过来也一样。所以我们需要一个「翻译官」——交叉编译工具链。
说白了,就是在 PC 上运行一个编译器,它生成的目标代码是开发板 CPU 能执行的指令。
3.1.1 工具链的三大件
| 组件 | 典型名称 | 作用 |
|---|---|---|
| 编译器 | arm-linux-gnueabihf-gcc | 将 C 源码编译为 ARM 机器码 |
| 链接器 | arm-linux-gnueabihf-ld | 将目标文件链接成可执行文件 |
| 调试器 | arm-linux-gnueabihf-gdb | 在 PC 上远程调试开发板程序 |
我习惯用 arm-linux-gnueabihf- 这个前缀。它代表:目标架构 ARM、Linux 系统、支持硬浮点。如果你的板子是 Cortex-A 系列,这个基本通用。
3.1.2 两种获取方式
方式一:从芯片厂商获取预编译包
这是最省事的。NXP、TI、Rockchip 都会提供官方工具链。比如 NXP 的 gcc-arm-none-eabi-* 系列。直接解压,配置 PATH 即可。
方式二:从 Linaro 或 ARM 官方下载
如果你用的 SoC 比较新,或者厂商没提供,可以去 Linaro 官网下载。命令如下:
# 下载 ARM 64位工具链(以 gcc-12.2 为例)
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到 /opt 目录
sudo tar -xvf gcc-linaro-*.tar.xz -C /opt/
# 配置环境变量(写入 ~/.bashrc)
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
# 使配置生效
source ~/.bashrc
CROSS_COMPILE 和 ARCH 必须设置。U-Boot 和 Linux 内核的 Makefile 依赖这两个变量。我曾经忘记设 ARCH=arm,结果编译出来的 U-Boot 是 x86 格式,烧进去直接黑屏。
3.1.3 验证工具链是否可用
# 查看编译器版本
arm-linux-gnueabihf-gcc --version
# 编译一个简单测试程序
echo 'int main(){return 0;}' > test.c
arm-linux-gnueabihf-gcc -o test test.c
# 查看生成的文件类型
file test
# 输出应为:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
看到 ARM, EABI5 就对了。如果显示 x86-64,说明你用的还是本地 gcc,PATH 没生效。
3.2 TFTP 网络启动环境:让开发板从网络加载镜像
为什么要用 TFTP?你想想看,每次修改 U-Boot 或内核都要插拔 SD 卡、烧写 eMMC,多麻烦。网络启动只需在 PC 上改文件,开发板重启就能加载新镜像。调试效率提升 10 倍不止。
3.2.1 在 PC 上搭建 TFTP 服务器
我用的是 Ubuntu 22.04,其他发行版大同小异。
# 安装 TFTP 服务器
sudo apt-get update
sudo apt-get install tftpd-hpa
# 创建 TFTP 根目录
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp
# 修改配置文件 /etc/default/tftpd-hpa
sudo vim /etc/default/tftpd-hpa
配置文件内容如下:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create"
然后重启服务:
sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa
# 检查服务状态
sudo systemctl status tftpd-hpa
sudo ufw allow 69/udp 即可。
3.2.2 在 U-Boot 中配置 TFTP 启动
开发板上电,进入 U-Boot 命令行。设置以下环境变量:
# 设置开发板 IP(根据你的网络环境修改)
setenv ipaddr 192.168.1.100
# 设置服务器 IP(PC 的 IP)
setenv serverip 192.168.1.10
# 设置网关(可选)
setenv gatewayip 192.168.1.1
# 设置网络掩码
setenv netmask 255.255.255.0
# 保存环境变量
saveenv
测试网络连通性:
# Ping 服务器
ping 192.168.1.10
如果看到 host 192.168.1.10 is alive,说明网络通了。接下来就可以从 TFTP 加载镜像:
# 从 TFTP 下载 U-Boot 镜像到内存地址 0x42000000
tftp 0x42000000 u-boot.bin
# 从 TFTP 下载 Linux 内核
tftp 0x42000000 zImage
# 从 TFTP 下载设备树
tftp 0x43000000 imx6ull-14x14-evk.dtb
3.3 NFS 网络文件系统:让开发板共享 PC 的根文件系统
TFTP 解决了镜像加载问题,但调试应用程序时,每次都要重新烧写根文件系统,太慢了。NFS 可以让你在 PC 上修改文件,开发板直接通过网络访问,实时生效。
3.3.1 在 PC 上搭建 NFS 服务器
# 安装 NFS 服务器
sudo apt-get install nfs-kernel-server
# 创建共享目录(存放根文件系统)
sudo mkdir -p /srv/nfs/rootfs
# 将你的根文件系统解压到该目录
sudo tar -xvf rootfs.tar.gz -C /srv/nfs/rootfs
# 修改配置文件 /etc/exports
sudo vim /etc/exports
在 /etc/exports 中添加一行:
/srv/nfs/rootfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
参数说明:
rw:读写权限sync:同步写入,保证数据一致性no_subtree_check:提高性能no_root_squash:允许开发板以 root 权限访问,调试时很有用
重启 NFS 服务:
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
# 验证共享是否生效
showmount -e localhost
3.3.2 在 U-Boot 中配置 NFS 启动
U-Boot 启动内核时,通过 bootargs 参数告诉内核使用 NFS 根文件系统:
# 设置 NFS 启动参数
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.10:/srv/nfs/rootfs,v3,tcp ip=192.168.1.100:192.168.1.10:192.168.1.1:255.255.255.0::eth0:off'
# 完整的启动命令
setenv bootcmd 'tftp 0x42000000 zImage; tftp 0x43000000 imx6ull-14x14-evk.dtb; bootz 0x42000000 - 0x43000000'
# 保存并重启
saveenv
boot
nfsroot 参数中的路径必须与 /etc/exports 中配置的路径一致。另外,v3 协议兼容性最好,我遇到过 NFSv4 在某些老内核上挂载失败的情况。
3.4 整体流程:一张图看懂
下面这张图展示了开发板从加电到进入 NFS 根文件系统的完整流程:
3.5 常见问题与排查思路
环境搭好了,但第一次启动大概率会出问题。别慌,我列几个最常见的坑:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| TFTP 下载超时 | 防火墙未放行 UDP 69 端口 | sudo ufw allow 69/udp |
| TFTP 下载成功但内核不启动 | 内核镜像格式不对(如 uImage 与 zImage 混淆) | 检查 U-Boot 的 bootm 或 bootz 命令是否匹配 |
NFS 挂载失败:VFS: Unable to mount root fs |
内核未开启 NFS 客户端支持 | 重新编译内核,选中 CONFIG_NFS_FS=y |
NFS 挂载失败:Network is unreachable |
U-Boot 设置的 IP 与内核启动参数中的 IP 不一致 | 检查 bootargs 中的 ip= 参数 |
| 开发板能 ping 通 PC,但 TFTP 无响应 | TFTP 根目录权限不足 | sudo chmod 777 /srv/tftp |
我的调试习惯: 先确保 TFTP 能下载文件,再搞 NFS。TFTP 通了,说明网络层没问题。NFS 挂不上,多半是内核配置或 bootargs 写错了。别同时排查两个问题,逐个击破。
3.6 小结
这一章我们搞定了三件事:交叉编译工具链、TFTP 服务器、NFS 服务器。工具链让你能在 PC 上编译出 ARM 代码,TFTP 让你通过网络加载内核和设备树,NFS 让你共享根文件系统。这三板斧砍下来,你的开发效率至少翻一倍。