第三章:Bootloader与内核:U-Boot移植与配置、Linux内核裁剪与编译、设备树(DTS)基础

各位同学,今天咱们聊聊嵌入式Linux在POS机上电后,最先发生的那些事。说白了,就是Bootloader怎么把内核请进内存,内核又怎么认识你的硬件。这部分我踩过的坑最多,咱们一个一个来拆解。

3.1 U-Boot移植与配置:让板子先跑起来

U-Boot,全称是Universal Bootloader。你可以把它理解成PC上的BIOS,但比BIOS灵活得多。POS机一上电,CPU首先执行的就是U-Boot。它的任务很简单:初始化硬件,加载内核。

我刚开始做POS机项目时,拿到一块新板子,第一件事就是移植U-Boot。嗯,这里要注意,移植不是从零写代码,而是基于现有板级配置修改。

3.1.1 获取与解压U-Boot源码

从官方仓库或芯片厂商的Github拉取代码。我个人习惯用denx.de的官方主线版本,因为社区支持好。解压后,你会看到这样的目录结构:

u-boot/
├── arch/          # CPU架构相关代码
├── board/         # 板级支持包
├── configs/       # 默认配置文件
├── drivers/       # 驱动
├── dts/           # 设备树源文件
└── include/       # 头文件

关键在 board/configs/ 目录。POS机常用的主控,比如全志、瑞芯微、NXP i.MX系列,都有现成的参考板。

3.1.2 配置U-Boot

配置U-Boot就像给汽车选配置。你想想看,你的POS机用的是什么CPU?多大的DDR?有没有NAND Flash?这些都要告诉U-Boot。

以我手头一个基于NXP i.MX6ULL的POS机项目为例:

make mx6ull_pos_defconfig   # 假设我们已经创建了默认配置
make menuconfig             # 图形化配置界面

在menuconfig里,我通常会做这几件事:

  • 设置串口波特率:POS机调试串口一般用115200,别搞错了,否则打印乱码。
  • 配置DDR参数:这个最坑。DDR时序参数错了,板子直接死给你看。我曾经因为一个时序参数抄错了,折腾了两天。
  • 使能网络支持:POS机需要网络升级固件,所以网卡驱动必须开。
  • 关闭不需要的功能:比如USB HOST、复杂的文件系统支持,能省则省,减少启动时间。
我的小技巧:第一次移植时,先找一个芯片厂商提供的评估板配置,在此基础上改。别自己从头配,那会疯的。

3.1.3 编译与烧录

配置好了,编译就简单了:

make -j4
# 生成 u-boot.imx 或 u-boot.bin,取决于芯片

烧录方式因芯片而异。i.MX系列可以用SD卡启动,也可以用USB下载工具。我记得第一次烧录时,忘了设置启动模式跳线,板子死活没反应。后来发现是拨码开关没拨对。

3.2 Linux内核裁剪与编译:给POS机瘦身

POS机不是服务器,不需要跑全套桌面Linux。内核裁剪,说白了就是去掉你用不到的驱动和功能。一个完整的Linux内核有上万个驱动,你的POS机可能只用到了几十个。

3.2.1 获取内核源码

同样,从芯片厂商的官方仓库拉取。比如全志的BSP内核,或者主线内核。我建议用厂商提供的长期支持版本,因为驱动适配好。

git clone https://github.com/xxx/linux-pos.git
cd linux-pos
make ARCH=arm pos_defconfig   # 加载POS机默认配置

3.2.2 裁剪步骤

进入配置界面:

make ARCH=arm menuconfig

这里我一般按这个顺序裁剪:

  1. 关闭不用的架构支持:只保留ARM,其他全关。
  2. 关闭不用的驱动:POS机不需要显卡驱动、声卡驱动、蓝牙驱动。把这些都去掉,内核能小一半。
  3. 精简文件系统支持:只保留ext4、FAT、NFS(调试用)。其他像Btrfs、XFS,用不到就关。
  4. 关闭调试选项:发布版本一定要关掉 Kernel debugging,否则内核又大又慢。

关键点:裁剪后,内核镜像大小最好控制在3MB以内。POS机的Flash空间很宝贵,你想想看,一个内核占10MB,那应用放哪?

3.2.3 编译与验证

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
# 生成 zImage 或 uImage

编译完成后,用 size 命令看看内核大小:

arm-linux-gnueabihf-size vmlinux
# 输出类似:text    data     bss     dec     hex
#         2845672 123456  78901  3048029  2e85dd

如果text段超过4MB,说明你裁剪得还不够狠。我曾经把一个内核从8MB裁到2.8MB,启动时间从12秒降到了4秒。效果立竿见影。

注意:裁剪时别把POS机必需的驱动关了,比如触摸屏、打印机串口、Wi-Fi模块。我见过有人把I2C驱动关了,结果触摸屏不工作,查了半天才发现。

3.3 设备树(DTS)基础:让内核认识你的硬件

设备树,英文叫Device Tree,缩写DTS。它的作用就是告诉内核:你的POS机上有哪些硬件,它们怎么连接的。

以前的内核,硬件信息都硬编码在C代码里。换一个板子就要改代码重新编译。有了设备树,硬件描述和内核代码分开了。你改硬件,只需要改DTS文件,不用动内核。

3.3.1 DTS文件结构

一个典型的POS机DTS文件长这样:

/dts-v1/;

#include "imx6ull.dtsi"   // 包含CPU核心定义

/ {
    model = "POS Terminal v1.0";
    compatible = "mycompany,pos-v1", "fsl,imx6ull";

    chosen {
        stdout-path = &uart1;
    };

    memory {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;  // 256MB DDR
    };

    &uart1 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
    };

    &i2c1 {
        clock-frequency = <100000>;
        status = "okay";

        touch: touch@38 {
            compatible = "goodix,gt911";
            reg = <0x38>;
            interrupt-parent = <&gpio1>;
            interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
        };
    };
};

你看,这里定义了内存大小、串口、I2C总线、触摸屏。每个硬件节点都有 compatible 属性,内核通过这个字符串找到对应的驱动。

3.3.2 编译DTS

DTS文件不能直接给内核用,要编译成二进制DTB文件:

dtc -I dts -O dtb -o pos.dtb pos.dts

或者在内核编译时一起生成:

make ARCH=arm dtbs

生成的 pos.dtb 文件,U-Boot会把它加载到内存,然后传递给内核。

3.3.3 调试设备树

设备树写错了,内核可能启动到一半就挂了。我常用的调试方法:

  • 查看内核启动日志:用 dmesg | grep -i "dtb\|of\|device tree" 看有没有错误。
  • 检查设备树节点:在板子上执行 ls /proc/device-tree/,看看节点有没有生成。
  • 反编译DTB:用 dtc -I dtb -O dts -o dump.dts pos.dtb 看看实际加载的设备树对不对。
避坑指南:我曾经在DTS里把GPIO号写错了,结果触摸屏中断一直触发不了。后来用示波器量引脚才发现,硬件上用的是GPIO1_IO09,我写成了GPIO1_IO08。差一个数字,折腾了一下午。

3.4 启动流程串联

最后,咱们把整个流程串起来。POS机启动时,大致经历这几个阶段:

阶段 执行内容 时间
1. ROM Code 芯片内部固件,初始化时钟、DDR ~100ms
2. U-Boot SPL 加载U-Boot主程序 ~200ms
3. U-Boot主程序 初始化外设,加载内核和设备树 ~500ms
4. Linux内核 解压、初始化、挂载根文件系统 ~2s
5. 应用程序 启动POS机主程序 ~1s

整个启动过程,控制在3-4秒内是比较理想的。如果超过5秒,用户就会觉得卡。我优化过一个项目,把U-Boot的启动延时从2秒降到0.5秒,就是去掉了不必要的驱动初始化和打印信息。

好了,这一章的内容就这些。U-Boot移植、内核裁剪、设备树,这三样是嵌入式Linux开发的看家本领。你把这些搞透了,POS机项目就成功了一半。下一章咱们聊聊根文件系统的构建,那是应用软件的家。