← 返回文章归档

ATK-IMX6U Qt/QML UI 部署与排障指南

在 Windows 调试 QML,用 WSL 交叉编译并部署到 i.MX6U,处理字体缺失和 tslib 触摸问题。

这套 QML 触摸界面先在 Windows 上调试,再用 WSL 交叉编译后部署到 ATK-IMX6U,控制板上的 LED 和蜂鸣器。部署时主要遇到了字体缺失和触摸无响应两个问题,下面记录环境、命令和处理办法。

1. 最终架构

Windows Qt Creator
  - Qt 5.12.9 MinGW 64-bit
  - 快速预览 QML 页面和交互

WSL2 Ubuntu
  - 正点原子/NXP i.MX6U Qt 交叉编译 SDK
  - 构建 ARM Linux 可执行文件

ATK-IMX6U
  - Qt 5.12.9 运行库
  - linuxfb 显示 /dev/fb0
  - tslib 触摸 /dev/input/touchscreen0
  - sysfs 控制 LED 和蜂鸣器

原则是:QML 负责界面,C++ 负责硬件,开发机负责编译,开发板负责运行。

2. 板子环境确认

开发板当前运行环境:

CPU 架构:ARMv7 hard-float
动态加载器:/lib/ld-linux-armhf.so.3
Qt:5.12.9
显示:/dev/fb0,1024x600
网络:192.168.10.2

检查 Qt 版本和 linuxfb 插件:

qmake -v
ls -l /usr/lib/libQt5Core.so*
find /usr/lib -type f -name 'libqlinuxfb.so'

本项目依赖的运行库已经存在:

libQt5Core.so.5.12.9
libQt5Gui.so.5.12.9
libQt5Qml.so.5.12.9
libQt5Quick.so.5.12.9
libQt5QuickControls2.so.5.12.9

3. 为什么不能直接复制 Windows 程序到板子

Windows Qt Creator 使用 Desktop Qt 5.12.9 MinGW 64-bit 编译出的文件是 Windows x86_64 程序,例如 .exe,不能在 ARM Linux 板子运行。

正确流程:

同一份 C++ / QML 源码
  ├─ Desktop Kit -> Windows 预览和调试
  └─ i.MX6U SDK -> ARM Linux 程序 -> SSH/SCP 部署到板子

板子只有 Qt 运行库,缺少 /usr/include 中的 Qt 开发头文件。因此不能在板子上直接编译 Qt 应用,也不能用 Ubuntu 通用 ARM 工具链随意替代厂商 SDK。

原因是板子 glibc 较旧,通用工具链可能生成依赖更高版本 GLIBC 的程序,部署后会出现 GLIBC_x.xx not found。

4. Windows 桌面 Qt 环境

安装 Qt 5.12.9 时选择:

Qt 5.12.9
  - MinGW 7.3.0 64-bit

Developer and Designer Tools
  - Qt Creator
  - MinGW 7.3.0 64-bit

本项目使用:

项目类型:Qt Quick Application - Empty
构建系统:qmake
桌面 Kit:Desktop Qt 5.12.9 MinGW 64-bit

QML 用于页面、按钮、布局和触摸交互;C++ 用于 GPIO、CAN、串口和系统接口。

5. 安装 i.MX6U 交叉编译 SDK

使用正点原子资料中的安装包:

E:\BaiduNetdiskDownload\05、开发工具\01、交叉编译器\
fsl-imx-x11-glibc-x86_64-meta-toolchain-qt5-cortexa7hf-neon-toolchain-4.1.15-2.1.0.sh

在 WSL 中安装到用户目录,避免污染系统 /opt:

sh '/mnt/e/BaiduNetdiskDownload/05、开发工具/01、交叉编译器/fsl-imx-x11-glibc-x86_64-meta-toolchain-qt5-cortexa7hf-neon-toolchain-4.1.15-2.1.0.sh' \
  -y -d "$HOME/imx6u/sdk"

每次使用 SDK 前加载环境:

source "$HOME/imx6u/sdk/environment-setup-cortexa7hf-neon-poky-linux-gnueabi"

该脚本设置了:

ARM 交叉编译器:arm-poky-linux-gnueabi-g++
目标 sysroot
Qt 5.12.9 ARM 头文件和库
目标 qmake/mkspec

易错点:SDK 环境脚本与 set -u

SDK 环境脚本会读取未定义的 CCACHE_PATH。脚本中不能在 source 前使用 set -u:

set -eo pipefail
source "$HOME/imx6u/sdk/environment-setup-cortexa7hf-neon-poky-linux-gnueabi"
set -u

否则会出现:

CCACHE_PATH: unbound variable

6. 本项目结构

vincent_ui/
├─ main.qml                 # 1024x600 QML 控制界面
├─ main.cpp                 # 把 C++ device 对象注册到 QML
├─ devicecontroller.h       # UI 与硬件的统一接口
├─ devicecontroller.cpp     # Windows 模拟与 Linux sysfs 控制
├─ vincent_ui.pro           # qmake 工程文件
└─ build-imx6u.sh           # WSL ARM 构建脚本

QML 通过统一接口控制设备:

Switch {
    checked: device.ledOn
    onToggled: device.setLed(checked)
}

C++ 后端在 Linux 上向 sysfs 写入开关值;在 Windows 上只记录模拟状态。因此同一套 QML 可以在电脑预览,也可以部署到板子。

7. 真实硬件节点

不要假设所有板子的 LED 都叫 status。本板实际节点通过下面命令确认:

ls -1 /sys/class/leds

当前板子结果:

LED:    /sys/class/leds/sys-led/brightness
蜂鸣器:/sys/class/leds/beep/brightness

手工测试:

echo 1 > /sys/class/leds/sys-led/brightness
echo 0 > /sys/class/leds/sys-led/brightness

echo 1 > /sys/class/leds/beep/brightness
echo 0 > /sys/class/leds/beep/brightness

devicecontroller.cpp 会自动探测这些节点,也支持覆盖路径:

IMX6U_LED_PATH=/custom/led/brightness
IMX6U_BUZZER_PATH=/custom/beep/brightness

8. 构建 ARM 版 UI

从 WSL 执行:

bash /mnt/c/Users/vincent/Documents/qt/vincent_ui/build-imx6u.sh

构建输出:

/home/vincent/imx6u/build-vincent_ui/vincent_ui

验证必须是 ARM 程序:

file /home/vincent/imx6u/build-vincent_ui/vincent_ui

预期关键字:

ELF 32-bit ... ARM ... interpreter /lib/ld-linux-armhf.so.3

9. 上传与运行

上传:

scp \
  -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  /home/vincent/imx6u/build-vincent_ui/vincent_ui \
  root@192.168.10.2:/opt/ui/vincent_ui

板子上赋予执行权限并检查依赖:

chmod 755 /opt/ui/vincent_ui
ldd /opt/ui/vincent_ui

ldd 输出中不能出现 not found。

原有 /opt/ui/systemui 会占用 /dev/fb0。测试新 UI 前先停止旧程序:

killall systemui

10. 字体问题

现象

屏幕只有色块、控件轮廓,没有任何文字。日志出现:

QFontDatabase: Cannot find font directory /usr/lib/fonts.

原因

系统裁剪了 Qt 默认字体目录,QML 的 Text 和 Button 文本无法渲染。

解决

从 WSL 部署字体:

scp /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf \
  root@192.168.10.2:/opt/ui/fonts/DejaVuSans.ttf

启动时设置:

QT_QPA_FONTDIR=/opt/ui/fonts

板子原系统也有 /usr/share/fonts/ttf/SourceHanSansCN-Regular.otf,但不要依赖不存在的 /usr/lib/fonts。

11. 触摸无响应问题

现象

文字显示正常,但点击 LED、蜂鸣器开关没有反应。

错误做法

强制使用:

QT_QPA_GENERIC_PLUGINS=evdevtouch:/dev/input/event1

本板触摸设备 EP0820M09 的驱动报告坐标最大值异常为 -1。通用 evdevtouch 无法稳定完成坐标映射,而且可能和 Qt 自动输入处理重复读取 event1。

正确做法:使用出厂 tslib 配置

确认触摸设备:

ls -l /dev/input/touchscreen0
cat /proc/bus/input/devices

当前映射:

/dev/input/touchscreen0 -> event1
设备名:EP0820M09

系统 tslib 配置:

/etc/profile                 # QT_QPA_FB_TSLIB=1
/etc/profile.d/tslib.sh      # TSLIB_TSDEVICE=/dev/input/touchscreen0
/etc/ts.conf                 # pthres, dejitter, linear 等模块

正确启动参数:

QT_QPA_FB_TSLIB=1
TSLIB_TSDEVICE=/dev/input/touchscreen0
TSLIB_CONFFILE=/etc/ts.conf

不要同时启用 evdevtouch 和 QT_QPA_FB_TSLIB=1。

12. 当前推荐启动命令

QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0 \
QT_QPA_FONTDIR=/opt/ui/fonts \
QT_QPA_FB_TSLIB=1 \
TSLIB_TSDEVICE=/dev/input/touchscreen0 \
TSLIB_CONFFILE=/etc/ts.conf \
QT_QUICK_BACKEND=software \
XDG_RUNTIME_DIR=/var/volatile/tmp/runtime-root \
nohup /opt/ui/vincent_ui >/tmp/vincent_ui.log 2>&1 &

检查程序和日志:

pidof vincent_ui
cat /tmp/vincent_ui.log

运行正常时,不应再有字体目录错误。进程的文件描述符中应看到:

/dev/fb0
/dev/input/event1

13. 常见问题速查

现象 原因 解决
ssh-rsa 协商失败 新版 OpenSSH 禁用了旧算法 加 HostKeyAlgorithms=+ssh-rsa 和 PubkeyAcceptedAlgorithms=+ssh-rsa
.exe 无法运行 Windows x86_64 程序不是 ARM Linux 程序 使用 i.MX6U SDK 交叉编译
GLIBC_x.xx not found 工具链/系统库版本不匹配 使用厂商 SDK,不用通用 Ubuntu ARM 工具链
g++ not found 直接在 PowerShell 调用 qmake 时 MinGW 未加 PATH 用 Qt Creator,或加入 MinGW bin 目录
页面无字 Qt 找不到字体目录 部署字体并设置 QT_QPA_FONTDIR
触摸不响应 使用 evdevtouch,驱动坐标范围异常 使用 QT_QPA_FB_TSLIB=1 和 tslib
新 UI 无法显示 systemui 占用 framebuffer 先 killall systemui
程序启动即退出 Qt 库/插件缺失 用 ldd 检查并查看 /tmp/vincent_ui.log

14. 开机自启动建议

当前只是手动测试,重启后仍会启动原来的 /opt/ui/systemui。

确认新 UI 功能稳定后,再把 /etc/rc.local 中的启动目标从:

/opt/ui/systemui

改为:

/opt/ui/vincent_ui

并使用第 12 节的完整环境变量。修改前保留旧启动命令,便于出现问题时回退。

15. 修改 UI 后如何部署验证

这一节用于日常迭代。每次修改界面或 C++ 后端后,按以下顺序执行。

第一步:修改源码

常见修改位置:

main.qml                 修改页面、颜色、按钮、布局和交互
devicecontroller.cpp     修改 LED、蜂鸣器、CAN、GPIO 等硬件逻辑
devicecontroller.h       增加 QML 可调用的方法和属性
main.cpp                 注册新的 C++ 后端对象
vincent_ui.pro           新增 C++ 源文件、Qt 模块或资源文件

修改 QML 时,要保持目标屏幕尺寸:

ApplicationWindow {
    width: 1024
    height: 600
}

硬件访问必须放在 C++ 后端,不要在 QML 里直接执行 shell 命令或写 sysfs。

第二步:在 Windows 电脑预览 UI

在 Qt Creator 中:

1. 选择 Desktop Qt 5.12.9 MinGW 64-bit Kit。
2. 点击 Run qmake(修改 .pro 后必须执行)。
3. 点击绿色运行按钮。
4. 检查 1024x600 窗口中的布局、文字、按钮和页面跳转。

电脑运行时,DeviceController 自动进入模拟模式:点击 LED、蜂鸣器不会操作真实板子,只会更新 UI 和输出调试信息。

先在电脑完成视觉和交互调试,再构建 ARM 版,可以减少板子部署次数。

第三步:交叉编译 ARM 版

打开 WSL,执行:

bash /mnt/c/Users/vincent/Documents/qt/vincent_ui/build-imx6u.sh

此脚本会自动:

1. 加载 ~/imx6u/sdk 的正点原子/NXP SDK 环境。
2. 使用 ARM Qt 5.12.9 的 qmake。
3. 调用 arm-poky-linux-gnueabi-g++ 编译。
4. 输出 ARM 程序到 ~/imx6u/build-vincent_ui/vincent_ui。

如果改动了 vincent_ui.pro,脚本会重新运行 qmake;不需要手动删除构建目录。

验证产物架构:

file ~/imx6u/build-vincent_ui/vincent_ui

必须看到:

ELF 32-bit ... ARM ... /lib/ld-linux-armhf.so.3

出现 x86-64、PE32+ 或 .exe 说明错误地使用了 Windows Desktop Kit,不能部署。

第四步:上传新程序

从 WSL 上传到板子。始终上传为独立文件 /opt/ui/vincent_ui,不要覆盖原始 /opt/ui/systemui:

scp \
  -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  ~/imx6u/build-vincent_ui/vincent_ui \
  root@192.168.10.2:/opt/ui/vincent_ui

首次上传或权限发生变化时:

ssh -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  root@192.168.10.2 'chmod 755 /opt/ui/vincent_ui'

第五步:检查运行库

在启动前检查动态库:

ssh -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  root@192.168.10.2 'ldd /opt/ui/vincent_ui'

确认输出没有:

not found

若有 not found,不要继续启动。应检查是否误用了 Desktop Qt 或错误的 ARM 工具链。

第六步:停止旧 UI 并启动新 UI

/dev/fb0 只能由一个 UI 使用。先停止当前 UI:

ssh -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  root@192.168.10.2 'killall vincent_ui 2>/dev/null; killall systemui 2>/dev/null || true'

然后用完整环境变量启动。不要省略字体和 tslib 配置:

ssh -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  root@192.168.10.2 '
    QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0 \
    QT_QPA_FONTDIR=/opt/ui/fonts \
    QT_QPA_FB_TSLIB=1 \
    TSLIB_TSDEVICE=/dev/input/touchscreen0 \
    TSLIB_CONFFILE=/etc/ts.conf \
    QT_QUICK_BACKEND=software \
    XDG_RUNTIME_DIR=/var/volatile/tmp/runtime-root \
    nohup /opt/ui/vincent_ui >/tmp/vincent_ui.log 2>&1 &
  '

第七步:板子现场验证

在屏幕上依次检查:

1. 所有标题、按钮文字是否显示。
2. 触摸 LED 和 Buzzer 开关是否有状态变化。
3. LED 是否实际亮灭。
4. 蜂鸣器是否实际响停。
5. 点击 Refresh 后状态栏是否正常更新。

同时通过 SSH 检查:

ssh -o HostKeyAlgorithms=+ssh-rsa \
  -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  root@192.168.10.2 'pidof vincent_ui; cat /tmp/vincent_ui.log'

正常情况:

能看到 vincent_ui 的 PID
日志没有 QML、字体或插件加载错误

硬件状态可复查:

cat /sys/class/leds/sys-led/brightness
cat /sys/class/leds/beep/brightness

第八步:出现问题时的回退

停止新 UI,恢复旧 UI:

killall vincent_ui

QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0 \
XDG_RUNTIME_DIR=/var/volatile/tmp/runtime-root \
nohup /opt/ui/systemui >/tmp/systemui.log 2>&1 &

/opt/ui/systemui 未被覆盖,因此新 UI 出问题时可以快速恢复显示。

每次修改的最短命令清单

当环境已配置完成后,日常最短流程是:

# WSL:编译
bash /mnt/c/Users/vincent/Documents/qt/vincent_ui/build-imx6u.sh

# WSL:上传
scp -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa \
  ~/imx6u/build-vincent_ui/vincent_ui root@192.168.10.2:/opt/ui/vincent_ui

# 板子:停止旧 UI,按第六步完整命令启动新 UI
← 返回文章归档

讨论交流

支持免注册访客评论,填写真实邮箱可接收回复提醒