2. 开发环境搭建:交叉编译工具链安装、TFTP/NFS服务配置、串口终端工具使用、虚拟机与开发板网络配置

说实话,嵌入式Linux开发的第一步,往往是最劝退的。我记得刚入行那会儿,光搭环境就折腾了整整两天——工具链版本不对、网络死活ping不通、串口乱码……嗯,这些坑我基本都踩过。这一章,我把这些年积累的「标准操作」和「避坑经验」一起给你,照着做,能省不少时间。

本章核心目标:在宿主机(Ubuntu虚拟机)上搭建一套完整的嵌入式开发环境,实现与目标开发板的通信、文件传输和调试。

2.1 交叉编译工具链安装

交叉编译,说白了就是在你的x86电脑上编译出能在ARM开发板上运行的代码。为什么不能直接在开发板上编译?你想想看,开发板的CPU性能、内存、存储都有限,编译个Linux内核可能要几个小时,而在PC上只要十几分钟。

2.1.1 工具链的选择

我个人习惯用Linaro提供的GCC工具链,稳定且社区活跃。针对不同的ARM架构,选择也不同:

目标架构 工具链前缀 典型应用
ARM Cortex-A7/A8 arm-linux-gnueabihf- 全志、瑞芯微入门级芯片
ARM Cortex-A53/A72 aarch64-linux-gnu- 树莓派3/4、RK3399等64位芯片
ARM Cortex-M系列 arm-none-eabi- 裸机或RTOS开发(非Linux)
我的建议:初学者先选 arm-linux-gnueabihf-,兼容性最好。等后面接触64位芯片再切到 aarch64。

2.1.2 安装步骤

以Ubuntu 20.04为例,安装Linaro 7.5版本的工具链:

# 下载工具链(约200MB)
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)
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

输出类似下面这样,就说明装好了:

arm-linux-gnueabihf-gcc (Linaro GCC 7.5-2019.12) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
我曾经踩过的坑:工具链版本和内核版本不匹配。比如用gcc 9.x编译Linux 4.19内核,会出现奇怪的链接错误。我的经验是:内核用什么版本编译的,工具链就用那个时期的版本,别追新。

2.2 TFTP/NFS服务配置

开发阶段,你不可能每次修改代码都重新烧写整个系统。TFTP和NFS就是用来解决这个问题的——TFTP传内核和设备树,NFS挂载根文件系统。这样你改完代码,重启开发板就能看到效果。

2.2.1 TFTP服务器配置

TFTP(Trivial File Transfer Protocol)是个轻量级的文件传输协议,专门用来在开发阶段快速传输内核镜像(uImage/zImage)和设备树文件(.dtb)。

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

# 创建TFTP根目录
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot

# 修改配置文件 /etc/default/tftpd-hpa
sudo vim /etc/default/tftpd-hpa

配置文件内容:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

重启服务并测试:

sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa

# 本地测试
echo "test" > /tftpboot/test.txt
tftp localhost
tftp> get test.txt
tftp> quit
注意:TFTP默认端口是69,如果虚拟机防火墙开着,记得放行。我一般直接关掉防火墙省事——反正是在内网开发。

2.2.2 NFS服务器配置

NFS(Network File System)可以把开发板上的根文件系统「映射」到虚拟机的一个目录里。开发板上电后,直接从网络加载根文件系统,所有修改实时生效。

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

# 创建共享目录(假设你的根文件系统在 /home/embedded/rootfs)
sudo mkdir -p /home/embedded/rootfs

# 修改 /etc/exports 文件
sudo vim /etc/exports

添加一行:

/home/embedded/rootfs *(rw,sync,no_root_squash,no_subtree_check)

参数说明:

参数 含义
rw 可读写
sync 同步写入,保证数据一致性
no_root_squash 允许开发板以root权限访问,否则会映射成nobody用户
no_subtree_check 禁用子树检查,提高性能
# 重启NFS服务
sudo systemctl restart nfs-kernel-server

# 本地验证
sudo mount -t nfs localhost:/home/embedded/rootfs /mnt
ls /mnt
sudo umount /mnt
我曾经踩过的坑:no_root_squash 这个参数一定要加。有一次我忘了加,结果开发板上所有操作都提示「Permission denied」,折腾了半天才发现是权限映射问题。

2.3 串口终端工具使用

串口是嵌入式开发中最基础的调试手段。开发板没有显示器、没有键盘,串口就是你和它沟通的唯一窗口。我个人最常用的是 minicom 和 screen,简单可靠。

2.3.1 安装和配置 minicom

# 安装
sudo apt-get install minicom

# 配置(第一次运行需要设置)
sudo minicom -s

进入配置菜单后,选择「Serial port setup」,设置以下参数:

参数 典型值 说明
Serial Device /dev/ttyUSB0 USB转串口设备,也可能是 ttyS0 或 ttyACM0
Bps/Par/Bits 115200 8N1 波特率115200,8数据位,无校验,1停止位
Hardware Flow Control No 关闭硬件流控
Software Flow Control No 关闭软件流控

设置完成后,选择「Save setup as dfl」保存为默认配置,然后退出。下次直接运行 sudo minicom 即可。

2.3.2 使用 screen 作为轻量替代

如果你不想装 minicom,screen 也能干这活:

# 安装
sudo apt-get install screen

# 连接串口(波特率115200)
sudo screen /dev/ttyUSB0 115200

# 退出:按 Ctrl+A,然后按 K,再按 Y 确认
我的习惯:调试阶段用 minicom,因为它支持日志记录(Ctrl+A → L)。出问题的时候,翻日志比靠脑子记靠谱多了。

2.3.3 常见问题排查

  • 找不到 /dev/ttyUSB0:检查USB转串口驱动是否安装,运行 lsusb 查看设备是否识别。
  • 乱码:波特率不匹配。开发板一般是115200,但也有用57600或9600的,看板子手册。
  • 权限问题:把当前用户加入 dialout 组:sudo usermod -a -G dialout $USER,然后注销重新登录。

2.4 虚拟机与开发板网络配置

网络配置是整个环境搭建中最容易出问题的一环。TFTP、NFS、SSH都依赖网络,网络不通,后面全白搭。我见过太多人卡在这一步了。

2.4.1 网络拓扑

先搞清楚我们要搭什么样的网络:

开发环境网络拓扑 Ubuntu 虚拟机 IP: 192.168.1.100 TFTP + NFS + SSH ARM 开发板 IP: 192.168.1.200 U-Boot + Linux 路由器/交换机 网段: 192.168.1.0/24 说明:虚拟机与开发板通过路由器连接,处于同一网段。虚拟机提供TFTP/NFS服务,开发板从网络启动。 串口线用于调试终端,网线用于数据传输。

2.4.2 虚拟机网络模式选择

VMware或VirtualBox有三种网络模式,我直接说结论:

模式 适用场景 缺点
桥接模式 推荐。虚拟机直接接入物理网络,和开发板在同一网段 占用一个局域网IP
NAT模式 虚拟机可以上网,但外部无法访问虚拟机 开发板无法连接虚拟机,不适合嵌入式开发
仅主机模式 虚拟机与宿主机通信,不连外网 需要额外配置,开发板无法直接访问
我的建议:直接用桥接模式。把虚拟机、开发板、宿主机都接到同一个路由器上,IP设为同一网段,最简单也最稳定。

2.4.3 配置步骤

以VirtualBox为例,设置桥接网络:

  1. 关闭虚拟机。
  2. 在VirtualBox管理界面,选中虚拟机 → 设置 → 网络。
  3. 「连接方式」选择「桥接网卡」。
  4. 「界面名称」选择你宿主机连路由器的网卡(通常是有线或WiFi)。
  5. 启动虚拟机,在Ubuntu中配置静态IP。
# 编辑网络配置文件(Ubuntu 20.04用netplan)
sudo vim /etc/netplan/01-netcfg.yaml

内容如下:

network:
  version: 2
  ethernets:
    enp0s3:
      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

# 验证
ip addr show enp0s3
ping 192.168.1.1  # 测试网关
ping 8.8.8.8      # 测试外网

2.4.4 开发板网络配置

开发板通常在U-Boot阶段设置IP,然后传给Linux内核。以常见的全志芯片为例:

# 在U-Boot命令行中设置
setenv ipaddr 192.168.1.200
setenv serverip 192.168.1.100   # 虚拟机的IP
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
saveenv

# 测试网络连通性
ping 192.168.1.100

如果ping通,说明网络配置成功。这时候你就可以用TFTP下载内核了:

# 从虚拟机下载内核镜像
tftp 0x42000000 zImage
tftp 0x43000000 sunxi.dtb
我曾经踩过的坑:开发板和虚拟机的IP不能冲突。有一次我两台设备都设了192.168.1.100,结果网络时通时断,查了半天才发现IP冲突。建议把虚拟机IP固定在一个范围(比如100-120),开发板IP固定在另一个范围(比如200-220),避免冲突。

2.5 环境验证

所有配置完成后,做一次完整的验证,确保每个环节都正常:

  1. 工具链验证:编译一个Hello World程序,放到开发板上运行。
  2. TFTP验证:在开发板U-Boot中通过TFTP下载文件。
  3. NFS验证:开发板挂载虚拟机的NFS共享目录,读写文件。
  4. 串口验证:通过串口终端能看到开发板的启动日志和命令行。
  5. 网络验证:虚拟机与开发板互相ping通。

这五个验证都通过,你的开发环境就算搭好了。后面写驱动、编译内核、调试应用,都会顺畅很多。

最后说一句:环境搭建是最枯燥但最重要的一步。我见过太多初学者在这步放弃了,或者搭了个半吊子环境,后面调试时各种莫名其妙的问题。花半天时间,把环境搭扎实,后面能省下几天的排查时间。这笔账,你想想看,值不值?