基于Yocto为reTerminal构建定制化嵌入式Linux系统实战指南

📅 2026/8/2 15:22:04 👁️ 阅读次数 📝 编程学习
基于Yocto为reTerminal构建定制化嵌入式Linux系统实战指南

1. 项目概述:为什么要在 reTerminal 上折腾 Yocto?

如果你手头有一块 reTerminal,大概率和我一样,是被它那块 5 英寸的 IPS 电容触摸屏、树莓派 CM4 核心模块的灵活性,以及内置的 IMU、RTC 等丰富传感器所吸引。它是个绝佳的嵌入式人机交互(HMI)设备原型平台。但当你拿到手,刷入官方提供的基于 Raspberry Pi OS 的镜像后,可能会隐隐觉得哪里不对:系统有点“胖”,启动不够快,后台服务一堆,自己想深度定制个啥,从内核驱动到根文件系统,都感觉隔着一层纱,无从下手。

这时候,Yocto 就该登场了。简单说,Yocto 不是一个现成的 Linux 发行版,而是一个构建自定义 Linux 系统的框架和工具集合。你可以把它想象成一个高度自动化的“Linux 系统厨房”,你提供“菜谱”(Layer 和配置文件),它就能帮你从源代码开始,编译出完全贴合你硬件(比如 reTerminal)和软件需求(比如只包含 Qt 应用框架和你的一个前台程序)的精简、高效、可复现的 Linux 系统镜像。

为 reTerminal 构建 Yocto 镜像,核心价值在于“掌控力”“优化”。你不再是被动接受一个通用系统,而是主动定义从 U-Boot 引导程序、Linux 内核、驱动、库、到最终应用程序的每一个环节。这对于产品化开发、追求极致启动速度、严格控制系统资源占用、或需要长期稳定维护的工业场景来说,几乎是必经之路。这个过程虽然前期有学习成本,但一旦跑通,后续的迭代、裁剪、问题定位都会变得清晰无比。

2. 核心思路与方案选型:如何为 reTerminal “定制菜谱”

直接从头开始为一块板子构建 Yocto 支持是极其复杂的。幸运的是,开源社区和硬件厂商通常会提供基础“菜谱”(即 Yocto 的 Layer)。我们的策略是“站在巨人的肩膀上,进行针对性改造”

2.1 基础 Layer 选型:Poky + Meta-RaspberryPi

Yocto 项目的核心是Poky,它提供了构建系统最基础的元数据、构建工具(如 BitBake)和参考配置。但 Poky 本身不包含对具体硬件的支持。

对于树莓派生态(包括基于 CM4 的 reTerminal),社区维护的meta-raspberrypi层是我们的不二之选。它包含了树莓派系列板子的 BSP(Board Support Package):内核配置、U-Boot、启动引导方式、GPU 固件等。这是我们的硬件适配基石。

2.2 关键决策:内核与启动引导

reTerminal 的官方系统使用树莓派内核和标准的config.txt启动方式。在 Yocto 世界里,我们有两种主流选择:

  1. 沿用 RaspberryPi 的启动流程:使用树莓派基金会提供的linux-raspberrypi内核,配合bootfiles(start.elf 等 GPU 固件)和config.txt。这是meta-raspberrypi层默认的方式,兼容性最好,能直接使用树莓派生态的闭源 GPU 驱动(VC4)以实现硬件加速。
  2. 使用主线 U-Boot + 主线内核:这是一个更“嵌入式”、更开放的选择。通过 U-Boot 来引导一个更接近主线或特定版本的内核。这种方式对启动流程的控制力更强,但 GPU 加速、某些外设驱动可能需要更多移植工作。

对于 reTerminal 的初次 Yocto 化,我强烈建议选择方案一。我们的首要目标是“跑起来”,并确保显示屏、触摸屏、传感器等关键外设正常工作。meta-raspberrypi已经为我们铺好了大部分的路。后续若有极致定制需求,再考虑方案二。

2.3 我们的构建方案架构

因此,我们的 Yocto “菜谱”将由以下核心层构成:

  • Poky: 构建系统骨架。
  • meta-raspberrypi: 树莓派硬件支持。
  • meta-openembedded: 一个庞大的、社区维护的软件包集合层(meta-oe,meta-python,meta-networking等),为我们提供成千上万个现成的软件包配方(recipes)。
  • 自定义层(例如meta-reterminal: 这是我们工作的核心。将包含:
    • 机器配置文件(conf/machine/reterminal.conf: 定义 reTerminal 的硬件特性,如 CPU 架构、内核类型、UBOOT_MACHINE(如果使用 U-Boot)、包含的硬件特性(如蓝牙、wifi)。
    • 镜像配方文件(recipes-core/images/: 定义我们要构建的系统镜像里具体包含哪些软件包(如 Qt5、触摸屏驱动、我们的应用)。
    • 自定义配方文件: 为 reTerminal 特有的组件(如特定的传感器驱动、屏幕校准工具)或我们的应用程序编写构建规则。

这个架构确保了我们在一个稳定、社区支持良好的基础上,进行精准的、针对 reTerminal 的定制。

3. 环境搭建与 Layer 配置实操

理论说再多,不如动手搭环境。下面是一步步的实操指南。

3.1 准备构建主机环境

Yocto 构建对主机有一定要求。推荐使用 Ubuntu 22.04 LTS 或 20.04 LTS。你需要一块至少 100GB 空闲空间的硬盘(SSD 最佳,能极大缩短构建时间),以及足够的内存(建议 16GB 或以上,8GB 会很吃力)。

首先安装必要的宿主机构建工具:

sudo apt update sudo apt install gawk wget git diffstat unzip texinfo gcc build-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint xterm python3-subunit mesa-common-dev zstd liblz4-tool file locales libacl1

确保你的 locale 设置为 UTF-8,否则构建过程中可能会报错:

sudo locale-gen en_US.UTF-8 export LANG=en_US.UTF-8

3.2 获取 Yocto 核心源码(Poky)和基础层

我们选择 Yocto 的长期支持版本kirkstone(4.0)作为起点,它相对稳定成熟。

# 创建一个工作目录并进入 mkdir ~/yocto-reterminal && cd ~/yocto-reterminal # 克隆 Poky (kirkstone 分支) git clone -b kirkstone https://git.yoctoproject.org/poky.git # 克隆 meta-openembedded (kirkstone 分支) git clone -b kirkstone https://github.com/openembedded/meta-openembedded.git # 克隆 meta-raspberrypi (kirkstone 分支) git clone -b kirkstone https://github.com/agherzan/meta-raspberrypi.git

3.3 创建并配置自定义层meta-reterminal

这是专属于我们项目的层。

# 在 yocto-reterminal 目录下 source poky/oe-init-build-env build # 这条命令会创建一个 `build` 目录并切换进去,同时设置好必要的环境变量。 # 注意:每次新开终端进入构建环境,都需要执行此命令。 # 退出当前构建目录,回到 yocto-reterminal 根目录 cd ~/yocto-reterminal # 创建自定义层的骨架 mkdir -p meta-reterminal/conf/machine mkdir -p meta-reterminal/recipes-core/images mkdir -p meta-reterminal/recipes-kernel/linux mkdir -p meta-reterminal/recipes-graphics/raspberrypi-firmware # 创建层的配置文件 cat > meta-reterminal/conf/layer.conf << EOF # 定义我们层的路径 BBPATH .= ":\${LAYERDIR}" # 定义此层中的配方文件(.bb和.bbappend)的路径 BBFILES += "\${LAYERDIR}/recipes-*/*/*.bb \ \${LAYERDIR}/recipes-*/*/*.bbappend" # 定义此层的优先级,数字越大优先级越高,后添加的层会覆盖先添加层中的同名配置。 BBFILE_COLLECTIONS += "reterminal" BBFILE_PATTERN_reterminal = "^" + "\${LAYERDIR}/" BBFILE_PRIORITY_reterminal = "10" EOF

3.4 编写 reTerminal 机器配置文件

这是最关键的文件之一,它告诉 Yocto 我们正在为 reTerminal 构建系统。

cat > meta-reterminal/conf/machine/reterminal.conf << EOF #@TYPE: Machine #@NAME: reterminal #@DESCRIPTION: Machine configuration for the reTerminal device based on Raspberry Pi CM4 # 继承 meta-raspberrypi 中为 CM4 定义的基础配置 require conf/machine/include/rpi-base.inc # 特别包含 CM4 的配置,它会设置正确的 DTB 等 require conf/machine/include/rpi-cm4.inc # 定义机器名称,会在镜像文件名等地方用到 MACHINE = "reterminal" # 内核配置:使用树莓派提供的内核 PREFERRED_PROVIDER_virtual/kernel = "linux-raspberrypi" # 指定内核版本,这里使用 kirkstone 分支兼容的 5.15 版本 PREFERRED_VERSION_linux-raspberrypi = "5.15.%" # 启动引导配置:使用树莓派标准的 bootfiles 方式(而非U-Boot) RPI_USE_U_BOOT = "0" # 启用 VC4 图形驱动(KMS),这是 HDMI 和 DSI 显示所必需的,包括 reTerminal 的屏幕 # 注意:reTerminal 的 5寸屏通过 DSI 接口连接,需要此驱动 VC4GRAPHICS = "1" # 启用 KMS(Kernel Mode Setting),现代图形栈的基础 ENABLE_SPI_BUS = "1" ENABLE_I2C = "1" # GPU 内存分配,对于 5寸屏和可能的硬件加速,建议分配至少 128MB GPU_MEM = "128" # 定义镜像安装的额外空间,单位 KB。reTerminal eMMC 通常有 8GB 或 32GB,这里预留一些空间。 IMAGE_ROOTFS_EXTRA_SPACE = "65536" # 系统特性:启用 wifi 和蓝牙(reTerminal CM4 模块通常带有) MACHINE_FEATURES += "wifi bluetooth" # 添加触摸屏支持特性 MACHINE_FEATURES += "touchscreen" # 为 reTerminal 指定额外的内核启动参数(如果需要) # 例如,可以强制使用特定的 DSI 显示参数,但通常树莓派内核能自动识别 # KERNEL_DEVICETREE_OVERLAYS += "\${THISDIR}/files/overlays/reterminal-dsi.dtbo" EOF

注意:上面的配置假设树莓派内核能正确驱动 reTerminal 的屏幕。实际上,reTerminal 的 5 寸屏可能需要特定的设备树覆盖(Device Tree Overlay)或内核参数。这通常需要从 reTerminal 官方资料或社区中寻找dtoverlay配置。如果找不到,一个常见的方法是分析官方 Raspberry Pi OS 镜像中/boot/config.txt里关于屏幕的配置,并将其转换到 Yocto 的配置中。我们稍后在问题排查章节会详细讨论。

3.5 配置构建目录(build/conf/local.conf

初始化构建环境后,build/conf/local.conf是主要的用户配置文件。我们需要修改它。

cd ~/yocto-reterminal/build # 使用编辑器(如 nano 或 vim)打开 local.conf nano conf/local.conf

找到并修改以下关键行(如果不存在则添加):

# 指定我们定义的机器类型 MACHINE ??= "reterminal" # 选择构建的镜像类型。我们先从一个基础镜像开始,例如 `core-image-base` # 后续我们会创建自己的镜像配方。这里先注释掉默认的,我们会在后面自定义。 # IMAGE_FSTYPES = "rpi-sdimg" # 更改为我们自定义的镜像类型,例如: # IMAGE_FSTYPES = "tar.bz2 ext4 rpi-sdimg" # 并行构建线程数,根据你的 CPU 核心数设置,可以显著加快构建速度。 # 例如 8 核 CPU 可以设置为 10(略大于核心数以利用 I/O 等待时间) BB_NUMBER_THREADS ?= "8" PARALLEL_MAKE ?= "-j 8" # 下载目录,存放所有下载的源码包。可以指向一个大的公共目录,避免重复下载。 # DL_DIR ?= "\${TOPDIR}/downloads" # 构建缓存目录(SSTATE),可以加速后续构建。多个项目可以共享。 # SSTATE_DIR ?= "\${TOPDIR}/sstate-cache"

3.6 将各层添加到构建系统中

我们需要编辑build/conf/bblayers.conf文件,告诉 BitBake 我们的层结构。

nano conf/bblayers.conf

修改BBLAYERS变量,添加我们所有的层路径(请根据你的实际路径调整):

BBLAYERS ?= " \ /home/your-username/yocto-reterminal/poky/meta \ /home/your-username/yocto-reterminal/poky/meta-poky \ /home/your-username/yocto-reterminal/poky/meta-yocto-bsp \ /home/your-username/yocto-reterminal/meta-openembedded/meta-oe \ /home/your-username/yocto-reterminal/meta-openembedded/meta-python \ /home/your-username/yocto-reterminal/meta-openembedded/meta-networking \ /home/your-username/yocto-reterminal/meta-raspberrypi \ /home/your-username/yocto-reterminal/meta-reterminal \ "

确保路径正确,并且meta-reterminal在最后,因为它的优先级(我们在 layer.conf 中设为 10)较高,可以覆盖前面层的配置。

4. 创建自定义镜像与软件包集成

基础环境搭好了,现在我们来定义最终要烧录到 reTerminal 里的系统镜像。

4.1 创建基础镜像配方

我们不直接使用core-image-base,而是创建一个包含 reTerminal 基础功能的镜像。

cd ~/yocto-reterminal/meta-reterminal/recipes-core/images nano reterminal-base-image.bb

输入以下内容:

# 这是一个为 reTerminal 定制的基础镜像配方 SUMMARY = "A basic console image for the reTerminal device" LICENSE = "MIT" # 继承 core-image 类,它提供了构建镜像的基础功能 inherit core-image # 设置镜像的额外功能特性 IMAGE_FEATURES += "ssh-server-openssh" # 定义要安装的软件包 # 首先,包含一些基础系统工具 CORE_IMAGE_BASE_INSTALL += " \ packagegroup-core-boot \ packagegroup-base-extended \ kernel-modules \ linux-firmware-rpidistro-bcm43455 \ wpa-supplicant \ iw \ crda \ tzdata \ e2fsprogs \ parted \ dosfstools \ util-linux \ vim \ " # 添加树莓派相关的工具和固件 CORE_IMAGE_BASE_INSTALL += " \ rpi-config \ raspi2fb \ userland \ " # 添加 I2C 工具,方便调试传感器(reTerminal 有多个 I2C 设备) CORE_IMAGE_BASE_INSTALL += " \ i2c-tools \ " # 添加 Python3 及一些基础库,很多应用和脚本会用到 CORE_IMAGE_BASE_INSTALL += " \ python3 \ python3-pip \ python3-modules \ " # 清理镜像,移除不必要的文档和包管理器数据库,减小体积 IMAGE_INSTALL:remove = "packagegroup-core-standalone-sdk-target" ROOTFS_RO_UNNEEDED = "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', '${ROOTFS_RO_UNNEEDED_USRMERGE}', '', d)}"

这个镜像配方定义了一个带有 SSH 服务、网络工具、文件系统工具、Python3 环境和基础调试工具的控制台系统。它还没有图形界面。

4.2 构建并测试基础镜像

现在,我们可以尝试第一次构建。

cd ~/yocto-reterminal/build # 设置好环境变量 source ../poky/oe-init-build-env . # 开始构建我们的自定义镜像 bitbake reterminal-base-image

警告:第一次构建会非常漫长(数小时到十几小时,取决于网络和主机性能),因为它需要从网络下载所有源代码(Linux 内核、工具链、各类库等)并从头编译。请确保网络通畅,并且有足够的耐心。

构建成功后,生成的镜像文件位于build/tmp/deploy/images/reterminal/目录下。我们需要的通常是reterminal-base-image-reterminal.rpi-sdimg(如果IMAGE_FSTYPES包含了rpi-sdimg)。你可以使用dd命令或Raspberry Pi Imager将这个.img文件烧录到 SD 卡,插入 reTerminal 的 CM4 模块(如果使用 eMMC,可能需要通过 USB 烧录工具),然后上电启动。

4.3 集成图形界面与触摸屏支持

如果 reTerminal 的亮点在于其屏幕,那么一个图形界面是必不可少的。在嵌入式领域,Qt 是一个流行的选择。我们可以创建一个带 Qt 和触摸屏支持的镜像。

首先,确保meta-raspberrypi层支持我们选择的图形后端(Wayland 或 X11)。meta-raspberrypi通常对waylandvc4graphics有较好的集成。

创建新的镜像配方:

cd ~/yocto-reterminal/meta-reterminal/recipes-core/images nano reterminal-qt-image.bb

输入内容:

SUMMARY = "A Qt5 image with Weston/Wayland for reTerminal touchscreen" LICENSE = "MIT" # 继承我们之前的基础镜像,并添加图形特性 require recipes-core/images/reterminal-base-image.bb # 添加对 Wayland 和 Qt5 的支持 DISTRO_FEATURES:append = " wayland opengl" # 如果使用 X11,则改为: DISTRO_FEATURES:append = " x11 opengl" # 安装 Qt5 相关的软件包组 IMAGE_INSTALL:append = " \ packagegroup-qt5-wayland \ qtwayland \ qtwayland-plugins \ qtbase-fonts \ qtbase-plugins \ qtdeclarative \ qtdeclarative-qmlplugins \ " # 安装 Weston(Wayland 合成器)作为我们的窗口系统 IMAGE_INSTALL:append = " \ weston \ weston-init \ weston-examples \ " # 安装触摸屏校准工具(可选,但建议) IMAGE_INSTALL:append = " \ tslib \ tslib-calibrate \ tslib-tests \ " # 安装一个简单的 Qt 示例应用,用于测试 IMAGE_INSTALL:append = " \ qt5everywheredemo \ " # 设置 Weston 自动启动(通过 systemd 或 inittab,这里以 systemd 为例) # 我们需要创建一个 systemd service 文件,但这通常可以通过 weston-init 包处理。 # 更常见的做法是在镜像构建后,手动修改根文件系统,或创建一个 bbappend 文件来配置 weston.ini。

这个配方构建的镜像将包含 Weston(Wayland 合成器)和 Qt5 应用框架。qt5everywheredemo是一个很好的测试程序,可以验证图形栈和触摸是否正常工作。

4.4 配置 Weston 和触摸屏

为了让 Weston 能正确识别 reTerminal 的触摸屏,我们需要配置weston.ini。创建一个配方来提供自定义配置。

mkdir -p ~/yocto-reterminal/meta-reterminal/recipes-graphics/wayland nano ~/yocto-reterminal/meta-reterminal/recipes-graphics/wayland/weston-ini_%.bbappend

bbappend文件用于修改或追加到已有配方。我们为weston-ini配方添加我们的配置:

# 此文件用于追加配置到 weston.ini FILESEXTRAPATHS:prepend := "\${THISDIR}/files:" # 安装我们自定义的 weston.ini SRC_URI += "file://weston.ini" # 确保我们的配置文件被安装到正确位置 do_install:append() { install -d \${D}\${sysconfdir}/xdg/weston install -m 0644 \${WORKDIR}/weston.ini \${D}\${sysconfdir}/xdg/weston/ }

然后创建对应的配置文件:

mkdir -p ~/yocto-reterminal/meta-reterminal/recipes-graphics/wayland/files nano ~/yocto-reterminal/meta-reterminal/recipes-graphics/wayland/files/weston.ini

weston.ini中,我们需要指定输入设备。reTerminal 的触摸屏通常通过 I2C 连接,在 Linux 输入子系统中可能是event0或类似。最可靠的方法是在第一次启动基础镜像后,通过evtestcat /proc/bus/input/devices来确认触摸屏设备节点。一个示例配置如下:

[core] # 取消注释以禁用屏幕保护 # idle-time=0 # 取消注释以保持屏幕常亮 # dpms-on=false [shell] # 设置背景色 background-color=0x002040 # 使用 kiosk-shell 可以全屏运行一个应用,适合 HMI # shell=kiosk-shell.so [output] name=DSI-1 # 设置屏幕分辨率和刷新率,reTerminal 屏幕是 720x1280 (竖屏) 或 1280x720 (横屏) mode=720x1280@60 # 如果需要旋转屏幕,可以使用 transform 选项,例如旋转90度 # transform=90 [input] # 配置触摸屏,device 需要根据实际情况修改,如 /dev/input/event0 name=reterminal-touchscreen device=/dev/input/event0 # 指定触摸屏的坐标变换,如果需要旋转触摸坐标以匹配屏幕旋转 # calibration_matrix=0 1 0 -1 0 1 0 0 1

重要提示device=/dev/input/eventX中的X不是固定的,它取决于内核加载驱动的顺序。在生产环境中,更好的做法是使用udev规则通过设备的属性(如供应商ID、产品ID)来创建静态符号链接,例如/dev/input/touchscreen,然后在weston.ini中引用这个符号链接。这需要额外的udev规则配方。

4.5 构建 Qt 镜像并烧录测试

更新build/conf/local.conf,将MACHINE设置为reterminal,并指定构建我们的 Qt 镜像:

cd ~/yocto-reterminal/build # 确保 MACHINE 设置正确 echo 'MACHINE = "reterminal"' >> conf/local.conf # 开始构建 bitbake reterminal-qt-image

构建完成后,烧录新的reterminal-qt-image-reterminal.rpi-sdimg到 SD 卡,启动 reTerminal。如果一切顺利,你应该能看到 Weston 桌面启动,并且可以通过触摸屏与qt5everywheredemo交互。

5. 深度定制与优化:内核、驱动与启动速度

当基础系统跑通后,我们就可以进行更深度的定制,以满足特定产品需求。

5.1 内核配置与设备树覆盖

reTerminal 的某些特定硬件(如精确的屏幕参数、额外的 GPIO 功能)可能需要调整内核配置或使用设备树覆盖(Device Tree Overlay)。

添加自定义内核配置片段:创建一个.cfg文件,启用或禁用特定的内核模块。

mkdir -p ~/yocto-reterminal/meta-reterminal/recipes-kernel/linux/files nano ~/yocto-reterminal/meta-reterminal/recipes-kernel/linux/files/reterminal.cfg

例如,增加 SPI 缓冲区大小或启用某个驱动:

# 增加 SPI 缓冲区大小 CONFIG_SPI_SPIDEV=y CONFIG_SPI_SPIDEV_MAX_SIZE=4096 # 启用某个传感器驱动 CONFIG_INV_MPU6050_IIO=y

然后创建一个bbappend文件来应用到linux-raspberrypi内核:

nano ~/yocto-reterminal/meta-reterminal/recipes-kernel/linux/linux-raspberrypi_%.bbappend

内容:

# 添加我们的内核配置片段 SRC_URI += "file://reterminal.cfg" FILESEXTRAPATHS:prepend := "\${THISDIR}/files:" # 将我们的配置片段合并到内核配置中 do_configure:append() { cat \${WORKDIR}/reterminal.cfg >> \${B}/.config }

使用设备树覆盖:如果 reTerminal 官方提供了.dtbo文件,我们可以将其集成到 Yocto 构建中。通常需要将其放在meta-reterminal/recipes-bsp/rpi-firmware/files/overlays/目录下,并修改rpi-firmware的配方来包含它。这是一个更高级的主题,需要参考meta-raspberrypi中处理 overlays 的方式。

5.2 系统服务与自启动应用

对于 HMI 设备,我们通常希望系统启动后自动运行我们的主应用程序。这可以通过systemd服务实现。

创建你的应用程序配方(假设应用名为my-hmi-app):

mkdir -p ~/yocto-reterminal/meta-reterminal/recipes-apps/my-hmi-app nano ~/yocto-reterminal/meta-reterminal/recipes-apps/my-hmi-app/my-hmi-app_1.0.bb

编写配方内容,定义如何获取源码(本地文件、Git 等)、编译和安装。然后,创建一个systemd服务文件:

mkdir -p ~/yocto-reterminal/meta-reterminal/recipes-apps/my-hmi-app/files nano ~/yocto-reterminal/meta-reterminal/recipes-apps/my-hmi-app/files/my-hmi-app.service

服务文件示例:

[Unit] Description=My reTerminal HMI Application After=weston.service Requires=weston.service [Service] Type=simple # 假设你的应用安装在 /usr/bin ExecStart=/usr/bin/my-hmi-app Restart=on-failure User=root [Install] WantedBy=multi-user.target

在应用的配方中,安装这个服务文件并启用它:

do_install:append() { install -d \${D}\${systemd_system_unitdir} install -m 0644 \${WORKDIR}/my-hmi-app.service \${D}\${systemd_system_unitdir}/ } SYSTEMD_SERVICE:\${PN} = "my-hmi-app.service" SYSTEMD_AUTO_ENABLE:\${PN} = "enable"

最后,在你的镜像配方(如reterminal-qt-image.bb)中添加my-hmi-app包。

5.3 启动速度优化

嵌入式设备对启动速度往往有要求。Yocto 提供了多种优化手段:

  • InitramfsInitrd:对于简单的系统,可以考虑将根文件系统构建进内核(Initramfs),避免单独的根文件系统挂载延迟。但这会增加内核大小。
  • Systemd 优化:分析systemd-analyze blame输出,禁用不必要的服务。在 Yocto 中,可以通过DISTRO_FEATURESIMAGE_INSTALL来裁剪服务。
  • 文件系统选择ext4是平衡性能和可靠性的选择。对于只读根文件系统,可以考虑squashfs,它压缩率高,加载快。tmpfs可用于/var/tmp等易变目录。
  • 并行初始化:确保systemdDefaultDependencies=noAfter=/Before=关系设置合理,允许更多服务并行启动。
  • 内核裁剪:使用bitbake -c menuconfig virtual/kernel进入内核配置菜单,移除所有不需要的驱动和模块,生成一个更小的内核。

优化是一个迭代过程,需要结合systemd-analyze plot > boot.svg生成的图表进行分析,找出瓶颈。

6. 常见问题排查与实战心得

在 reTerminal 上构建 Yocto 的过程中,我踩过不少坑,这里总结几个最常见的问题和解决思路。

6.1 屏幕不亮或显示异常

这是最可能遇到的问题。

  • 症状:系统似乎启动了(串口有输出),但 reTerminal 屏幕黑屏或白屏。
  • 排查
    1. 检查内核日志:通过串口(reTerminal 有调试串口引脚)连接,查看内核启动日志,关注drmvc4panel相关的信息。是否有加载失败或错误?
    2. 确认设备树:确保使用的 DTB 文件正确。对于 CM4,通常是bcm2711-rpi-cm4.dtb。检查config.txtdtoverlay的配置。reTerminal 屏幕可能需要特定的 overlay,例如vc4-kms-dsi-7inch或类似。你需要从 reTerminal 的官方资料中确认正确的 overlay 名称和参数。
    3. 在 Yocto 中配置:在reterminal.conf机器配置文件中,可以通过RPI_EXTRA_CONFIG变量来追加config.txt的内容。例如:
      RPI_EXTRA_CONFIG += "\n\ # 强制使用特定 DSI 显示参数\n\ dtoverlay=vc4-kms-dsi-7inch\n\ # 如果需要旋转屏幕\n\ display_rotate=1\n\ "
    4. 检查 GPU 内存:确保GPU_MEM设置足够(如 128 或 256)。过小的 GPU 内存可能导致帧缓冲区分配失败。

6.2 触摸屏无响应或坐标错误

  • 症状:屏幕显示正常,但触摸没反应,或者触摸点与显示位置不对应。
  • 排查
    1. 确认输入设备节点:在系统启动后,通过ls /dev/input/by-path/evtest命令找到触摸屏对应的eventX。检查是否有事件输出。
    2. Weston 配置:确保weston.ini中的device=指向正确的设备节点。考虑使用udev规则固定设备节点。
    3. 坐标校准:如果触摸有反应但坐标不对,需要使用tslib进行校准。在镜像中安装tslib-calibrate,启动后运行ts_calibrate进行五点校准。校准数据会保存在/etc/pointercal。你可以创建一个启动脚本,在首次启动时自动运行校准,或者将校准好的文件打包进镜像。
    4. 内核驱动:确认触摸屏的 I2C 驱动是否正确加载。检查内核日志中关于ft5x06edt-ft5x06goodix等常见触摸芯片驱动的信息。

6.3 构建失败:配方解析错误或下载失败

  • 症状bitbake命令执行失败,报错关于parsefetch
  • 排查
    1. 层依赖和路径:仔细检查bblayers.conf,确保所有层的路径都正确,并且没有拼写错误。确保meta-reterminallayer.conf语法正确。
    2. 配方语法:Yocto 的.bb.bbappend文件对空格和制表符非常敏感。确保使用空格缩进,而不是制表符。检查变量赋值和函数调用的语法。
    3. 网络问题:下载失败通常是因为网络连接问题或源地址不可用。Yocto 会从多个源(如 GitHub、Kernel.org 等)下载代码。可以尝试配置代理,或者使用premirror功能将常用源码缓存到本地服务器。
    4. 许可问题:某些软件包需要接受许可协议。例如,树莓派的 GPU 固件。你可能需要在local.conf中添加LICENSE_FLAGS_ACCEPTED = "commercial"等。

6.4 镜像过大

  • 症状:生成的.rpi-sdimg文件远超预期。
  • 优化
    1. 裁剪IMAGE_INSTALL:仔细检查镜像配方中安装的每一个包,移除所有非必需的包。使用bitbake -g <image-name>生成依赖图,分析哪些包被引入。
    2. 使用rm_work:在local.conf中启用INHERIT += "rm_work",这会在构建完成后删除每个配方的临时工作目录,虽然不能减小最终镜像,但能节省构建空间。
    3. 压缩根文件系统:考虑使用squashfsubifs(针对 NAND Flash)等压缩文件系统作为只读根文件系统。
    4. 移除调试符号:在local.conf中设置INHIBIT_PACKAGE_DEBUG_SPLIT = "1"INHIBIT_PACKAGE_STRIP = "0"来移除调试符号,但会使得问题调试困难。

6.5 无线网络(WiFi/蓝牙)无法使用

  • 症状iwconfig看不到wlan0,或蓝牙设备未出现。
  • 排查
    1. 固件:确保镜像中包含了正确的固件。对于 CM4 上的 Cypress CYW43455 芯片,需要linux-firmware-rpidistro-bcm43455包(已在我们的基础镜像配方中包含)。
    2. 内核配置:确认内核配置中启用了CONFIG_BRCMFMAC(用于 WiFi)和CONFIG_BT_HCIUARTCONFIG_BT_BCM(用于蓝牙)。meta-raspberrypi通常已经配置好。
    3. 设备树:CM4 的 WiFi/BT 是通过 SDIO 和 UART 连接的,设备树中需要正确启用。bcm2711-rpi-cm4.dtb应该已经包含。检查内核启动日志是否有brcmfmachci_uart相关的错误。
    4. 用户空间工具:确保安装了wpa-supplicantiwbluez5等工具。

实战心得

  1. 迭代构建:不要试图一次就构建完美的最终镜像。采用迭代方式:先构建一个最小能启动的系统(甚至只是内核和 busybox),通过串口确认基础功能。然后逐步添加图形、触摸、网络、应用。每步都测试,能快速定位问题所在层。
  2. 善用开发 shellbitbake -c devshell virtual/kernel可以进入内核源码目录进行手动配置和编译测试,非常方便调试内核问题。
  3. 维护自己的层:将所有的自定义配置、补丁、配方都放在meta-reterminal层中。这样当上游的pokymeta-raspberrypi更新时,你可以相对容易地合并更新,并保持你的定制内容独立、清晰。
  4. 版本控制:将整个yocto-reterminal目录(包括downloadssstate-cache可以排除)置于 Git 版本控制之下。这能完美复现每一次构建,是团队协作和项目维护的生命线。

为 reTerminal 构建 Yocto 系统是一个典型的嵌入式 Linux 定制过程,涉及 BSP 适配、驱动集成、系统裁剪和性能优化。虽然入门有门槛,但一旦掌握了 Yocto 的工作流,你将获得对嵌入式系统前所未有的控制力,能够打造出真正符合产品需求的、高效稳定的专属系统。这个过程本身,就是对嵌入式 Linux 系统架构一次深刻的理解和实践。