2. 嵌入式Linux开发环境搭建:Ubuntu虚拟机、交叉编译链、TFTP/NFS与串口终端
说实话,做BSP开发,环境搭不好,后面全是坑。我见过太多新手,代码写得挺溜,结果卡在环境配置上好几天。这一章,咱们就把这些基础工作一次性搞定。
你想想看,咱们要在PC上开发,代码最终要跑到ARM架构的TI Jacinto芯片上。这中间需要一套完整的工具链和通信链路。我习惯把整个环境拆成四个部分:宿主系统(Ubuntu虚拟机)、编译工具(交叉编译器)、文件传输(TFTP/NFS)、调试终端(串口)。
核心逻辑: 在x86的Ubuntu上,用交叉编译器生成ARM可执行文件,通过TFTP/NFS把文件送到开发板,再用串口观察运行结果。缺一环,调试就卡壳。
2.1 Ubuntu虚拟机安装:别小看这一步
我个人习惯用 Ubuntu 22.04 LTS。为什么?因为TI官方的SDK和Processor SDK Linux在这个版本上验证得最充分。你用20.04也行,但有些新工具链的依赖包需要手动补,麻烦。
虚拟机软件我推荐 VMware Workstation Pro 或者 VirtualBox。如果你问我,我会选VMware,它的USB设备穿透和网络配置更稳定。我在项目中遇到过VirtualBox在挂载NFS时偶尔丢包的情况,排查了半天,最后换VMware就没事了。
配置要点:
- 内存: 至少8GB,建议16GB。编译内核时,4GB内存会直接卡死。
- CPU: 分配4核以上。交叉编译是并行任务,核越多越快。
- 磁盘: 至少80GB。一个完整的内核源码树加上编译产物,轻松吃掉30-40GB。
- 网络: 选择桥接模式。这样开发板和虚拟机在同一个网段,TFTP/NFS才能正常工作。
注意: 不要用NAT模式!NAT模式下,开发板无法直接访问虚拟机,TFTP和NFS都会失败。我曾经有个学员折腾了两天,最后发现是网络模式选错了。
2.2 交叉编译工具链配置:GCC Linaro
交叉编译,说白了就是在x86电脑上编译出ARM芯片能跑的程序。你直接在Ubuntu里gcc编译出来的东西,开发板是跑不了的——指令集都不一样。
TI Jacinto平台用的是 ARM Cortex-A72/A53 核心,所以我们需要 aarch64-linux-gnu 的交叉编译器。我推荐用 Linaro GCC,它是ARM官方推荐的优化版本。
安装步骤:
- 下载Linaro GCC 7.5或更高版本(建议用 gcc-arm-9.2-2019.12-x86_64-aarch64-linux-gnu)。
- 解压到
/opt/toolchains/目录。 - 配置环境变量,把工具链的bin目录加入PATH。
具体命令:
# 解压
sudo mkdir -p /opt/toolchains
sudo tar xvf gcc-arm-9.2-2019.12-x86_64-aarch64-linux-gnu.tar.xz -C /opt/toolchains/
# 配置环境变量(写入 ~/.bashrc)
export PATH=/opt/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-linux-gnu/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# 使生效
source ~/.bashrc
# 验证
aarch64-linux-gnu-gcc --version
验证成功的话,你会看到类似这样的输出:
aarch64-linux-gnu-gcc (GCC) 9.2.1 20191025
Copyright (C) 2019 Free Software Foundation, Inc.
小技巧: 我习惯把 ARCH 和 CROSS_COMPILE 也写进 ~/.bashrc。这样每次打开终端,编译内核或驱动时就不用再手动指定了。省事。
2.3 TFTP/NFS服务器搭建:文件传输的命脉
开发板启动后,怎么把编译好的内核、设备树、根文件系统传过去?两个办法:TFTP 和 NFS。
- TFTP: 用于传输内核镜像(Image)和设备树(.dtb)。U-Boot启动时,通过TFTP从虚拟机拉取这些文件。
- NFS: 用于挂载根文件系统。开发板通过网络,把虚拟机上共享的目录当作自己的硬盘来用。这样你修改了文件系统,开发板重启就能生效,不用反复烧写。
2.3.1 安装和配置TFTP服务器
# 安装
sudo apt update
sudo apt install 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 mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp
sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa
2.3.2 安装和配置NFS服务器
# 安装
sudo apt install nfs-kernel-server
# 创建共享目录(比如放根文件系统)
sudo mkdir -p /srv/nfs/rootfs
# 配置导出
sudo vim /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,导致无法写入文件系统。我曾经因为这个,调试一个驱动时发现日志写不进去,查了半天才发现是NFS权限问题。
2.4 Minicom/串口终端配置:调试的窗口
开发板没有显示器,你怎么看它打印的信息?怎么输入命令?全靠串口。串口就是BSP工程师的“眼睛”和“手”。
我推荐用 Minicom,轻量、稳定。当然你也可以用 screen 或 putty,但Minicom的配置更直观。
安装和配置:
# 安装
sudo apt install minicom
# 配置(第一次运行)
sudo minicom -s
进入配置菜单后,选择 Serial port setup,设置以下参数:
| 参数 | 值 | 说明 |
|---|---|---|
| Serial Device | /dev/ttyUSB0 |
根据实际设备节点调整,可能是ttyUSB1或ttyACM0 |
| Bps/Par/Bits | 115200 8N1 |
TI Jacinto默认的串口波特率 |
| Hardware Flow Control | No | 关闭硬件流控,否则可能无法输入 |
| Software Flow Control | No | 同上 |
配置完成后,选择 Save setup as dfl 保存为默认配置。以后直接运行 sudo minicom 就能连上开发板。
小技巧: 如果插上USB转串口线后,/dev/ttyUSB0 不存在,先检查驱动:lsmod | grep usb_serial。如果没有,安装 sudo apt install linux-image-extra-virtual。另外,记得把用户加入 dialout 组,这样就不用每次都sudo了:sudo usermod -aG dialout $USER。
2.5 环境验证:跑通第一个Hello World
环境搭好了,怎么知道对不对?写个简单的C程序,交叉编译,然后放到开发板上跑一下。
在虚拟机上:
# 编写测试程序
echo '#include <stdio.h>
int main() {
printf("Hello from TI Jacinto!\n");
return 0;
}' > hello.c
# 交叉编译
aarch64-linux-gnu-gcc -o hello hello.c
# 检查文件类型
file hello
输出应该是:
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1
看到 ARM aarch64 就对了。然后把 hello 文件复制到TFTP目录:
cp hello /srv/tftp/
在开发板的串口终端里,通过U-Boot加载并运行:
# 在U-Boot中
tftp 0x80000000 hello
go 0x80000000
如果串口打印出 Hello from TI Jacinto!,恭喜你,整个环境全部打通了。
总结一下: 虚拟机是工作台,交叉编译器是工具,TFTP/NFS是传送带,串口是观察窗。这四个东西配合好,后面的驱动开发才能顺畅。别嫌麻烦,这一步值得花时间彻底搞定。