3. 开发环境搭建:交叉编译工具链安装、TFTP与NFS服务器配置、串口终端工具设置

做嵌入式开发,第一件事就是把开发环境搭好。这步要是没弄利索,后面调试起来会非常痛苦。我见过不少新手,花了一周时间在环境问题上打转,最后发现只是工具链版本不对。

这一章,我把环境搭建拆成三块:交叉编译工具链、TFTP/NFS服务器、串口终端工具。每块我都会给出具体操作步骤,还有我踩过的坑。

核心原则:开发环境要「一次配好,到处可用」。建议用虚拟机或独立开发机,别在主力工作机上乱装。

3.1 交叉编译工具链安装

交叉编译,说白了就是在PC上编译出能在ARM板子上跑的程序。你想想看,板子上的CPU跑不动GCC,所以得靠PC代劳。

3.1.1 工具链的选择

我个人习惯用Linaro GCC,它针对ARM架构做了优化,稳定性和性能都不错。当然,你也可以用芯片厂商提供的工具链,比如NXP的、TI的。但要注意版本匹配。

工具链类型 适用场景 前缀示例
arm-linux-gnueabihf ARM Cortex-A系列,硬件浮点 arm-linux-gnueabihf-gcc
aarch64-linux-gnu ARMv8 64位平台 aarch64-linux-gnu-gcc
arm-none-eabi 裸机程序(无操作系统) arm-none-eabi-gcc

注意:U-Boot移植必须用arm-linux-gnueabihf-前缀的工具链。别用arm-none-eabi,那个是给裸机用的,链接脚本不一样。

3.1.2 安装步骤

以Ubuntu 20.04为例,我推荐用apt安装,省事。但如果你需要特定版本,就去Linaro官网下载。

# 方法一:apt安装(推荐)
sudo apt update
sudo apt install gcc-arm-linux-gnueabihf

# 方法二:下载Linaro工具链
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
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
sudo mv gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf /opt/

# 设置环境变量
echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc

安装完后,验证一下:

arm-linux-gnueabihf-gcc --version

如果看到版本信息,说明工具链装好了。

小技巧:我习惯在/opt下建一个toolchains目录,把所有工具链都放里面。这样方便管理,也方便切换版本。

3.1.3 避坑指南

我曾经在项目里遇到过工具链版本不匹配的问题。U-Boot 2020.04用gcc 7.5编译没问题,但换成gcc 9.4就报了一堆警告。后来查了U-Boot的文档,发现它对GCC版本有明确要求。

  • 版本匹配:U-Boot官方推荐GCC 7.x或8.x,别用太新的。
  • 32位库:如果你用的是64位系统,可能需要安装32位兼容库:sudo apt install lib32z1 lib32ncurses5
  • 路径不要有中文:工具链路径里别出现中文或空格,否则编译会报一些莫名其妙的错误。

3.2 TFTP与NFS服务器配置

这两个服务是调试U-Boot和内核的利器。TFTP用来下载镜像,NFS用来挂载根文件系统。配合起来用,调试效率能提升好几倍。

3.2.1 TFTP服务器

TFTP是个轻量级的文件传输协议,U-Boot用它从PC上下载内核和设备树。配置起来很简单。

# 安装TFTP服务器
sudo apt install tftpd-hpa

# 配置TFTP目录
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp

# 修改配置文件
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下放一个测试文件,然后在板子的U-Boot命令行里执行tftp 0x80800000 test.bin。如果能下载成功,说明TFTP配置没问题。

3.2.2 NFS服务器

NFS用来共享根文件系统。调试内核时,你不需要每次都烧写根文件系统到板子上,直接通过网络挂载就行。

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

# 创建共享目录
sudo mkdir -p /srv/nfs/rootfs
sudo chmod 777 /srv/nfs/rootfs

# 配置导出
sudo vim /etc/exports

在/etc/exports中添加:

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

重启服务:

sudo exportfs -a
sudo systemctl restart nfs-kernel-server

注意:no_root_squash这个选项很重要。如果不加,板子上的root用户会被映射成nobody,导致权限问题。我曾经因为这个选项,折腾了一下午才找到原因。

3.2.3 网络拓扑

为了让TFTP和NFS正常工作,你需要把PC和板子连在同一个网段。我一般用路由器或者交换机,PC的IP设为192.168.1.100,板子的IP设为192.168.1.200。

开发环境网络拓扑 开发主机 (PC) IP: 192.168.1.100 交换机/路由器 目标板 (ARM) IP: 192.168.1.200 TFTP 服务 NFS 服务 串口终端 TFTP下载内核/设备树 → NFS挂载根文件系统 → 串口输出调试信息

3.3 串口终端工具设置

串口是嵌入式开发中最常用的调试接口。U-Boot的启动信息、内核的打印日志,都靠它输出。我推荐两个工具:minicom和picocom。

3.3.1 minicom

minicom是老牌工具,功能强大,但配置稍微复杂一点。

# 安装minicom
sudo apt install minicom

# 配置minicom
sudo minicom -s

进入配置界面后,选择Serial port setup,设置以下参数:

参数 值 说明
Serial Device /dev/ttyUSB0 串口设备文件,根据实际情况修改
Bps/Par/Bits 115200 8N1 波特率115200,8数据位,无校验,1停止位
Hardware Flow Control No 关闭硬件流控
Software Flow Control No 关闭软件流控

配置完成后,选择Save setup as dfl保存为默认配置,然后退出。

小技巧:如果minicom启动后屏幕是黑的,按Ctrl+A然后按Z,可以调出帮助菜单。按O进入配置,按X退出。

3.3.2 picocom

picocom更轻量,配置也简单。我个人更喜欢用picocom,因为它启动快,参数直接写在命令行里。

# 安装picocom
sudo apt install picocom

# 启动picocom
picocom -b 115200 -d 8 -p n -s 1 /dev/ttyUSB0

# 参数说明:
# -b 115200 : 波特率
# -d 8      : 数据位
# -p n      : 无校验
# -s 1      : 停止位

退出picocom:按Ctrl+A然后按Ctrl+X。

3.3.3 权限问题

串口设备默认只有root用户能访问。如果你不想每次都加sudo,可以把当前用户加入dialout组。

sudo usermod -a -G dialout $USER

然后注销重新登录,或者执行newgrp dialout使组权限生效。

注意:如果你用的是USB转串口模块,比如CH340或CP2102,需要先安装驱动。Ubuntu一般自带驱动,插上就能识别。如果识别不到,检查一下lsusb和dmesg的输出。

3.4 环境验证

环境搭好了,怎么验证?我一般会写一个简单的测试程序,交叉编译后通过TFTP下载到板子上运行。

// test.c
#include <stdio.h>

int main(void)
{
    printf("Hello, Embedded Linux!\n");
    return 0;
}

交叉编译:

arm-linux-gnueabihf-gcc -o test test.c

把编译好的test文件放到TFTP目录:

cp test /srv/tftp/

然后在板子的U-Boot命令行里:

tftp 0x80800000 test
go 0x80800000

如果串口输出Hello, Embedded Linux!,说明整个环境都通了。

总结一下:开发环境搭建看似琐碎,但每一步都很关键。工具链决定了你能不能编译,TFTP/NFS决定了你能不能高效调试,串口决定了你能不能看到输出。这三样配好了,后面的移植工作才能顺利推进。