Blog:
嵌入式Linux下使用 Plymouth 实现开机画面示例

Friday, January 26, 2024

1). 简介

嵌入式 Linux 下传统实现 Splash Screen 的方式是通过替换 kernel 默认的 TUX 小企鹅 logo 为定制的开机画面图片来实现嵌入式设备开机图片,虽然比较成熟且可以保证开机画面加载比较早,但是存在的问题首先是对嵌入式设备不同显示接口的兼容性不好,另外每次修改适配都需要重新编译内核,维护起来不是很方便,然后就是只能支持静态图片无法支持动画。基于上述原因,使用专门的 Splash Screen 工具来实现开机画面逐渐成为嵌入式设备的主流方向,本文就简单演示使用 Plymouth 工具来实现动态开机画面的示例。

本文所演示的平台来自于Toradex Verdin iMX8MM  嵌入式平台,基于 NXP iMX8M Mini 系列 ARM 处理器,主要核心架构为 Cortex-A53 


2). 硬件准备

a).  Verdin iMX8MM ARM核心版配合Dahlia载板,并通过 DSI-LVDS Adapter 连接 10inch LVDS 液晶显示屏以及调试串口以便测试。


3). 关于 Plymouth

a). Plymouth 是一个实现 Linux 启动过程中开机画面的工具软件,其启动的时间非常早,通过 initramfs 帮助可以在 Linux 内核加载同时启动,甚至要早于 Linux rootfs 文件系统挂载。Plymouth 可以方便的实现开关机图片或者动画。

b). 关于 Plymouth 更多详细介绍以及源代码请自行参考如下资料。

./ Plymouth 官方页面

https://www.freedesktop.org/wiki/Software/Plymouth/


./ Plymouth 源代码

https://gitlab.freedesktop.org/plymouth/plymouth


./ Plymouth 深入配置使用说明

https://wiki.archlinux.org/title/Plymouth


4). 通过 Ycoto 环境配置 Plymouth 并编译 Ycoto Linux BSP Image

a). 配置 Ycoto Project 编译环境

./ 参考这里配置基本的 Ycoto Project 编译环境

https://developer.toradex.cn/linux-bsp/os-development/build-yocto/build-a-reference-image-with-yocto-projectopenembedded


./ 参考如下文章配置定制化 layer

https://www.toradex.cn/blog/tong-guo-yocto-project-ding-zhi-qian-ru-shi-yocto-linux-jing-xiang


b). 在定制化 layer meta-customer-demos 下面添加 layer 配置文件

$ mkdir -p ../oe_core/layers/meta-customer-demos/conf
$ cd .../oe_core/layers/meta-customer-demos/conf
### create layer.conf file ###
# We have a conf and classes directory, append to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"

BBFILE_COLLECTIONS += "customer-demos"
BBFILE_PATTERN_customer-demos = "^${LAYERDIR}/"
BBFILE_PRIORITY_customer-demos = "24"

# Let us add layer-specific bbappends which are only applied when that
# layer is included in our configuration
BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bbappend' % layer \
             for layer in BBFILE_COLLECTIONS.split())}"
# Add layer-specific bb files too
BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bb' % layer \
             for layer in BBFILE_COLLECTIONS.split())}"

LAYERDEPENDS_customer-demos = " \
  core \
  yocto \
  openembedded-layer gnome-layer multimedia-layer networking-layer \
"
LAYERSERIES_COMPAT_customer-demos = "hardknott honister kirkstone"


c). 在定制化 layer meta-customer-demos 下面添加 Plymouth 相关配置文件

./ 增加 Plymouth bb file

$ cd .../oe_core/layers/meta-customer-demos/
$ mkdir -p recipes-core/plymouth
$ cd recipes-core/plymouth
### cteate plymouth_%.bbappend file ###
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI += " \
file://toradexlogo-white.png \
file://spinner.plymouth \
"

PACKAGECONFIG = "pango drm"

EXTRA_OECONF += "--with-udev --with-runtimedir=/run"

do_install:append () {
install -m 0644 ${WORKDIR}/toradexlogo-white.png ${D}${datadir}/plymouth/themes/spinner/watermark.png
install -m 0644 ${WORKDIR}/spinner.plymouth ${D}${datadir}/plymouth/themes/spinner/spinner.plymouth
}


./ 添加 Plymouth 使用的 theme 文件 和 background logo 图片文件,这里使用的是一个配合屏幕分辨率的白色背景图片,因此 spinner 图标会被遮盖,实际使用可以根据需要修改图片文件和 theme 配置。

$ mkdir files
$ cp .../toradexlogo-white.png files
$ cd files
### cteate spinner theme file spinner.plymouth ###
[Plymouth Theme]
Name=Spinner
Description=Adoption of official Spinner Theme for Toradex.
ModuleName=two-step

[two-step]
Font=Cantarell 12
TitleFont=Cantarell Light 30
ImageDir=/usr/share/plymouth/themes/spinner
DialogHorizontalAlignment=.5
DialogVerticalAlignment=.382
TitleHorizontalAlignment=.5
TitleVerticalAlignment=.382
HorizontalAlignment=.5
VerticalAlignment=.7
WatermarkHorizontalAlignment=.5
WatermarkVerticalAlignment=.45
Transition=none
TransitionDuration=0.0
BackgroundStartColor=0x000000
BackgroundEndColor=0x000000
ProgressBarBackgroundColor=0x606060
ProgressBarForegroundColor=0xffffff
MessageBelowAnimation=true


d). 由于 Plymouth 是文件系统组件,通过 Linux kernel 加载完成后在使能systemd 来启动,这样就会导致比较大的延迟;为了尽可能使 Plymouth 在系统启动过程中尽早启动,可以添加包含 Plymouth Initramfs 镜像使得 Plymouth Linux Kernel 加载过程中即同步启动了。

./ 添加 Initramfs bb 定义以及相关文件,对应需要 files 目录下的相关文件请参考这里

$ cd .../oe_core/layers/meta-customer-demos/recipes-core
$ mkdir -p initramfs-framework/files
$ cd initramfs-framework
### cteate initramfs-framework_1.0.bbappend file ###
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI += "\
  file://plymouth \
  file://kmod \
  file://0001-Mount-run-with-tmpfs.patch \
  file://0002-only-scan-for-block-devices.patch \
"

PACKAGES:append = " \
  initramfs-module-plymouth \
  initramfs-module-kmod \
"

SUMMARY:initramfs-module-plymouth = "initramfs support for plymouth"
RDEPENDS:initramfs-module-plymouth = "${PN}-base plymouth ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-udev-rules', '', d)}"
FILES:initramfs-module-plymouth = "/init.d/02-plymouth"

SUMMARY:initramfs-module-kmod = "initramfs support for loading kernel modules"
RDEPENDS:initramfs-module-kmod = "${PN}-base"
FILES:initramfs-module-kmod = "\
  /init.d/01-kmod \
  /etc/modules-load.d/* \
"

do_install:append() {
  install -m 0755 ${WORKDIR}/plymouth ${D}/init.d/02-plymouth
  install -m 0755 ${WORKDIR}/kmod ${D}/init.d/01-kmod
}

# Adding modules so plymouth can show the splash screen during boot
SRC_URI:append:mx8-nxp-bsp = " file://50-imx8-graphics.conf"
RDEPENDS:initramfs-module-kmod:append:mx8-nxp-bsp = " \
  kernel-module-display-connector \
  kernel-module-lontium-lt8912b \
"

do_install:append:mx8-nxp-bsp() {
  install -d ${D}/etc/modules-load.d/
  install -m 0755 ${WORKDIR}/50-imx8-graphics.conf ${D}/etc/modules-load.d/50-imx8-graphics.conf
}


./ 添加 initramfs image 定义文件

$ cd .../oe_core/layers/meta-customer-demos/recipes-core
$ mkdir images
$ cd images
### cteate initramfs-plymouth-splash-image.bb file ###
DESCRIPTION = "Toradex plymouth splash demo initramfs image"

PACKAGE_INSTALL = "initramfs-framework-base initramfs-module-udev \
  initramfs-module-rootfs initramfs-module-debug \
  initramfs-module-plymouth ${VIRTUAL-RUNTIME_base-utils} base-passwd \
  initramfs-module-kmod"

SYSTEMD_DEFAULT_TARGET = "initrd.target"

# Do not pollute the initrd image with rootfs features
IMAGE_FEATURES = "splash"

export IMAGE_BASENAME = "initramfs-plymouth-splash-image"
IMAGE_LINGUAS = ""

LICENSE = "MIT"

IMAGE_FSTYPES = "cpio.gz"
IMAGE_FSTYPES:remove = "wic wic.gz wic.bmap wic.vmdk wic.vdi ext4 ext4.gz teziimg"

IMAGE_CLASSES:remove = "image_type_torizon image_types_ostree image_types_ota image_repo_manifest license_image qemuboot"

# avoid circular dependencies
EXTRA_IMAGEDEPENDS = ""

inherit core-image nopackages

IMAGE_ROOTFS_SIZE = "8192"

# Users will often ask for extra space in their rootfs by setting this
# globally.  Since this is a initramfs, we don't want to make it bigger
IMAGE_ROOTFS_EXTRA_SPACE = "0"
IMAGE_OVERHEAD_FACTOR = "1.0"

BAD_RECOMMENDATIONS += "busybox-syslog"


e). 由于增加了 initramfs image,就需要修改 distroboot 启动文件 boot.scr 来调整启动进程,这里通过修改 u-boot-distro-boot 文件来适配,对应的 files 目录下的文件完整内容请参考这里

$ cd .../oe_core/layers/meta-customer-demos/
$ mkdir -p recipes-bsp/u-boot/files
$ cd recipes-bsp/u-boot
### cteate u-boot-distro-boot.bbappend file ###
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI:append = " \
file://boot.cmd.in \
"


f). 另外,对于 Verdin iMX8M Mini,由于显示部分是通过 DSI-LVDS Bridge 来实现的,为了使得在 initramfs 阶段就可以加载相关驱动,需要修改 Linux Kernel 配置,而对于其他 iMX8/iMX8X/iMX8MP 如果是原生 LVDS/HDMI 接口则无需修改。

$ cd .../oe_core/layers/meta-customer-demos/
$ mkdir -p recipes-kernel/linux/files
$ cd recipes-kernel/linux
### cteate linux-toradex%.bbappend file ###
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

# Prevent the use of in-tree defconfig
unset KBUILD_DEFCONFIG

SRC_URI += "\ 
  file://defconfig \
  "


./ files 目录下的完整 defconfig 文件请见这里,主要修改了如下几个驱动的配置

-CONFIG_DRM_PANEL_LVDS=m
+CONFIG_DRM_PANEL_LVDS=y

-CONFIG_DRM_SEC_MIPI_DSIM=m
+CONFIG_DRM_SEC_MIPI_DSIM=y

-CONFIG_DRM_TI_SN65DSI83=m
+CONFIG_DRM_TI_SN65DSI83=y

-CONFIG_DRM_IMX_SEC_DSIM=m
+CONFIG_DRM_IMX_SEC_DSIM=y


g). 最后配置完成的 meta-customer-demos 文件结构如下

$ tree meta-customer-demos/
meta-customer-demos/
├── conf
│   └── layer.conf
├── recipes-bsp
│   └── u-boot
│       ├── files
│       │   └── boot.cmd.in
│       └── u-boot-distro-boot.bbappend
├── recipes-core
│   ├── images
│   │   ├── initramfs-ostree-torizon-image.bb
│   │   └── initramfs-plymouth-splash-image.bb
│   ├── initramfs-framework
│   │   ├── files
│   │   │   ├── 0001-Mount-run-with-tmpfs.patch
│   │   │   ├── 0002-only-scan-for-block-devices.patch
│   │   │   ├── 50-imx8-graphics.conf
│   │   │   ├── kmod
│   │   │   ├── plymouth
│   │   │   └── rootfs
│   │   └── initramfs-framework_1.0.bbappend
│   └── plymouth
│       ├── files
│       │   ├── spinner.plymouth
│       │   └── toradexlogo-white.png
│       └── plymouth_%.bbappend
└── recipes-kernel
  └── linux
      ├── files
      │   └── defconfig
      └── linux-toradex%.bbappend

13 directories, 17 files


h). 为了将 initramfs 集成到编译生成的 Image 压缩包内,需要修改如下 image_type 配置文件

--- a/layers/meta-toradex-bsp-common/classes/image_type_tezi.bbclass
+++ b/layers/meta-toradex-bsp-common/classes/image_type_tezi.bbclass
@@ -8,7 +8,7 @@
WKS_FILE_DEPENDS:append = " tezi-metadata virtual/dtb"
DEPENDS += "${WKS_FILE_DEPENDS}"
IMAGE_BOOT_FILES_REMOVE = "${@make_dtb_boot_files(d) if d.getVar('KERNEL_IMAGETYPE') == 'fitImage' else ''}"
-IMAGE_BOOT_FILES:append = " overlays.txt ${@'' if d.getVar('KERNEL_IMAGETYPE') == 'fitImage' else 'overlays/*;overlays/'}"
+IMAGE_BOOT_FILES:append = " overlays.txt initramfs-plymouth-splash-image-${MACHINE}.cpio.gz;initramfs-plymouth-splash-image.img ${@'' if d.getVar('KERNEL_IMAGETYPE') == 'fitImage' else 'overlays/*;overlays/'}"
IMAGE_BOOT_FILES:remove = "${IMAGE_BOOT_FILES_REMOVE}"

RM_WORK_EXCLUDE += "${PN}"


i). 修改 build/conf/bblayer.conf 文件添加相关 layer

--- a/build/conf/bblayers.conf     2023-03-30 11:13:22.946533642 +0800
+++ b/build/conf/bblayers.conf    2023-11-17 16:03:01.666129480 +0800
@@ -35,6 +35,7 @@
 ${TOPDIR}/../layers/meta-freescale-distro \
 ${TOPDIR}/../layers/meta-toradex-demos \
 ${TOPDIR}/../layers/meta-qt5 \
+  ${TOPDIR}/../layers/meta-customer-demos \
 \
 \
 ${TOPDIR}/../layers/meta-toradex-distro \


j). 修改 build/conf/local.conf 文件,增加 Plymouth initramfs 相关定义

# add plymouth support
CORE_IMAGE_EXTRA_INSTALL += "plymouth"
INITRAMFS_IMAGE = "initramfs-plymouth-splash-image"
INITRAMFS_FSTYPES = "cpio.gz"


k). 重新编译生成 Ycoto Linux BSP Image

$ MACHINE="verdin-imx8mm" PARALLEL_MAKE="-j 4" BB_NUMBER_THREADS="4" bitbake tdx-reference-multimedia-image


l). 参考这里的说明将上述修改下重新编译生成的 Ycoto Linux Image 通过 Toradex Easy Installer 更新到 Verdin iMX8MM 模块。


5). Plymouth Splash 部署测试


a). 安装好上述编译的 Image 后,参考这里说明配置合适的 Device-tree Overlay 文件来适配屏幕;然后配置如下 U-boot 环境变量来显示 Splash,且缩短加载时间

# setenv tdxargs ‘quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3’
# setenv bootdelay 0
# saveenv && reset


b). 为了保证 Plymouth SplashQt Demo App切换更自然,且中间不会被 Weston Desktop 中断,需要修改一下一些 Systemd Service 文件

--- a/lib/systemd/system/plymouth-quit.service
+++ b/lib/systemd/system/plymouth-quit.service
@@ -1,6 +1,6 @@
[Unit]
Description=Terminate Plymouth Boot Screen
-After=rc-local.service plymouth-start.service systemd-user-sessions.service
+After=rc-local.service plymouth-start.service systemd-user-sessions.service waylan
d-app-launch.service

[Service]
ExecStart=-/bin/plymouth quit --retain-splash

--- a/lib/systemd/system/serial-getty@.service
+++ b/lib/systemd/system/serial-getty@.service
@@ -12,7 +12,7 @@
Documentation=man:agetty(8) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
BindsTo=dev-%i.device
-After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service getty
-pre.target
+After=dev-%i.device systemd-user-sessions.service getty-pre.target
After=rc-local.service

# If additional gettys are spawned during boot then we should make

--- a/lib/systemd/system/weston.service
+++ b/lib/systemd/system/weston.service
@@ -13,7 +13,7 @@
After=systemd-user-sessions.service

# If Plymouth is used, we want to start when it is on its way out.
-After=plymouth-quit-wait.service
+#After=plymouth-quit-wait.service

# D-Bus is necessary for contacting logind. Logind is required.
Wants=dbus.socket

--- a/etc/xdg/weston/weston.ini
+++ b/etc/xdg/weston/weston.ini
@@ -6,6 +6,7 @@
repaint-window=16
#enable-overlay-view=1
modules=screen-share.so
+shell=kiosk-shell.so

#[shell]
#size=1920x1080


b). 最后部署完成的测试效果如下,实测从开机到出现 Splash 画面大约5秒,另外 Plymouth splash 默认除了支持开机画面,在 reboot 重启和 poweroff 关机的时候也会同样显示 splash 画面



6). 总结

本文基于嵌入式 Linux 简单演示了 Plymouth splash 开机画面的部署和测试。



以上所有的信息仅供您的参考,其中并不包含任何承诺。Toradex 会不定期发布软件更新,以上信息不保证能够适用于最新的软件。关于文中任何的错误、遗漏或者链接内容,我们对此不承担责任。

Author: 秦海,Toradex 销售工程师
Share this on:

Leave a comment

Please login to leave a comment!
Have a Question?