imx6ull UI開發簡介
- 在imx6ull上開發UI 應用
- 硬件層面
- 內核驅動
- 顯示設備
- 文件描述符
- 設備樹
- 軟件
- LVGL
- 用戶空間
- 內核
- QT
在imx6ull上開發UI 應用
在 Linux 系統中,應用程序需要通過操作 RGB LCD 的顯存來實現在屏幕上顯示字符、圖像等信息。由于 Linux 采用嚴格的內存管理機制,顯存必須經過申請才能使用。由于虛擬內存機制的存在,驅動程序設置的顯存地址必須與應用程序訪問的物理內存區域保持一致。
下面從硬件,內核 驅動和軟件層面介紹整個流程。
硬件層面
imx6ull 的外設 LCDIF(Liquid Crystal Display Interface) 支持以下功能:
- 具有異步并行MPU接口的顯示器,用于與集成幀緩沖區進行命令和數據傳輸。
- 支持動態圖像且需要RGB接口模式(DOTCLK接口)的顯示器。
- 用于高速數據傳輸的VSYNC模式。
- 接受ITU-R BT.656格式4的數字視頻編碼器。
因此可以用這個外設來驅動 TFT(RGB 接口)
內核驅動
通常情況下, 芯片廠商和屏幕廠商已經在Linux內核中實現了驅動, 對于應用來說, 只需要根據實際的硬件來修改一些設置, 如 device tree里LCDIF的有關IO口, 屏幕的有關參數等。
顯示設備
在Linux系統中,顯示設備通常通過圖形子系統來管理,主要有兩種方式:直接使用幀緩沖(Framebuffer)和間接使用圖形用戶界面(GUI)系統,如X Window System或QT等。
幀緩沖是Linux內核提供的一個設備驅動接口,它允許用戶空間程序直接訪問顯示硬件的幀緩沖區。通過/dev/fbX(X: 0~n)等設備文件,用戶空間程序可以讀寫顯示內存,從而實現圖形顯示。
文件描述符
/dev/fbX是字符設備, 文件描述符定義在drivers/video/fbdev/core/fbmem.c文件
設備樹
- imx6ul.dtsi: 設置 LCDIF的有關屬性
lcdif: lcdif@21c8000 {compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif";reg = <0x021c8000 0x4000>;interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,<&clks IMX6UL_CLK_LCDIF_APB>,<&clks IMX6UL_CLK_DUMMY>;clock-names = "pix", "axi", "disp_axi";status = "disabled";};
- OEM工程的設備樹: 設置屏幕相關的屬性和pinctrl 有關信息
&lcdif {assigned-clocks = <&clks IMX6UL_CLK_LCDIF_PRE_SEL>;assigned-clock-parents = <&clks IMX6UL_CLK_PLL5_VIDEO_DIV>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_lcdif_dat&pinctrl_lcdif_ctrl>;display = <&display0>;status = "okay";display0: display {bits-per-pixel = <24>;bus-width = <24>;display-timings {native-mode = <&timing0>;timing0: timing0 {clock-frequency =<60000000>;hactive = <1024>;vactive = <600>;hfront-porch = <160>;hback-porch = <160>;hsync-len = <10>;vback-porch = <23>;vfront-porch = <12>;vsync-len = <3>;hsync-active = <0>;vsync-active = <0>;de-active = <1>;pixelclk-active = <1>;};};};
};// backlight
pinctrl_pwm1: pwm1grp {fsl,pins = <MX6UL_PAD_LCD_DATA00__PWM1_OUT 0x110b0>;};// lcdif command line
pinctrl_lcdif_ctrl: lcdifctrlgrp {fsl,pins = <MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79MX6UL_PAD_NAND_ALE__GPIO4_IO10 0x17059>;};
// lcdif data linepinctrl_lcdif_dat: lcdifdatgrp {fsl,pins = <MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79>;};
- 驅動
搜索 imx6ul.dtsi里定義的 LCDIF 的 compatible , 可以找到 imx6ull LCDIF的驅動文件 drivers/video/fbdev/mxsfb.c
軟件
分別以LVGL 和QT兩種UI 開發框架角度介紹
LVGL
LVGL移植的詳細介紹可以參考LVGL倉庫。現簡要介紹LVGL實現圖形顯示的框架流程。
用戶空間
- 使用 “mmap” 將framebuffer和 /dev/fbX 映射起來
- 實現flush_cb
–使用memcpy將 UI 數據copy 到 framebuffer
–最后調用 lv_disp_flush_ready 表示顯示刷新操作已完成
內核
/dev/fb0
是 Linux FrameBuffer 驅動導出的字符設備。- 用戶空間通過
mmap
把 FrameBuffer 物理內存映射到用戶空間指針(fbp
)。 - 用戶空間寫
fbp
,實際上就是直接寫顯存。 - 內核 FrameBuffer 驅動負責把這些數據同步到實際的顯示控制器(如 i.MX6ULL 的 LCDIF 控制器)。
- 顯示控制器周期性地從顯存讀取數據,驅動 TFT 屏顯示。
- 內核 FrameBuffer 驅動的主要職責
- 初始化 LCD 控制器(如設置分辨率、時序、顯存地址等)。
- 響應用戶空間的 ioctl(如獲取/設置分辨率、虛擬分辨率、offset 等)。
- 提供 mmap 支持,讓用戶空間可以直接訪問顯存。
- 處理可能的同步(如部分硬件需要顯存 flush 或 cache 操作)。
- 流程圖
LVGL (flush_cb)|vmemcpy/寫入 fbp (mmap 映射的顯存)|v/dev/fb0 (FrameBuffer 設備)|vLinux FrameBuffer 驅動 (fbmem.c, fbdev.c, mxsfb.c 等)|vLCD 控制器 (i.MX6ULL LCDIF)|vTFT 屏顯示
QT
- 移植QT 到 imx6ull
-
移植完成后, 設置qt的環境變量 /etx/profile/
把/dev/fb0指定為QT的顯示設備
export QT_QPA_PLATFORM=li nuxfb:tty=/dev/fb0
-
- QT應用程序結合Qt的屏幕管理功能,通過QScreen類獲取和操作多個顯示設備
QList<QScreen *> screens = QGuiApplication::screens();for (QScreen *screen : screens) {qDebug() << "Found screen:" << screen->name();// 可以在這里進行其他屏幕相關的操作}