Qt on Embedded Linux
Qt runs on embedded Linux without a desktop environment. It drives the framebuffer or GPU directly via platform plugins:
| Plugin | Description |
|---|---|
eglfs | OpenGL ES directly to framebuffer — best for GPU targets (i.MX6, Pi 4) |
linuxfb | Software rendering to /dev/fb0 — for targets without GPU |
xcb | X11 — when running a full desktop |
wayland | Wayland compositor support |
Target Hardware
Common embedded Linux targets for Qt HMI:
| Board | SoC | GPU | Plugin |
|---|---|---|---|
| Raspberry Pi 4 | BCM2711 (ARM A72) | VideoCore VI | eglfs |
| Raspberry Pi Zero 2W | BCM2710 (ARM A53) | VideoCore IV | linuxfb or eglfs |
| NXP i.MX6 | ARM Cortex-A9 | Vivante GC2000 | eglfs |
| BeagleBone Black | AM335x (ARM A8) | No GPU | linuxfb |
| STM32MP1 | ARM Cortex-A7 | No 3D GPU | linuxfb |
Cross-Compiling Qt for Raspberry Pi
Step 1 — Install Sysroot
# On your host PC, create a Raspberry Pi sysroot
mkdir -p ~/rpi-sysroot
rsync -avz --rsync-path="sudo rsync" \
pi@raspberrypi.local:/usr/include ~/rpi-sysroot/usr/
rsync -avz --rsync-path="sudo rsync" \
pi@raspberrypi.local:/usr/lib ~/rpi-sysroot/usr/
rsync -avz --rsync-path="sudo rsync" \
pi@raspberrypi.local:/lib ~/rpi-sysroot/
Step 2 — Toolchain File (cmake/rpi-toolchain.cmake)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(SYSROOT $ENV{HOME}/rpi-sysroot)
set(CMAKE_SYSROOT ${SYSROOT})
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_FIND_ROOT_PATH ${SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Step 3 — Build
cmake -B build-rpi \
-DCMAKE_TOOLCHAIN_FILE=cmake/rpi-toolchain.cmake \
-DCMAKE_PREFIX_PATH=~/Qt/6.x/gcc_arm \
-DCMAKE_BUILD_TYPE=Release
cmake --build build-rpi --parallel $(nproc)
Step 4 — Deploy and Run
# Copy binary to Pi
scp build-rpi/MyHMI pi@raspberrypi.local:~/
# Run on Pi (no desktop needed)
ssh pi@raspberrypi.local \
"QT_QPA_PLATFORM=eglfs ./MyHMI"
# For software rendering (no GPU)
ssh pi@raspberrypi.local \
"QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0 ./MyHMI"
Touch Input
Qt auto-detects touchscreens on Linux via evdev. Set the device if needed:
# Run with explicit touch device
QT_QPA_PLATFORM=eglfs \
QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0 \
./MyHMI
In code, handle touch events:
class TouchWidget : public QWidget {
protected:
void touchEvent(QTouchEvent *event) override {
for (const auto &point : event->points()) {
if (point.state() == QEventPoint::Pressed) {
qDebug() << "Touch at:" << point.position();
}
}
event->accept();
}
bool event(QEvent *e) override {
if (e->type() == QEvent::TouchBegin ||
e->type() == QEvent::TouchUpdate ||
e->type() == QEvent::TouchEnd)
{
touchEvent(static_cast<QTouchEvent*>(e));
return true;
}
return QWidget::event(e);
}
};
Enable multi-touch:
setAttribute(Qt::WA_AcceptTouchEvents);
Screen Orientation & Resolution
// Force landscape orientation in QML
Window {
contentOrientation: Qt.LandscapeOrientation
}
// Set screen via environment
// QT_QPA_PLATFORM=eglfs QT_QPA_EGLFS_ROTATION=90 ./MyHMI
// Query screen info at runtime
QScreen *screen = QGuiApplication::primaryScreen();
qDebug() << "Resolution:" << screen->size();
qDebug() << "DPI:" << screen->physicalDotsPerInch();
qDebug() << "Pixel ratio:" << screen->devicePixelRatio();
Optimizing Qt for Embedded
Reduce Binary Size
# Strip debug symbols in release
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -s")
# Enable LTO
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
Reduce Memory Usage
// Disable unused Qt features in qtconfig.pri or configure Qt with:
// -no-feature-accessibility
// -no-feature-printer
// -no-feature-sql
// Use QOpenGLWidget instead of QWidget where GPU acceleration helps
// Prefer QML for animated UIs (GPU-composited)
Startup Time
# Pre-load Qt libraries via ldconfig
ldconfig
# Use Qt Quick Compiler to pre-compile QML
# In CMakeLists.txt:
qt_add_qml_module(MyApp
QML_FILES Main.qml
RESOURCE_PREFIX /
OUTPUT_TARGETS MyApp_qmlcache # pre-compiled QML
)
Systemd Service — Auto-Start on Boot
# /etc/systemd/system/hmi.service
[Unit]
Description=EmbeddexAI HMI Application
After=multi-user.target
[Service]
Type=simple
User=pi
Environment="QT_QPA_PLATFORM=eglfs"
Environment="QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0"
ExecStart=/home/pi/MyHMI
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl enable hmi.service
sudo systemctl start hmi.service
Summary
| Topic | Key Point |
|---|---|
eglfs | Best plugin for GPU targets (Pi 4, i.MX6) |
linuxfb | Software rendering, no GPU required |
| Cross-compile | Use sysroot + CMake toolchain file |
| Touch input | Qt auto-detects evdev; set device via env var |
| Startup service | Use systemd to auto-launch HMI on boot |
| Optimization | Strip symbols, LTO, pre-compile QML |
Next tutorial → Cross-Platform Deployment