1. 嵌入式Linux开发环境搭建

嵌入式Linux驱动开发的第一步是构建一个稳定、可复现的宿主机开发环境。本章将系统讲解交叉编译工具链的安装、TFTP/NFS服务器的配置,以及开发板与主机的网络连接方法。这些基础环境是后续驱动编译、下载与调试的基石。

环境概览: 宿主机通常为 x86_64 架构的 Ubuntu 20.04/22.04 LTS,目标板为 ARM Cortex-A 系列(如 i.MX6ULL、STM32MP157)。所有操作均以 root 或具有 sudo 权限的用户执行。

1.1 交叉编译工具链安装

交叉编译是指在宿主机(x86)上编译生成目标板(ARM)可执行代码的过程。工具链包含编译器、链接器、库文件及头文件。

1.1.1 工具链选择与下载

常见工具链来源:

  • Linaro GCC: 针对 ARM 架构优化,支持 arm-linux-gnueabihf 和 aarch64-linux-gnu。
  • 芯片厂商 SDK: NXP Yocto SDK、ST SDK 等,包含板级 BSP 和专用库。
  • Buildroot / Yocto: 可定制生成完整工具链和根文件系统。
架构 工具链前缀 典型版本 适用芯片
ARM 32-bit (v7) arm-linux-gnueabihf- gcc-linaro-7.5.0 i.MX6ULL, STM32MP157
ARM 64-bit (v8) aarch64-linux-gnu- gcc-arm-10.3 Raspberry Pi 4, RK3399
RISC-V 64-bit riscv64-linux-gnu- gcc-riscv64-unknown-linux-gnu K210, D1

1.1.2 安装步骤(以 arm-linux-gnueabihf 为例)

  1. 下载工具链压缩包到 /opt 目录。
  2. 解压并确认目录结构。
  3. 将工具链的 bin 目录加入系统 PATH。
  4. 验证安装:编译一个简单的 C 程序。
# 下载 Linaro 7.5.0 工具链
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

# 解压到 /opt
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt

# 添加环境变量(写入 ~/.bashrc 或 /etc/profile)
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin

# 验证
arm-linux-gnueabihf-gcc --version
# 输出应显示 gcc (Linaro GCC 7.5-2019.12) 7.5.0

# 编译测试程序
echo '#include <stdio.h>
int main() { printf("Hello ARM!\n"); return 0; }' > test.c
arm-linux-gnueabihf-gcc -o test_arm test.c
file test_arm
# 输出: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
关键检查点: 使用 file 命令确认生成的可执行文件是 ARM 架构,而非 x86 架构。如果显示 x86-64,说明使用了宿主机 gcc,而非交叉编译器。

1.1.3 工具链结构说明

一个完整的交叉工具链包含以下组件:

  • bin/ — 编译器、汇编器、链接器(gcc, as, ld, objcopy, objdump)。
  • lib/ — 运行时库(libc, libm, libpthread 等)。
  • libc/ — 目标板的 C 库头文件和库文件。
  • include/ — 目标板内核头文件(用于编译驱动模块)。
交叉编译工具链结构图 arm-linux-gnueabihf- bin/ lib/ arm-linux-gnueabihf/ gcc ld objcopy objdump libc.so / libm.so libpthread.so include/ (内核头文件) libc/ (目标板库)

1.2 TFTP/NFS 服务器配置

嵌入式开发中,TFTP 用于快速下载内核和设备树到开发板内存,NFS 用于挂载远程根文件系统,实现“无盘启动”和实时调试。

1.2.1 TFTP 服务器安装与配置

TFTP(Trivial File Transfer Protocol)基于 UDP,用于 Bootloader(如 U-Boot)从宿主机下载镜像。

# 安装 TFTP 服务器和客户端
sudo apt update
sudo apt install tftpd-hpa tftp-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

# 测试:在 /srv/tftp 下创建测试文件,从另一终端获取
echo "TFTP Test" | sudo tee /srv/tftp/test.txt
tftp localhost -c get test.txt
cat test.txt
# 应输出 "TFTP Test"
防火墙注意: TFTP 使用 UDP 端口 69。如果宿主机启用了 ufw,请执行 sudo ufw allow 69/udp。开发板侧需确保网络连通性。

1.2.2 NFS 服务器安装与配置

NFS(Network File System)允许开发板将宿主机上的目录挂载为根文件系统,避免每次修改后重新烧写。

# 安装 NFS 服务器
sudo apt install nfs-kernel-server

# 创建导出目录(例如存放根文件系统)
sudo mkdir -p /srv/nfs/rootfs
sudo chmod 777 /srv/nfs/rootfs

# 编辑 /etc/exports,添加导出规则
sudo vim /etc/exports

在 /etc/exports 中添加:

/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

参数说明:

  • * — 允许所有主机访问(生产环境应限制为开发板 IP)。
  • rw — 读写权限。
  • sync — 同步写入,保证数据一致性。
  • no_root_squash — 允许开发板 root 用户保持 root 权限。
# 导出并重启 NFS 服务
sudo exportfs -a
sudo systemctl restart nfs-kernel-server

# 验证导出
showmount -e localhost
# 输出: /srv/nfs/rootfs *

1.2.3 TFTP 与 NFS 工作流程对比

特性 TFTP NFS
协议 UDP (端口 69) TCP/UDP (端口 2049)
主要用途 下载内核、设备树、uboot 镜像 挂载根文件系统、共享应用程序
传输效率 低(无确认重传) 高(有状态连接)
安全性 无认证 基于 IP 和导出规则
典型使用阶段 U-Boot 启动阶段 Linux 内核启动后
TFTP + NFS 开发启动流程 宿主机 (x86_64) 开发板 (ARM) 以太网 (静态 IP) TFTP 服务器 U-Boot 请求 zImage ① tftp 0x12000000 zImage NFS 服务器 内核挂载 NFS 根文件系统 ② nfsroot=192.168.1.100:/srv/nfs/rootfs 宿主机编译驱动 .ko 开发板 insmod 测试 ③ scp/cp 到 NFS 目录

1.3 开发板与主机网络连接

网络连接是 TFTP/NFS 通信的基础。推荐使用静态 IP 配置,避免 DHCP 分配导致地址变化。

1.3.1 网络拓扑与 IP 规划

设备 接口 IP 地址 子网掩码 网关
宿主机 eth0 (有线) 192.168.1.100 255.255.255.0 192.168.1.1
开发板 eth0 192.168.1.200 255.255.255.0 192.168.1.1
连接方式: 推荐使用交叉网线直连,或通过交换机/路由器连接。避免使用无线网络,以减少延迟和丢包。

1.3.2 宿主机网络配置

# 查看当前网络接口
ip addr show

# 临时设置静态 IP(以 Ubuntu 为例)
sudo ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up

# 永久配置(编辑 netplan 或 /etc/network/interfaces)
# Ubuntu 18.04+ 使用 netplan
sudo vim /etc/netplan/01-netcfg.yaml

netplan 配置示例:

network:
  version: 2
  ethernets:
    eth0:
      dhcp4: no
      addresses:
        - 192.168.1.100/24
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 114.114.114.114]
# 应用配置
sudo netplan apply

1.3.3 开发板网络配置(U-Boot 与 Linux)

U-Boot 环境变量设置:

# 进入 U-Boot 命令行,设置网络参数
setenv ipaddr 192.168.1.200
setenv serverip 192.168.1.100
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
saveenv

# 测试网络连通性
ping 192.168.1.100
# 应返回 "host 192.168.1.100 is alive"

Linux 内核启动后网络配置:

# 临时设置 IP
ifconfig eth0 192.168.1.200 netmask 255.255.255.0 up
route add default gw 192.168.1.1

# 永久配置(根据根文件系统类型)
# 对于 Buildroot 或 Yocto,编辑 /etc/network/interfaces
echo "auto eth0" >> /etc/network/interfaces
echo "iface eth0 inet static" >> /etc/network/interfaces
echo "    address 192.168.1.200" >> /etc/network/interfaces
echo "    netmask 255.255.255.0" >> /etc/network/interfaces
echo "    gateway 192.168.1.1" >> /etc/network/interfaces

1.3.4 连通性验证清单

  1. 物理层: 网口 LED 灯亮起,确认链路正常。
  2. IP 层: 宿主机 ping 开发板,开发板 ping 宿主机。
  3. TFTP 层: 开发板 U-Boot 执行 tftp 0x12000000 zImage,观察下载进度。
  4. NFS 层: 开发板挂载 NFS 目录:mount -t nfs -o nolock 192.168.1.100:/srv/nfs/rootfs /mnt。
常见故障排查:
  • ping 不通:检查网线、防火墙、IP 地址是否在同一网段。
  • TFTP 超时:确认 TFTP 服务运行、文件路径正确、权限为 777。
  • NFS 挂载失败:检查 /etc/exports 语法、showmount -e 输出、开发板是否安装 nfs-common。
网络连通性验证流程 ① 物理层检查 ② IP 层 ping ③ TFTP 下载 ④ NFS 挂载 失败:检查网线/防火墙 失败:检查 IP/子网掩码 失败:检查 TFTP 路径/权限 ✅ 环境搭建完成,可进行驱动开发

1.4 本章小结

本章完成了嵌入式 Linux 驱动开发环境的三大核心搭建:

  • 交叉编译工具链: 安装并验证了 arm-linux-gnueabihf-gcc,确保能生成 ARM 架构的可执行文件。
  • TFTP/NFS 服务器: 配置了 TFTP 用于内核下载,NFS 用于根文件系统挂载,实现了无盘启动和快速迭代。
  • 网络连接: 设置了静态 IP,验证了从物理层到应用层的全链路连通性。
下一步: 环境就绪后,即可进入 GPIO 驱动模块的编写与编译。请确保开发板能通过 TFTP 启动内核,并通过 NFS 挂载根文件系统,这是后续所有驱动实验的基础运行环境。