第1章 嵌入式 Linux 开发全景图
本章目标
- 建立嵌入式 Linux 的整体认知,理解 Linux 在嵌入式系统中的角色
- 区分 MCU、MPU、SoC、SBC 等概念,理解单片机开发与嵌入式 Linux 开发的差异
- 掌握嵌入式 Linux 软件架构的四层结构:Bootloader、Kernel、RootFS、Application
- 了解工业控制、消费电子、AIoT 选择 Linux 的原因
- 明确嵌入式 Linux 工程师的能力模型与学习路径
知识导图
1 | 嵌入式系统 |
背景原理
1. 嵌入式系统的定义与分类
嵌入式系统是指以应用为中心、以计算机技术为基础、软硬件可裁剪,适用于对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统。与通用 PC 不同,嵌入式系统通常“看不见计算机”,却无处不在:手机、路由器、车载中控、工业 PLC、智能家居、摄像头等。
从处理器形态上,常分为以下几类:
| 类型 | 全称 | 典型特点 | 常见用途 |
|---|---|---|---|
| MCU | Microcontroller Unit | 单芯片集成 CPU、RAM、Flash、外设;无 MMU;跑 RTOS 或裸机 | 小家电、电机控制、传感器节点 |
| MPU | Microprocessor Unit | 以 CPU 为核心,外挂 DDR、Flash;有 MMU;可跑 Linux | 工控、网关、复杂人机界面 |
| SoC | System on Chip | 在单芯片内集成 CPU、GPU、NPU、编解码、各种接口 | 手机、平板、开发板、AI 盒子 |
| SBC | Single Board Computer | 以 SoC 为核心的完整板级产品,可直接运行完整 OS | 树莓派、泰山派、各类开发板 |
RK3566 属于 SoC:在一块芯片内集成了 ARM Cortex-A55 CPU、Mali-G52 GPU、0.8 TOPS NPU、视频编解码 VPU、以及 DDR 控制器、eMMC/SD、USB、以太网、MIPI 等接口。泰山派开发板则是在 RK3566 基础上做成的 SBC,方便学习与产品原型开发。
2. MCU/单片机开发与嵌入式 Linux 开发的差异
| 维度 | 单片机 / MCU 开发 | 嵌入式 Linux 开发 |
|---|---|---|
| 运行环境 | 裸机或 RTOS,直接操作寄存器 | 多进程、多用户、有内核与文件系统 |
| 编程方式 | 以 C 为主,少量汇编,直接访问硬件 | 以用户态 C/C++ 为主,通过内核、驱动、系统调用访问硬件 |
| 启动流程 | 上电→复位→从 Flash 取指执行 | 上电→BootROM→Bootloader→Kernel→init→Shell/应用 |
| 资源 | KB 级 RAM、Flash | 通常百 MB 级 DDR、GB 级 eMMC/SD |
| 调试 | JTAG、串口、逻辑分析仪 | 串口、网络、gdb、内核日志、设备树、驱动调试 |
| 软件组成 | 一个工程里编一个固件 | 需分别构建 U-Boot、内核、根文件系统、应用 |
理解这些差异,有助于从“单片机思维”过渡到“系统思维”:在 Linux 下,我们更多是在配置与集成已有组件(Bootloader、内核、根文件系统),并编写用户态程序或内核驱动,而不是从零写一个“主循环”。
3. 嵌入式 Linux 软件架构
嵌入式 Linux 从“上电”到“应用运行”,软件上通常分为四层,每一层都有明确职责。
3.1 Bootloader(引导加载程序)
- 职责:上电后最先运行的程序;初始化关键硬件(如 DDR、时钟、存储控制器);从存储或网络加载内核镜像和设备树(及可选的 initramfs),并跳转到内核入口。
- 常见形态:U-Boot、U-Boot SPL + U-Boot、厂商提供的 loader(如 Rockchip 的 miniloader + U-Boot)。
- 与本书的关系:泰山派使用 U-Boot,通过环境变量(如
bootargs)把根设备、串口、命令行参数传给内核。
3.2 Kernel(Linux 内核)
- 职责:硬件抽象、进程调度、内存管理、文件系统、网络协议栈;加载设备树描述的驱动;挂载根文件系统;最后启动用户空间第一个进程(如
/sbin/init或 systemd)。 - 与本书的关系:本工程使用
rockchip_linux_defconfig及泰山派设备树tspi-rk3566-user-v10-linux.dts构建内核,生成Image与.dtb,并打包为boot.img。
3.3 RootFS(根文件系统)
- 职责:提供
/下的目录结构、必备命令(如ls、mount)、库、脚本和配置文件;提供 init 程序及启动脚本(如/etc/init.d或 systemd 单元),完成系统服务与应用的启动。 - 与本书的关系:本工程支持 Buildroot 默认 rootfs,也可使用 Ubuntu 24.04 作为根文件系统(见
BUILD.md),通过RK_ROOTFS_SYSTEM=ubuntu24.04与./build.sh rootfs生成ubuntu-rootfs.img。
3.4 Application(应用程序)
- 职责:实现具体业务逻辑,如网络服务、GUI、音视频、AI 推理等。运行在用户态,通过系统调用、设备节点、网络接口等与内核和硬件交互。
四层关系可概括为:Bootloader 加载并启动 Kernel → Kernel 挂载 RootFS 并启动 init → init 拉起各种服务与 Application。
4. 为什么工业控制、消费电子、AIoT 选择 Linux
- 生态丰富:成熟的文件系统、网络协议栈、数据库、脚本语言、容器与云原生工具,便于快速集成和二次开发。
- 多任务与多用户:适合同时跑多个服务、远程登录、权限管理,符合工业与网关场景需求。
- 硬件支持广泛:主流 SoC 厂商都会提供 Linux BSP,驱动与社区资源多。
- AI 与多媒体:RK3566 等 SoC 的 NPU、GPU、VPU 在 Linux 下有成熟 SDK(如 RKNN、Mali、MPP),便于做边缘推理与音视频处理。
- 可维护性与升级:支持远程升级、日志、脚本化运维,适合量产后的问题定位与功能迭代。
5. 嵌入式 Linux 工程师的能力模型与学习路径
- 系统认知:清楚从上电到 Shell 的完整流程,能区分 Bootloader、Kernel、RootFS、应用各自的作用。
- 构建与部署:能使用本工程中的
build.sh完成 uboot、kernel、rootfs、firmware、update 镜像的构建与烧录。 - 用户态开发:交叉编译、Makefile、C 系统编程(文件、进程、线程、网络)、Shell 脚本与自动化。
- 板级与驱动:设备树、GPIO、I2C、SPI、UART、字符设备与 platform 驱动,以及内核调试。
- 工程化能力:Buildroot/Yocto、日志与看门狗、升级与恢复、安全与量产部署。
建议学习路径:先搞清全景与启动流程(本篇),再练用户态与调试(第三篇),然后深入设备树与驱动(第四篇),最后拓展多媒体、AI 与工程化(第五、六篇)。
关键概念说明
- BSP(Board Support Package):板级支持包,一般包括该板子对应的 Bootloader、内核配置与设备树、根文件系统定制和厂商提供的库与工具。本仓库即为 RK3566 泰山派的 BSP 工程。
- 设备树(Device Tree):一种描述硬件拓扑与资源(寄存器、中断、GPIO、时钟等)的数据结构,由 Bootloader 传给内核,内核据此加载对应驱动,避免把板级细节写死在内核里。
- 交叉编译:在 PC(x86_64)上使用针对 ARM64 的编译器生成在开发板上运行的二进制,本工程使用
aarch64-linux-gnu-gcc等工具链。
泰山派实验步骤
实验 1:通过启动日志认识系统的启动阶段
- 准备:泰山派接好电源、串口(连接主机)、存储(TF 卡或 eMMC 已烧录镜像)。
- 串口连接:在主机上打开串口终端(如 minicom、screen、或 IDE 串口工具),波特率一般为 1500000(与设备树中
fiq-debugger的rockchip,baudrate一致)。 - 上电或复位:观察终端输出,按时间顺序可大致看到:
- Bootloader 阶段:U-Boot 或 loader 的版本与初始化信息;
- Kernel 阶段:Linux 版本、设备树、驱动 probe、挂载 rootfs;
- 用户态阶段:systemd 或 init 启动服务、出现登录提示或 Shell。
- 记录:将完整启动日志保存为文本,用不同颜色或注释标出各阶段边界,便于后续章节对照分析。
实验 2:结合泰山派软件包结构理解 BSP 的组成
在工程根目录下执行:
1 | cd /path/to/tspi_linux_sdk_repo_20240131 |
然后浏览以下目录与文件,建立“BSP 由哪些部分组成”的直观认识:
| 路径 | 说明 |
|---|---|
device/rockchip/.BoardConfig.mk |
当前板型配置的软链接,指向 BoardConfig-rk3566-tspi-v10.mk |
device/rockchip/rk356x/BoardConfig-rk3566-tspi-v10.mk |
泰山派板级配置:架构、U-Boot/Kernel 的 defconfig、DTS、rootfs 类型等 |
u-boot/ |
U-Boot 源码与构建产物 |
kernel/ |
内核源码;arch/arm64/boot/dts/rockchip/ 下为泰山派相关设备树 |
buildroot/ |
Buildroot 根文件系统构建(当使用 buildroot rootfs 时) |
ubuntu/ |
Ubuntu 24.04 根文件系统脚本(如 mk-rootfs-noble.sh) |
rockdev/ |
构建后生成的各分区镜像(boot.img、rootfs.img、recovery.img 等) |
理解:一次完整构建会依次生成 U-Boot → Kernel(含 DTB)→ RootFS,再通过 build.sh firmware 和 build.sh updateimg 打包成可烧录的 rockdev/ 与 update.img。
代码讲解
1. 板级配置:BoardConfig-rk3566-tspi-v10.mk
本工程中,泰山派的“选型”和“构建开关”集中在 device/rockchip/rk356x/BoardConfig-rk3566-tspi-v10.mk。下面摘录与“软件架构”直接相关的几项并做说明。
1 | # Target arch |
- RK_ARCH=arm64:目标为 64 位 ARM,与 RK3566 的 Cortex-A55 对应。
- RK_KERNEL_DTS:指定内核使用的设备树基名,构建时会编译
tspi-rk3566-user-v10-linux.dts并打包进boot.img。 - RK_USE_BOOT_AS_RECOVERY=yes:recovery 分区直接使用内核的
boot.img,不再单独编 recovery 镜像,简化维护。
这些变量会被根目录的 build.sh 以及 device/rockchip/common/build.sh 使用,完成 uboot、kernel、rootfs、firmware 的串联。
2. 构建入口:build.sh 与“all”流程
主构建脚本为仓库根目录的 build.sh,实际逻辑在 device/rockchip/common/build.sh。执行 ./build.sh all 时,会依次调用(摘录自脚本逻辑):
build_uboot:编译 U-Boot,生成 loader 与 U-Boot 镜像;build_kernel:编译内核与设备树,生成Image与.dtb,并打成boot.img;build_toolchain:如需则构建交叉工具链;build_rootfs:根据配置构建 Buildroot 或 Ubuntu 等根文件系统,得到rootfs.img;build_recovery:本板为使用boot.img作为 recovery;- 后续
build_firmware/build_updateimg会把各分区镜像打包到rockdev/并生成update.img。
对应“软件架构”:uboot → kernel → rootfs → 打包,与前面四层模型一致。
3. 设备树顶层:tspi-rk3566-user-v10-linux.dts
设备树是“板级硬件描述”,内核和驱动依赖它识别外设。泰山派用户可见的顶层 DTS 为 kernel/arch/arm64/boot/dts/rockchip/tspi-rk3566-user-v10-linux.dts。开头如下:
1 | ; |
- rk3566.dtsi:SoC 级公共节点(CPU、内存、各控制器)。
- tspi-rk3566-core-v10.dtsi:泰山派核心板公共配置(电源、调试串口、音频、部分外设)。
- tspi-rk3566-hdmi-v10.dtsi、tspi-rk3566-csi-v10.dtsi:HDMI 与摄像头等板级功能;注释掉的为未启用功能(如 EDP、DSI、千兆网)。
通过“包含/注释”即可做板级功能裁剪,这是 BSP 中设备树组织的典型方式。
运行结果与现象分析
- 实验 1:串口应看到从 U-Boot 到内核再到 systemd/init 的连续输出;若在某阶段卡住,可初步判断是 Bootloader、内核还是 rootfs/init 问题。
- 实验 2:执行
./build.sh lunch并选择 rk3566-tspi 后,device/rockchip/.BoardConfig.mk应指向BoardConfig-rk3566-tspi-v10.mk;随后执行./build.sh allsave(或all+firmware+updateimg),应在rockdev/下得到boot.img、rootfs.img、recovery.img等,对应 Bootloader 之后要加载的 Kernel+DTB 与 RootFS。
常见错误与排查方法
| 现象 | 可能原因 | 排查建议 |
|---|---|---|
| 串口无输出 | 串口线接错、波特率不对、未选对串口设备 | 确认 TX/RX、GND;波特率试 1500000 或 115200;在主机上确认 ttyUSB0 等设备 |
| 选错板型 | lunch 选了其他 BoardConfig | 重新执行 ./build.sh lunch 选 rk3566-tspi |
| 构建报错缺少工具链 | 未安装 aarch64 交叉编译器或未构建 toolchain | 按 BUILD.md 安装依赖,或执行 ./build.sh toolchain |
| 启动卡在内核或 rootfs | bootargs 中 root= 错误、rootfs 未正确烧录 | 对照第 5、6、8 章检查 bootargs 与分区、镜像 |
本章小结
- 嵌入式系统按处理器形态可分为 MCU、MPU、SoC、SBC;RK3566 为 SoC,泰山派为基于 RK3566 的 SBC。
- 嵌入式 Linux 软件可归纳为四层:Bootloader → Kernel → RootFS → Application,本工程通过
build.sh与 BoardConfig 依次构建 U-Boot、内核(含设备树)、根文件系统并打包为镜像。 - 通过串口观察启动日志可建立“阶段边界”的感性认识;通过浏览
device/rockchip、kernel、u-boot、rockdev等目录可理解 BSP 的组成与构建流程。 - 后续章节将围绕启动流程、存储与分区、U-Boot、内核与设备树、根文件系统等展开,并逐步过渡到用户态开发、设备树与驱动、以及工程化内容。
思考题与扩展实验
- 查阅 RK3566 芯片手册,列出其 CPU 核数、主频、以及 GPU、NPU、VPU 的简要规格,并说明它们在本工程中对应的软件组件(内核、驱动、用户库)可能在哪里体现。
- 在
device/rockchip/common/build.sh中搜索build_kernel和build_rootfs,画出从build.sh all到生成boot.img和rootfs.img的调用关系。 - 若将
tspi-rk3566-user-v10-linux.dts中 HDMI 的#include "tspi-rk3566-hdmi-v10.dtsi"注释掉并重新编译内核,预期启动后显示会有什么变化?在学完设备树章节后再做验证。