第一章 课程导论与实验环境搭建

各位同学好,我是这门课的主讲。做了十几年嵌入式Linux和实时系统,踩过的坑不少,积累的经验也还算丰富。今天咱们开始第一讲——先把路铺好。

嵌入式实时协议栈移植,说白了就是让一个原本跑在通用Linux上的网络协议栈,能在你的嵌入式板子上稳定、低延迟地工作。我当年第一次做这个,以为就是把代码交叉编译一下烧进去就完事了。结果呢?系统跑起来动不动就丢包,延迟抖得像心电图。后来才明白,环境没搭对,后面全是白费功夫。

本章核心目标:把开发环境彻底搞定,让你后续每一行代码、每一次调优都有可靠的实验基础。

1.1 嵌入式Linux实时协议栈概述

先说说什么是实时协议栈。普通的Linux网络协议栈,设计目标是吞吐量和公平性。但实时场景下——比如工业控制、车载通信、无人机飞控——我们关心的是确定性:这个包必须在1毫秒内送达,不能早也不能晚。

常见的实时协议栈方案有几种:

方案 特点 适用场景
PREEMPT_RT + 标准协议栈 内核全抢占,延迟可控制在几十微秒 通用实时网络,开发成本低
XDP/DPDK 用户态协议栈 绕过内核,零拷贝,延迟可到微秒级 高性能数据面,如5G核心网
专用实时协议栈(如RT-TCP) 修改TCP/IP行为,保证时序 工业以太网、车载时间敏感网络

我个人习惯把实时协议栈的优化分成三个层次:内核调度层、协议处理层、驱动层。这门课会一层一层带着大家走通。

1.2 课程目标与学习路径

这门课学完,你能做到什么?

  • 独立搭建一套完整的嵌入式Linux实时开发环境
  • 把至少一种实时协议栈移植到ARM Cortex-A72平台上
  • 用性能工具定位延迟瓶颈,并做针对性调优
  • 理解实时网络的核心指标:延迟、抖动、吞吐量、丢包率

学习路径我建议这样走:

  1. 环境搭建(本章)—— 把工具链、内核、网络启动全搞定
  2. 内核实时化改造 —— 打PREEMPT_RT补丁,配置实时内核
  3. 协议栈移植 —— 把选定的协议栈代码集成进内核
  4. 性能基准测试 —— 用cyclictest、netperf等工具拿到基线数据
  5. 调优实战 —— 中断亲和性、CPU隔离、内存池优化……

嗯,这里要注意:不要跳步。我见过太多人急着调优,结果环境没配好,测出来的数据全是假的。

1.3 硬件平台介绍:ARM Cortex-A72

我们用的板子是基于ARM Cortex-A72的。为什么选它?

  • 性能足够:四核或八核,主频1.5GHz以上,跑实时协议栈绰绰有余
  • 生态成熟:Linux主线内核支持完善,驱动好找
  • 工业级:很多车载、工控设备用的就是A72

具体参数我列一下:

项目 规格
CPU ARM Cortex-A72,4核,1.5GHz
内存 4GB LPDDR4
存储 32GB eMMC + microSD卡槽
网络 千兆以太网 x2
调试接口 UART、JTAG、USB

我建议你手头也准备一块类似的板子。如果手边没有,用QEMU模拟也可以,但性能调优那几章效果会打折扣。

1.4 交叉编译工具链安装

交叉编译,说白了就是在你的x86电脑上编译出ARM能跑的程序。我最早用Linaro的工具链,后来发现主线gcc配合crosstool-ng自己定制更灵活。

这里我用的是gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu。安装步骤:

# 下载工具链
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz

# 解压到 /opt
sudo tar -xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz -C /opt

# 添加环境变量
export PATH=/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH

# 验证
aarch64-none-linux-gnu-gcc --version

小技巧:把环境变量加到 ~/.bashrc 里,省得每次开终端都要 export 一遍。我习惯在 .bashrc 里加一行注释 # ARM交叉编译工具链,方便以后找。

1.5 Linux内核源码获取与配置

内核源码我们选长期支持版(LTS),稳定且社区维护时间长。我推荐5.10或5.15,实时补丁支持得最好。

# 获取内核源码
git clone --depth=1 -b v5.10.120 git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git

# 进入目录
cd linux

# 配置内核(使用默认的ARM64配置)
make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- defconfig

# 打开菜单配置界面
make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- menuconfig

在menuconfig里,有几个关键选项必须打开:

  • General setup —> Preemption Model 选 Fully Preemptible Kernel (Real-Time)
  • Device Drivers —> Network device support 确保你的网卡驱动选上
  • Kernel Features —> Timer frequency 设为 1000 Hz

我曾经踩过的坑:第一次配置时忘了开网卡驱动,结果内核启动后网络不通。折腾了半天才发现是驱动没编进去。所以配置完一定要检查 .config 文件里有没有 CONFIG_你的网卡驱动=y。

1.6 TFTP/NFS网络启动环境搭建

嵌入式开发最常用的启动方式就是网络启动。内核放在TFTP服务器上,根文件系统通过NFS挂载。这样你修改了内核或驱动,重启板子就能看到效果,不用反复烧写eMMC。

搭建步骤:

  1. 安装TFTP服务器
sudo apt-get install tftpd-hpa
sudo mkdir -p /srv/tftp
sudo chmod 777 /srv/tftp
# 把编译好的内核镜像 Image 和设备树 .dtb 文件复制到 /srv/tftp
  1. 安装NFS服务器
sudo apt-get install nfs-kernel-server
sudo mkdir -p /srv/nfs/rootfs
# 把根文件系统解压到 /srv/nfs/rootfs
sudo tar -xf ubuntu-base-20.04.5-base-arm64.tar.gz -C /srv/nfs/rootfs

# 编辑 /etc/exports,添加一行
echo "/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports

# 重启NFS服务
sudo systemctl restart nfs-kernel-server
  1. 配置U-Boot启动参数
setenv ipaddr 192.168.1.100
setenv serverip 192.168.1.10
setenv netmask 255.255.255.0
setenv gatewayip 192.168.1.1
setenv bootargs 'console=ttyAMA0,115200 root=/dev/nfs nfsroot=192.168.1.10:/srv/nfs/rootfs rw ip=192.168.1.100:192.168.1.10:192.168.1.1:255.255.255.0::eth0:off'
setenv bootcmd 'tftp 0x40080000 Image; tftp 0x48000000 board.dtb; booti 0x40080000 - 0x48000000'
saveenv
boot

关键点:IP地址要和你主机的TFTP/NFS服务器在同一个网段。我第一次配的时候把serverip写成了网关地址,结果板子一直timeout。检查网络连接时,先ping一下主机IP,确认物理链路通。

下面这张图展示了整个网络启动的流程:

嵌入式Linux网络启动流程 嵌入式Linux网络启动流程 开发主机 TFTP服务器 NFS服务器 目标板 (A72) U-Boot → 内核 → 根文件系统 TFTP传内核和设备树 NFS挂载根文件系统 ① 启动请求 ② 下载内核 ③ 挂载根文件系统

流程很简单:板子上电 -> U-Boot从TFTP下载内核和设备树 -> 内核启动 -> 通过NFS挂载根文件系统 -> 进入系统。整个过程不到10秒,开发效率比烧写eMMC高太多了。

本章小结

这一章我们把整个课程的实验环境搭好了。工具链、内核源码、网络启动,这三样东西是后面所有实验的基石。我建议你花点时间把每一步走通,别急着往下赶。环境稳了,后面调优才有底气。