Blog:
NXP iMX8 基于Qtwayland 配置双屏显示

Friday, November 20, 2020

简介

嵌入式平台多屏显示是比较常见的功能,在 NXP iMX6上面,由于使用了基于 fbdev/X11 的显示接口驱动和显示服务,可以比较方便的通过 framebuffer 方式来实现多屏显示,Qt 也提供了想 eglfs 或者 linuxfb 这样的组件来对接。而基于 NXP 新的 iMX8 平台,由于使用了 DRM/KMS 显示接口驱动和 Wayland 显示服务,多屏显示的实现思路可能有如下几种,而本文就演示基于 Qtwayland 组件来实现双屏独立显示。

  • 通过底层 IPU 驱动来实现,主要可以比较灵活的实现如 clone 模式等,但难度比较大,需要对 iMX8 底层 IPU 驱动有比较深入的了解
  • 如果是通过 iMX8 双通道 LVDS,连接两个单通道的 LVDS 屏幕,可以通过 device tree ldb 节点 ”dual-mode” 来实现 clone 显示
  • iMX8 默认的 wayland/Weston compositor 默认支持多屏扩展模式显示,但是 9.0 以下版本无法对应用程序窗口进行定位,9.0 以后引入了 Kiosk shell 支持,则可以通过应用程序窗口定位到不同屏幕实现多屏独立显示的效果
  • 使用 Qtwayland 组件构建 wayland compositor,可以方便的实现多屏独立显示,在多屏都是同样分辨率前提下,也可以实现 clone 显示

本文所使用的 Arm 嵌入式平台来自于 Toradex 基于 NXP 最新的 iMX8 SoC(基于Cortex-A72+A53和Coretex-M4架构)的 Arm 计算机模块 Apalis iMX8QM 4GB WB IT。

准备

Apalis iMX8QM 4GB WB IT Arm 核心版配合 Ioxra 载板,连接调试串口 UART1(载板X22)到开发主机方便调试。

Apalis iMX8支持 HDMI 和 LVDS 显示接口,分别连接如下两个屏幕

  • 13.3 inch HDMI panel 显示屏,分辨率1920x1080,支持 USB 接口电容式触摸,将触摸接口连接到 Ixora 载板 USB 接口
  • 10.1 inch LVDS 显示屏,分辨率 1280x800,支持 I2C 接口电容式触摸,将触摸接口连接到 Ixora 载板 X24 连接器

USB UVC 标准摄像头连接到 Ixora 载板用于 Gstreamer 测试

Apalis iMX8 Ycoto Linux 编译部署以及配置

Apalis iMX8 Ycoto Linux 通过 Ycoto/Openembedded 框架编译,具体的配置方法请参考这里,参考如下修改后编译 Reference-Multimedia image 镜像。

local.conf,增加eglfs和kms支持

+ PACKAGECONFIG_append_pn-qtbase = " sql-sqlite eglfs kms"
+ PACKAGECONFIG_append_pn-qtmultimedia = " gstreamer"
+ ACCEPT_FSL_EULA = "1"

layers/meta-toradex-demos/recipes-images/images/tdx-reference-multimedia-image.bb,增加SDK populate

inherit populate_sdk populate_sdk_qt5

compile Reference-Multimedia image

$ bitbake bitbake tdx-reference-multimedia-image

compile SDK

bitbake tdx-reference-multimedia-image -c populate_sdk

Ycoto Linux image 部署

参考这里通过 Toradex Easy installer 将上面编译好的 image 更新部署到模块,版本为目前最新的 Ycoto Linux V5.1

显示配置

HDMI默认即可正常显示,如果有显示器EDID读取问题不能成功显示,可以通过下面方法通过软件firmware方式手动加载EDID,更多关于显示的配置请参考这里

cp EDID binary file to rootfs

$ mkdir /lib/firmware/edid
$ cp 1920x1080.bin /lib/firmware/edid

set uboot kernel command line

# setenv defargs ‘pci=nomsi drm.edid_firmware=HDMI-A-1:edid/1920x1080.bin’
# saveenv && reset

LVDS 显示,Ycoto Linux V5.1默认 device tree 下 LVDS 是 disable 的,需要通过下面方式加载对应 device tree overlay来enable,device tree overlay 的更多说明请参考这里

overlay files path

root@apalis-imx8:~# ls /media/mmcblk0p1/overlays/
apalis-imx8_atmel-mxt_overlay.dtbo          apalis-imx8x_parallel-rgb_overlay.dtbo
apalis-imx8_lvds_overlay.dtbo               display-edt5.7_overlay.dtbo
apalis-imx8x_ad7879_overlay.dtbo            display-edt7_overlay.dtbo
apalis-imx8x_atmel-mxt_overlay.dtbo         display-fullhd_overlay.dtbo
apalis-imx8x_display-lt161010_overlay.dtbo  display-lt161010_overlay.dtbo
apalis-imx8x_display-lt170410_overlay.dtbo  display-lt170410_overlay.dtbo

add lvds and i2c touch(atmel) related overlay file to /media/mmcblk0p1/overlays.txt

fdt_overlays=overlays/apalis-imx8_lvds_overlay.dtbo overlays/display-lt170410_overlay.dtbo overlays/apalis-imx8_atmel-mxt_overlay.dtbo

触摸设备测试,通过”evetst”命令

list all devices

root@apalis-imx8:~# evtest 
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      sc-powerkey
/dev/input/event1:      gpio-keys
/dev/input/event2:      HID 27c0:0818
/dev/input/event3:      USB 2.0 Camera: HD USB Camera
/dev/input/event4:      Atmel maXTouch Touchscreen

from above output

event2 is HDMI display USB HID capacitive touch device
event4 is LVDS display I2C capacitive touch device

Qtwayland compositor 编译部署

Qt Qtwayland 组件可以非常方便的使用 QML 语言开发定制化的 wayland compositor,详细说明请见这里,也提供了很多 sample project 供参考。

本文测试所使用的 qtwayland compositor来 自于 Toradex Europe FAE Stefan Eichenberger,源代码请参考这里,这是一个用于双屏显示的 qtwayland compositor

参考这里说明使用上面章节 3.a 编译出的 SDK文 件配置qtcreator交叉编译环境,下载 dual-screen qtwayland compositor 代码后进行编译,生成 dual-screen 可执行二进制文件上传到 Apalis iMX8 系统中

使用编译好的 dual-screen qtwayland compositor 替换系统默认的 weston compositor

创建dual-screen.sh执行脚本文件

# copy dual-screen binary to /usr/bin

$ cp dual-screen /usr/bin/

# create dual-screen.sh script, detailed content in below

$ vi /usr/bin/dual-screen.sh

# add executable permission

$ chmod +x dual-screen.sh

dual-screen.sh – 由于系统包含三个 input 设备,两个触摸设备和一个 USB 摄像头,在启动过程中,其对应的 event 号码可能会变化,因此脚本前面先对 “kms.conf” 文件里面的设置和系统启动后的设备 event 进行比对,如果一致则直接启动 compositor,如不一致则需要先修改 ”kms.conf” 文件后再启动 compositor。这里使用的 ts0/ts1 symbol 链接则是在下面 udev rule 文件中定义的。

#get system touch device event number
while [ ! -e /dev/input/ts0 ]
do
sleep 0.1
done

ts0=$(readlink /dev/input/ts0)

while [ ! -e /dev/input/ts1 ]
do
sleep 0.1
done
ts1=$(readlink /dev/input/ts1)

# compare with kms.conf settings

while [ ! -e /etc/kms.conf ]
do
sleep 0.1
done
ts_hdmi=$(sed -n 8p /etc/kms.conf|cut -d '"' -f4|cut -d '/' -f4)
ts_lvds=$(sed -n 13p /etc/kms.conf|cut -d '"' -f4|cut -d '/' -f4)

# modify kms.conf if seetings is not consistent with system event
if [ "$ts_hdmi"!="$ts0" ];then
sed -i "8 s/event.*/$ts0\"\,/g" /etc/kms.conf
fi

if [ "$ts_lvds"!="$ts1" ];then
sed -i "13 s/event.*/$ts1\"\,/g" /etc/kms.conf
fi

# execute qtwayland compositor
/usr/bin/dual-screen &

创建systemd service 文件

/lib/systemd/system/qtwayland@.service

[Unit]
Description=Qt Wayland Compositor    
RequiresMountsFor=/run
Conflicts=plymouth-quit.service
After=systemd-user-sessions.service plymouth-quit-wait.service

[Service]
User=%i
PAMName=login
Environment="QT_QPA_EGLFS_KMS_CONFIG=/etc/kms.conf"
Environment="QT_QPA_EGLFS_INTEGRATION=eglfs_kms"
Environment="QT_QPA_PLATFORM=eglfs"
Environment="QT_QPA_EGLFS_KMS_ATOMIC=1"
Environment="QT_QPA_EGLFS_NO_LIBINPUT=1"
StandardError=journal
PermissionsStartOnly=true
IgnoreSIGPIPE=no

ExecStart=/usr/bin/dual-screen.sh

通过 /etc/kms.conf 文件来配置 KMS 显示接口设备,”touchDevice” 参数对应 3.c 章节中测试的 event,更多关于 Qt eglfs DRM/KMS 的配置说明请参考这里

$ vi /etc/kms.conf
{
"device": "/dev/dri/card0",
"hwcursor": true,
"pbuffers": false,
"outputs": [
    { "name": "HDMI1",
      "mode": "1920x1080",
      "touchDevice": "/dev/input/event2",
      "virtualIndex": 0, "primary": true
    },
    { "name": "LVDS1",
      "mode": "1280x800",
      "touchDevice": "/dev/input/event4",
      "virtualIndex": 1
    }
]
}

创建新的 udev rule 替换系统默认的 weston udev rule

remove default weston udev rule

$ rm /etc/udev/rules.d/71-weston-drm.rules

add qtwayland rule
$ vi /etc/udev/rules.d/71-qtwayland-drm.rules


connect HDMI HID touchscreen and LVDS I2C touchscreen with fix symlink
SUBSYSTEM=="input" KERNEL=="event*" ATTRS{name} =="HID 27c0:0818",       SYMLINK+="input/ts0"
SUBSYSTEM=="input" KERNEL=="event*" ATTRS{name} =="Atmel maXTouch Touchscreen",       SYMLINK+="input/ts1
# start qtwayland compositor
ACTION=="add", SUBSYSTEM=="graphics", KERNEL=="fb0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="qtwayland@root.service"
ACTION=="add", SUBSYSTEM=="drm", KERNEL=="card0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="qtwayland@root.service"

测试 qtwayland composito

disable default wayland qt demo app systemd service

$ systemctl disable wayland-app-launch
$ reboot

重启后,可以看到下面双屏显示结果,qtwayland compositor 启动成功

Gstreamer测试

分别运行两个 gstreamer pipeline,然后 qtwayland compositor 会将第一个运行的 pipeline 显示在 HDMI 显示器上面,第二个运行的显示在 LVDS 显示器上面

Gstreamer pipeline 1 - USB 摄像头播放,关于 gstreamer 使用的更多说明请参考这里

$ gst-launch-1.0 v4l2src device=/dev/video2 ! 'image/jpeg,width=1920,height=1080,framerate=30/1' ! \
jpegdec ! videoconvert ! waylandsink fullscreen=1 sync=false &

Gstreamer pipeline 2 – gstreamer 测试pipeline

$ gst-launch-1.0 videotestsrc ! waylandsink fullscreen=1

实际运行效果如下

 

Qt应用测试

分别使用一个 Qt Widget 应用和一个 Qt Quick 应用进行测试

  • Qt Widget 应用 – 读取系统时间和 CPU 温度,同时调用 sqlite 数据库进行保存的应用,详细说明请参考这里,将编译好的可执行 binary “qt-sqlite” 上传到 Apalis iMX8
  • Qt Quick 应用 – 调用 qtmultimedia 组件播放视频以及摄像头,详细说明请参考这里,将编译好的可执行 binary “videotest” 上传到 Apalis iMX8

创建应用启动脚本

$ vi /usr/bin/qtwayland-app-launch.sh
#!/bin/sh
if test -z "$XDG_RUNTIME_DIR"; then
  export XDG_RUNTIME_DIR=/run/user/`id -u`
  if ! test -d "$XDG_RUNTIME_DIR"; then
      mkdir --parents $XDG_RUNTIME_DIR
      chmod 0700 $XDG_RUNTIME_DIR
  fi
fi

# wait for qtwayland
while [ ! -e  $XDG_RUNTIME_DIR/wayland-0 ] ; do sleep 0.1; done
sleep 1

/home/root/videotest -url file:///home/root/ready-player-one-trailer-2_h720p.mov &
sleep 1
/home/root/qt-sqlite &

创建开机自启动systemd service文件

$ vi /lib/systemd/system/qtwayland-app-launch.service
[Unit]
Description=Start a Qt wayland application
After=qtwayland@root.service
Requires=qtwayland@root.service

[Service]
Restart=on-failure
Type=forking
Environment="QT_QPA_PLATFORM=wayland"
ExecStart=/usr/bin/qtwayland-app-launch.sh
RestartSec=1

[Install]
WantedBy=multi-user.target

enable service 并测试

$ systemctl enable qtwayland-app-launch
$ reboot

重启后效果如下,两个屏幕的触摸都可以分别正常使用

 

总结

本文在 iMX8 嵌入式平台下使用 Qtwayland 工具测试了 HDMI/LVDS 双屏独立显示功能。

参考文档:

https://developer.toradex.cn/knowledge-base/display-output-resolution-and-timings-linux 
https://doc.qt.io/qt-5/embedded-linux.html#embedded-eglfs 
https://github.com/eichenberger/qt-dual-screen-compositor 

Author: 秦海,技术销售工程师,韬睿(上海)
Share this on:

Leave a comment

Please login to leave a comment!
Have a Question?