By Toradex秦海
1).?簡介
嵌入式平臺多屏顯示是比較常見的功能,在NXP iMX6上面,由于使用了基于fbdev/X11的顯示接口驅(qū)動和顯示服務(wù),可以比較方便的通過framebuffer方式來實(shí)現(xiàn)多屏顯示,Qt也提供了想eglfs或者linuxfs這樣的組件來對接。而基于NXP新的iMX8平臺,由于使用了DRM/KMS顯示接口驅(qū)動和Wayland顯示服務(wù),多屏顯示的實(shí)現(xiàn)思路可能有如下幾種,而本文就演示基于Qtwayland?組件來實(shí)現(xiàn)雙屏獨(dú)立顯示。
./?通過底層IPU驅(qū)動來實(shí)現(xiàn),主要可以比較靈活的實(shí)現(xiàn)如clone模式等,但難度比較大,需要對iMX8?底層IPU驅(qū)動有比較深入的了解
./?如果是通過iMX8?雙通道LVDS,連接兩個單通道的LVDS屏幕,可以通過device tree ldb節(jié)點(diǎn)”dual-mode”來實(shí)現(xiàn)clone顯示
./ iMX8默認(rèn)的wayland/Weston compositor默認(rèn)支持多屏擴(kuò)展模式顯示,但是9.0以下版本無法對應(yīng)用程序窗口進(jìn)行定位,9.0以后引入了Kiosk shell支持,則可以通過應(yīng)用程序窗口定位到不同屏幕實(shí)現(xiàn)多屏獨(dú)立顯示的效果
./?使用Qtwayland組件構(gòu)建wayland compositor,可以方便的實(shí)現(xiàn)多屏獨(dú)立顯示,在多屏都是同樣分辨率前提下,也可以實(shí)現(xiàn)clone顯示
本文所使用的ARM嵌入式平臺來自于Toradex?基于NXP最新的iMX8 SoC(基于Cortex-A72+A53和Coretex-M4架構(gòu))的ARM計(jì)算機(jī)模塊Apalis iMX8QM 4GB WB IT。
2).?準(zhǔn)備
a).?Apalis iMX8QM?4GB WB IT ARM核心版配合Ioxra?載板,連接調(diào)試串口UART1(載板X22)到開發(fā)主機(jī)方便調(diào)試。
b). Apalis iMX8支持HDMI和LVDS顯示接口,分別連接如下兩個屏幕
./ 13.3 inch HDMI panel?顯示屏,分辨率1920x1080,支持USB接口電容式觸摸,將觸摸接口連接到Ixora?載板USB接口
./ 10.1 inch?LVDS?顯示屏,分辨率1280x800,支持I2C接口電容式觸摸,將觸摸接口連接到Ixora載板X24連接器
c). USB UVC標(biāo)準(zhǔn)攝像頭連接到Ixora載板用于Gstreamer測試
3). Apalis iMX8 Ycoto Linux?編譯部署以及配置
a). 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
-------------------------------
b). Ycoto Linux image部署
參考這里通過Toradex Easy installer將上面編譯好的image更新部署到模塊,版本為目前最新的Ycoto Linux V5.1
c).?顯示配置
./ HDMI默認(rèn)即可正常顯示,如果有顯示器EDID讀取問題不能成功顯示,可以通過下面方法通過軟件firmware方式手動加載EDID,更多關(guān)于顯示的配置請參考這里
-------------------------------
# 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默認(rèn)device tree下LVDS是disable的,需要通過下面方式加載對應(yīng)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
-------------------------------
./?觸摸設(shè)備測試,通過”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
-------------------------------
4). Qtwayland compositor?編譯部署
a). Qt Qtwayland組件可以非常方便的使用QML語言開發(fā)定制化的wayland compositor,詳細(xì)說明請見這里,也提供了很多sample project供參考
b).?本文測試所使用的qtwayland compositor來自于Toradex Europe FAE Stefan Eichenberger,源代碼請參考這里,這是一個用于雙屏顯示的qtwayland compositor
c).?參考這里說明使用上面章節(jié)?3.a編譯出的SDK文件配置qtcreator交叉編譯環(huán)境,下載dual-screen qtwayland compositor代碼后進(jìn)行編譯,生成dual-screen可執(zhí)行二進(jìn)制文件上傳到Apalis iMX8系統(tǒng)中
d).?使用編譯好的dual-screen qtwayland compositor?替換系統(tǒng)默認(rèn)的weston compositor
./?創(chuàng)建dual-screen.sh執(zhí)行腳本文件
-------------------------------
# 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 –?由于系統(tǒng)包含三個input設(shè)備,兩個觸摸設(shè)備和一個USB攝像頭,在啟動過程中,其對應(yīng)的event?號碼可能會變化,因此腳本前面先對?“kms.conf”?文件里面的設(shè)置和系統(tǒng)啟動后的設(shè)備event進(jìn)行比對,如果一致則直接啟動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 &
-------------------------------
./?創(chuàng)建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顯示接口設(shè)備,”touchDevice”?參數(shù)對應(yīng)?3.c章節(jié)中測試的event,更多關(guān)于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
????? }
? ]
}
-------------------------------
./?創(chuàng)建新的udev rule替換系統(tǒng)默認(rèn)的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"
-------------------------------
e).?測試qtwayland compositor
-------------------------------
# disable default wayland qt demo app systemd service
$ systemctl disable wayland-app-launch
$ reboot
-------------------------------
重啟后,可以看到下面雙屏顯示結(jié)果,qtwayland compositor啟動成功

5). Gstreamer測試
a).?分別運(yùn)行兩個gstreamer pipeline,然后qtwayland compositor會將第一個運(yùn)行的pipeline顯示在HDMI顯示器上面,第二個運(yùn)行的顯示在LVDS顯示器上面
b). Gstreamer pipeline 1 - USB攝像頭播放,關(guān)于gstreamer使用的更多說明請參考這里
-------------------------------
$ gst-launch-1.0 v4l2src device=/dev/video2 ! 'image/jpeg,width=1920,height=1080,frame
rate=30/1' ! jpegdec ! videoconvert ! waylandsink fullscreen=1 sync=false &
-------------------------------
c). Gstreamer pipeline 2 – gstreamer?測試pipeline
-------------------------------
$ gst-launch-1.0 videotestsrc ! waylandsink fullscreen=1
-------------------------------
d).?實(shí)際運(yùn)行效果如下

6). Qt應(yīng)用測試
a).?分別使用一個Qt Widget應(yīng)用和一個Qt Quick應(yīng)用進(jìn)行測試
./ Qt Widget應(yīng)用?–?讀取系統(tǒng)時間和CPU溫度,同時調(diào)用sqlite數(shù)據(jù)庫進(jìn)行保存的應(yīng)用,詳細(xì)說明請參考這里,將編譯好的可執(zhí)行binary “qt-sqlite”?上傳到Apalis iMX8
./ Qt Quick?應(yīng)用?–?調(diào)用qtmultimedia組件播放視頻以及攝像頭,詳細(xì)說明請參考這里,將編譯好的可執(zhí)行binary “videotest”?上傳到Apalis iMX8
b).?創(chuàng)建應(yīng)用啟動腳本
-------------------------------
$ 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 &
-------------------------------
c).?創(chuàng)建開機(jī)自啟動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
-------------------------------
d). enable service?并測試
-------------------------------
$ systemctl enable qtwayland-app-launch
$ reboot
-------------------------------
e).?重啟后效果如下,兩個屏幕的觸摸都可以分別正常使用

5).?總結(jié)
本文在iMX8嵌入式平臺下使用Qtwayland工具測試了HDMI/LVDS雙屏獨(dú)立顯示功能。
參考文檔
https://developer.toradex.cn/knowledge-base/display-output-resolution-and-timings-linux