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

好,咱们正式开始动手了。这一章要解决一个核心问题:怎么让你的电脑和开发板“说上话”。说白了,就是搭建一条从代码到硬件的通道。

我刚开始做嵌入式Linux时,最头疼的就是环境搭建。明明代码写得没问题,一烧到板子上就黑屏。后来才发现,不是代码的锅,是工具链版本不对。嗯,这里咱们一步步来,把坑都填平。

2.1 交叉编译工具链安装

先说说为什么需要交叉编译。你的电脑是x86架构,开发板是ARM架构。在x86上编译出来的程序,ARM跑不了。所以我们需要一个在x86上运行、但能生成ARM可执行文件的编译器——这就是交叉编译工具链。

核心概念:交叉编译 = 在宿主机(PC)上编译,在目标机(开发板)上运行。

2.1.1 获取工具链

我个人习惯用Linaro提供的工具链,稳定且社区活跃。以ARM Cortex-A7为例,我常用的是gcc-arm-linux-gnueabihf

# 下载工具链(以Ubuntu 20.04为例)
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 -C /opt/

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

我的经验:别把工具链解压到系统目录(如/usr/local),万一要换版本,清理起来很麻烦。放/opt下,一个文件夹就是一个版本,清爽。

2.1.2 验证安装

装完别急着高兴,先验证一下。我曾经遇到过解压完发现少了个关键库,折腾了半天。

# 查看编译器版本
arm-linux-gnueabihf-gcc --version

# 编译一个测试程序
echo 'int main(){ return 0; }' > test.c
arm-linux-gnueabihf-gcc test.c -o test.arm

# 查看生成的文件类型
file test.arm
# 输出应为:ELF 32-bit LSB executable, ARM, version 1 (SYSV)

注意:如果提示command not found,检查PATH是否生效。可以用echo $PATH看看路径对不对。另外,32位系统可能需要安装lib32z1等兼容库。

2.2 TFTP/NFS服务配置

工具链装好了,接下来要解决怎么把编译好的程序送到开发板上。这里有两个常用服务:TFTP和NFS。它们分工不同,我一般两个都配。

2.2.1 TFTP服务(传文件用)

TFTP是个轻量级的文件传输协议。说白了,就是开发板能从你的电脑上“拉”文件下来。我常用它来下载内核和设备树。

# 安装TFTP服务
sudo apt-get install 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 mkdir -p /tftpboot
sudo chmod 777 /tftpboot

# 重启服务
sudo systemctl restart tftpd-hpa

避坑指南:我曾经把TFTP目录权限设成了755,结果开发板下载文件时一直报“Permission denied”。后来改成777就正常了。另外,防火墙要放行UDP 69端口。

2.2.2 NFS服务(挂载根文件系统用)

NFS比TFTP高级一点。它能让开发板直接挂载你电脑上的一个目录,就像访问本地硬盘一样。调试阶段特别有用,改完代码直接编译,开发板那边立刻就能用。

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

# 配置导出目录
sudo vim /etc/exports

# 添加一行(假设你的开发板IP是192.168.1.100)
/nfsroot 192.168.1.100(rw,sync,no_subtree_check,no_root_squash)

# 创建共享目录
sudo mkdir -p /nfsroot
sudo chmod 777 /nfsroot

# 重启服务
sudo systemctl restart nfs-kernel-server

重要no_root_squash这个参数很关键。不加的话,开发板上的root用户会被映射成nobody,导致很多操作权限不足。我刚开始就因为这个,折腾了一下午。

2.3 虚拟机与开发板网络互通

环境配好了,但连不上也是白搭。这里要解决虚拟机、宿主机、开发板三者之间的网络通信。我推荐用桥接模式,让虚拟机直接和开发板在同一个网段。

2.3.1 虚拟机网络设置

以VirtualBox为例,设置步骤如下:

  1. 关闭虚拟机
  2. 打开虚拟机设置 → 网络
  3. 连接方式选择“桥接网卡”
  4. 界面名称选择你电脑上网的网卡(有线或无线)
  5. 启动虚拟机,配置静态IP
# 在虚拟机中配置静态IP(Ubuntu 20.04)
sudo vim /etc/netplan/01-netcfg.yaml

# 修改内容如下:
network:
  version: 2
  ethernets:
    enp0s3:
      dhcp4: no
      addresses:
        - 192.168.1.10/24
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 114.114.114.114]

# 应用配置
sudo netplan apply

我的习惯:我会把虚拟机的IP固定下来,比如192.168.1.10。开发板用192.168.1.100。这样调试时不用每次查IP,省心。

2.3.2 开发板网络配置

开发板这边,我一般通过串口登录,然后手动配置IP。如果板子跑的是BusyBox,命令稍有不同。

# 通过串口登录开发板
# 配置IP(假设网卡是eth0)
ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up

# 添加默认网关
route add default gw 192.168.1.1

# 测试连通性
ping 192.168.1.10   # 虚拟机IP
ping 192.168.1.1    # 网关

验证方法:在虚拟机上ping 192.168.1.100,在开发板上ping 192.168.1.10。两边都能通,说明网络搞定了。

2.3.3 常见问题排查

你想想看,网络不通时最让人抓狂。我列几个我踩过的坑:

现象 可能原因 解决方法
虚拟机ping不通开发板 防火墙拦截 关闭虚拟机防火墙:sudo ufw disable
开发板ping不通虚拟机 网线没插好或交换机问题 检查网口指示灯,换根网线试试
两边都能ping通网关,但互ping不通 子网掩码不一致 确保两边子网掩码都是255.255.255.0
TFTP下载超时 防火墙或服务没启动 检查systemctl status tftpd-hpa

特别提醒:如果你用的是无线网卡,桥接模式可能会不稳定。我建议用有线连接开发板和电脑,或者用一根交叉网线直连。无线环境下的广播风暴,你懂的。

2.4 实战:验证整个环境

好,所有东西都配好了。咱们来跑一个完整的流程,验证一下环境是否OK。

# 1. 在虚拟机上编译一个测试程序
echo '#include <stdio.h>
int main() {
    printf("Hello, POS World!\n");
    return 0;
}' > hello.c

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

# 2. 复制到TFTP目录
cp hello.arm /tftpboot/

# 3. 在开发板上通过TFTP下载
tftp -g -r hello.arm 192.168.1.10

# 4. 添加执行权限并运行
chmod +x hello.arm
./hello.arm

# 输出:Hello, POS World!

成就感时刻:当你在开发板上看到“Hello, POS World!”时,说明你的开发环境已经搭建成功了。我第一次跑通时,差点激动得跳起来。别笑,这真的是嵌入式开发者的“Hello World”时刻。

嗯,到这里,开发环境就搭建好了。下一章咱们会深入POS机的硬件接口,开始真正的驱动开发。到时候你会发现,今天搭的环境,就是后面所有工作的基石。