新闻详情

新闻详情

首页 / 资讯中心 / 详情

IMX6ULL接入SPI屏ILI9341跑QT:基于fbtft完整方案

发布时间:2026/8/31 20:06:29来源:尧图网络
IMX6ULL接入SPI屏ILI9341跑QT:基于fbtft完整方案
简介本资源是面向嵌入式Linux开发者与Qt初学者的IMX6ULL平台SPI LCD图形界面实战项目聚焦解决ARM Cortex-A7平台下ILI9341驱动TFT屏显示Qt GUI的核心适配问题。压缩包共含多个关键文件包括适配MSP2402ILI9341的设备树源码.dts、交叉编译后的Qt应用程序源码.cpp/.h、构建脚本及启动配置整体大小为9.57MB文件类型以C源码、设备树描述和Shell初始化脚本为主支撑从内核驱动到应用层渲染的完整链路。已有278人学习下载适合具备基本Linux驱动与Qt开发基础的学习者开展实操验证。读者可直接部署运行掌握SPI总线配置、设备树修改、Qt嵌入式渲染后端如linuxfb适配、以及无窗口管理器环境下GUI启动流程等关键技术点是理解IMX6ULLSPI LCDQt协同工作的典型工程范例。 最近在做IMX6ULL相关的东西需要在板子上加一块SPI接口的TFT小屏来跑QT界面。屏的型号是MSP2402驱动IC是经典的ILI9341接口是6针SPISCLK、MOSI、CS、DC、RST、BL项目源码打包下来是一个rar名字就叫“IMX6ULL开发板 SPI LCD MSP2402 显示简单的QT界面源码”。这个项目看着简单但真要把QT、SPI、内核fbtft、LCD初始化全家桶凑到一起坑真不少。我干脆把整个过程中的方案思路、硬件接线、设备树配置、QT端处理和排障记录整理出来给准备在IMX6ULL这类开发板上接SPI小屏跑QT的朋友做个参考。1. 项目整体设计与方案选型1.1 为什么在IMX6ULL上接SPI小屏IMX6ULL跑QT本身毫无压力Cortex-A7单核800MHz在240x320这么小的分辨率下QPainter画简单界面绰绰有余。问题在于很多项目并不需要大屏比如仪表盘选项菜单、设备配置面板、状态指示灯界面一块2.4寸或者2.8寸的小屏就够了。SPI接口的屏走线少、占用引脚少在嵌入式产品里很常见。和RGB并口屏相比SPI屏最大的优势是省引脚。一块RGB565接口的4.3寸屏需要约20根数据线加时钟同步线而SPI屏只需要4根数据线SCLK、MOSI、CS、DC加上复位和背光也就6根线对于IMX6ULL这种引脚不算特别富余的板子非常友好。缺点是刷新率低因为SPI是串行传输跑满10MHz时钟一帧240x320x2字节的数据大约需要15ms实际加上指令开销和等待时间QT局部刷新可以接受但全屏动画会有点吃力。在这个项目里屏是MSP2402驱动IC是ILI9341。ILI9341是市面上最常见的SPI/并口TFT驱动IC之一支持240x320分辨率内置GRAM像素格式支持RGB565和RGB666几乎所有做嵌入式显示的朋友都见过这块IC。MSP2402应该是屏模组厂商的型号通用性没问题直接按ILI9341处理。1.2 两条驱动路线fbtft还是用户态SPI打点显示屏驱动有几种常见做法我简单梳理一下。第一种是内核fbtft框架。fbtft是内核staging目录下的一套小屏framebuffer驱动框架专门用来支持各种SPI/并口TFT屏。它在内核里注册一个独立的fb设备挂上后系统会多出/dev/fb0或者/dev/fb1用户态程序包括QT只需要往framebuffer里写像素数据不用关心底层SPI时序。优点是QT可以直接以linuxfb的方式工作代码改动最小兼容性好。第二种是用户态直接通过SPI设备节点打点。应用层打开/dev/spidevX.0通过ioctl自己发初始化命令和像素数据还要自己维护一块显存。这样做的缺点是QT没办法直接往spidev里画图除非你自己实现一个QPA插件或者自己写一个绘图引擎开发量大维护成本高不推荐做QT界面。第三种是走DRM/KMS这是现代Linux主推的显示框架但对SPI小屏的支持很弱而且IMX6ULL的GPU也不强用mipi或者RGB屏才会考虑走DRM。这个项目我选fbtft。原因很直接IMX6ULL内核自带fbtft支持ILI9341有现成的fb_ili9341驱动设备树里配好spi节点注册后就能得到一个240x320的真彩framebufferQT用linuxfb插件直接对接代码量最小踩坑最少。1.3 整条显示链路长什么样搞清楚数据流向后面调试才不会懵。IMX6ULL跑Linux内核系统起来后SPI控制器驱动注册了SPI总线。fbtft挂在SPI总线上初始化时通过SPI向ILI9341发送初始化序列设置显示方向、颜色格式、背光。之后fbtft在内核里申请一块fb内存注册为fb设备。QT应用通过linuxfb的QPA插件打开/dev/fb0把界面内容渲染到fb内存fbtft定时或者按刷新机制把fb内存里的数据转换成RGB565像素流通过SPI逐行发送给ILI9341ILI9341把数据写进自己的GRAM完成屏幕显示。简单说就是QT绘制 - fbtft的fb内存 - SPI - ILI9341 GRAM - 液晶面板。理解了这条链路后面遇到白屏、花屏、闪屏就能快速定位是哪个环节出了问题。2. 硬件接线与SPI通信细节2.1 MSP2402引脚与IMX6ULL接线MSP2402模组上常见的引脚有SCLK、MOSI、CS、DC、RST、BL有些还带MISO读GRAM用大多数场景用不上。IMX6ULL有多个ECSPI控制器我用ECSPI3引脚分配如下MSP2402引脚功能说明IMX6ULL引脚复用功能SCLKSPI时钟UART2_TXD / GPIO1_IO20ECSPI3_SCLKMOSISPI主机输出UART2_RXD / GPIO1_IO21ECSPI3_MOSIMISOSPI主机输入可空UART2_CTS / GPIO1_IO22ECSPI3_MISOCS片选GPIO1_IO20对应替换实际用GPIO5_IO11做软件片选GPIODC数据/命令选择GPIO5_IO14GPIORST复位GPIO5_IO15GPIOBL背光控制GPIO5_IO13GPIOVCC/GND电源3.3V / GND-这里有个细节要注意CS片选我特意没用ECSPI3的硬件片选而是用GPIO模拟。原因是硬件片选在每个SPI word传输时可能拉高拉低产生毛刺某些屏模组对CS要求比较严软件片选更可控。IMX6ULL设备树里cs-gpios属性可以直接指定GPIO很方便。MISO这根线在纯写屏场景下可以不接ILI9341的读回功能用不到。但建议还是留一根线方便调试时读ID、读状态寄存器特别是排查初始化失败问题时很管用。2.2 SPI模式、速率和线序的选择ILI9341支持SPI Mode 0CPOL0CPHA0和Mode 3CPOL1CPHA1两种模式下时钟空闲电平不同。绝大多数初始化代码和现成驱动默认用Mode 0我在设备树里没有额外配spi-cpha和spi-cpol默认就是Mode 0。传输格式上要注意ILI9341的SPI接口是按字节传输的不是按位。fbtft通过spi_transfer发数据时每8个bit组成一个字节DC引脚的电平决定这个字节是命令还是数据。DC为低发送命令DC为高发送数据。这个时序要求DC信号先于SCLK建立fbtft驱动内部会在发送前把DC置好问题不大。速率方面ILI9341芯片手册上SPI时钟上限一般是10MHz但实际和布线关系很大。杜邦线连接时超过10MHz线间串扰会很严重容易花屏我自己实测5MHz最稳10MHz在短距离飞线下也能跑。设备树里spi-max-frequency我配的是10000000如果出现花屏再降到5000000或者再低。2.3 ILI9341初始化序列的关键点ILI9341刚上电时处于未知状态必须发初始化序列。fbtft的fb_ili9341驱动里写好了常规初始化序列包括软件复位、退出睡眠、像素格式设置、显示开关等不需要自己写全但有几个命令值得理解。命令参数作用备注0x01无软件复位复位后要延时120ms0x11无退出睡眠模式必须延时120ms0x360xXX存储访问控制MADCTL控制扫描方向和RGB/BGR0x3A0x55像素格式0x55即16位RGB5650x20/0x21无反转显示开关根据屏模组选择部分屏要开反转0x29无打开显示不发这个屏幕不亮MADCTL命令0x36很关键它的低3位分别控制颜色格式和扫描方向。BGR位设为1表示像素数据按BGR顺序解释这个设错屏上颜色会明显偏色比如红色变成蓝色。项目里MSP2402我实测需要设置BGR0但每个屏模组可能不一样如果颜色不对就改这个bit。上电时序上RST引脚要先拉低10ms以上再拉高等待120ms后再发初始化命令。如果RST悬空或者复位时序不对屏大概率白屏。这个坑我踩过后面排障部分细说。3. 内核设备树与FBTFT配置3.1 设备树节点配置示例IMX6ULL的设备树需要配置两个大块一是ECSPI控制器本身的引脚复用和片选二是挂在SPI总线上的LCD子节点。我贴出可以直接用的设备树片段iomuxc { pinctrl_ecspi3: ecspi3grp { fsl,pins MX6UL_PAD_UART2_TXD__ECSPI3_SCLK 0x10b0 MX6UL_PAD_UART2_RXD__ECSPI3_MOSI 0x10b0 MX6UL_PAD_UART2_CTS__ECSPI3_MISO 0x10b0 MX6UL_PAD_CSI_DATA05__GPIO5_IO11 0x80000000 /* CS */ MX6UL_PAD_CSI_DATA08__GPIO5_IO14 0x80000000 /* DC */ MX6UL_PAD_CSI_DATA09__GPIO5_IO15 0x80000000 /* RST */ MX6UL_PAD_CSI_DATA07__GPIO5_IO13 0x80000000 /* BL */ ; }; }; ecspi3 { pinctrl-0 pinctrl_ecspi3; fsl,spi-num-chipselects 1; cs-gpios gpio5 11 GPIO_ACTIVE_LOW; status okay; lcd_panel: msp24020 { compatible ilitek,ili9341; reg 0; spi-max-frequency 10000000; rotate 90; fps 30; buswidth 8; dc-gpios gpio5 14 GPIO_ACTIVE_HIGH; reset-gpios gpio5 15 GPIO_ACTIVE_HIGH; led-gpios gpio5 13 GPIO_ACTIVE_HIGH; status okay; }; };这里把CS、DC、RST、BL全部通过GPIO控制。其中led-gpios是fbtft的背光控制字段设置后驱动会在初始化时自动把背光引脚拉高。如果设备树里不写这个屏能显示但背光不亮会让人误以为是白屏。3.2 把LCD注册成/dev/fb0编译内核时确认开启fbtft和ILI9341驱动。配置路径在Device Drivers - Staging drivers - Support for small TFT LCD display modules - FB driver for the ILI9341 LCD controller注意fbtft位于staging目录有些内核版本默认没开需要在menuconfig里手动勾选。编译完成后启动系统dmesg里应该能看到类似内容fbtft: module is from the staging directory, the quality is unknown, you have been warned. fb_ili9341: SPI display 240x320 registered as fb0 fbtft: 240x320, SPI, RGB565, 8bit如果看到“registered as fb0”说明注册成功。没有fb0先查设备树有没有挂对再看内核日志。启动后可以用cat /sys/class/graphics/fb0/name确认设备节点名字也可以直接往/dev/fb0里填充数据测试cat /dev/urandom /dev/fb0屏幕出现雪花噪点说明显示链路已经通了再用QT接管。3.3 调试显示参数的小工具fbtft有一个很有用的特性很多显示参数可以在运行时动态修改不用反复编译内核和重启。比如分辨率、虚拟分辨率、旋转方向、灰度gamma在用户态通过/sys/class/graphics/fb0/目录下的属性节点查看和修改。旋转方向可以通过fb0的rotate属性调整echo 180 /sys/class/graphics/fb0/rotate这个很实用。实际装屏时物理方向可能和设计方向差90度或者180度一行命令就能转过来不用重新编译。RGB/BGR顺序、gamma值也可以在部分fbtft版本里直接调。调试颜色顺序的快捷方法是在QT里画一张纯红、纯绿、纯蓝的色块图看屏上三个颜色是否对应。如果红蓝互换就把设备树bgr字段改一下或者调整MADCTL位。4. QT界面应用开发4.1 编译带linuxfb插件的QTIMX6ULL上跑QT交叉编译时QPA插件至少得有linuxfb。这个插件是QT基础平台插件在configure时加上-linuxfb即可。我用的配置命令大致如下./configure -prefix /opt/qt5 \ -xplatform linux-arm-gnueabi-g \ -opensource -confirm-license \ -no-opengl -no-xcb -no-vulkan \ -no-eglfs -no-gtk \ -linuxfb \ -nomake tests -nomake examples \ -no-pch如果希望QT直接全屏铺满屏幕不需要桌面系统linuxfb是首选。编译完成后把QT库拷贝到开发板设置环境变量export QT_ROOT/opt/qt5 export LD_LIBRARY_PATH$QT_ROOT/lib:$LD_LIBRARY_PATH export QT_QPA_PLATFORMlinuxfb:fb/dev/fb0:size240x320:mmSize90x67 export QT_QPA_FB_FORCE_FULLSCREEN1mmSize这个参数建议设置成接近实际屏幕物理尺寸的值否则字体缩放可能不对。如果没设置也没关系QT会用默认值对界面布局影响不大。有一点要注意QT的linuxfb后端默认只做局部刷新它有一个脏矩形机制界面变动区域才上报给framebuffer。这意味着QT不是每帧全屏刷新画简单静态界面时SPI压力很小但动画效果多了刷新率会明显下降。4.2 画一个旋转正方体的棱项目源码里的QT界面包含一个旋转的正方体这个效果其实只用了QPainter没有用到OpenGL。IMX6ULL不带GPUOpenGL只能走软渲染很吃力所以手动做三维投影反而是更靠谱的方案。实现思路分为几步。定义8个顶点坐标三维坐标范围在-1到1之间。通过旋转矩阵绕Y轴或Z轴旋转。最后做正交投影到二维坐标再通过QPainter的drawLine把12条棱画出来。核心代码思路如下void CubeWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(rect(), Qt::black); painter.setPen(QPen(Qt::green, 2)); const float angle m_angle; // 由QTimer定时递增 float box[8][3] { {-1,-1,-1},{ 1,-1,-1},{ 1, 1,-1},{-1, 1,-1}, {-1,-1, 1},{ 1,-1, 1},{ 1, 1, 1},{-1, 1, 1} }; QPoint pts[8]; for (int i 0; i 8; i) { float x box[i][0]; float y box[i][1] * cosf(angle) - box[i][2] * sinf(angle); float z box[i][1] * sinf(angle) box[i][2] * cosf(angle); int sx (int)(x * 80 width() / 2); int sy (int)(y * 80 height() / 2); pts[i] QPoint(sx, sy); } static const int edges[12][2] { {0,1},{1,2},{2,3},{3,0}, {4,5},{5,6},{6,7},{7,4}, {0,4},{1,5},{2,6},{3,7} }; for (int i 0; i 12; i) { painter.drawLine(pts[edges[i][0]], pts[edges[i][1]]); } }这个demo跑在320x240屏上很流畅30fps左右没问题。关键技巧是QTimer定时器设为16ms或者33ms配合update()触发重绘视觉上就是平滑旋转。4.3 中文字体与资源打包SPI小屏跑QT中文字体是个容易忽略的细节。标准QT交叉编译不带中文字体直接显示中文会变成方框。解决方法是把字体文件拷贝到开发板并在应用启动时加载。常见的做法是把文泉驿微米黑wqy-microhei.ttc或者思源黑体SourceHanSansCN-Regular.otf放到/usr/share/fonts目录然后代码里注册#include QFontDatabase QFontDatabase::addApplicationFont(/usr/share/fonts/wqy-microhei.ttc); QFont font(WenQuanYi Micro Hei); font.setPointSize(12); app.setFont(font);字体文件比较大几MB到十几MB对于IMX6ULL的eMMC来说完全没压力。如果实在想省空间可以用Fontmin之类的工具裁剪出用到的几个汉字几百KB就搞定。不过对大部分项目来说直接放下整个字体文件最省事调试也方便。QSS资源文件、图片资源正常用qrc打进二进制就行运行时不依赖额外文件这样交付方便。唯一要注意的是尺寸大的图片在SPI刷新下会有明显拖影尽量少用大面积渐变和背景图。4.4 触摸输入的接入如果MSP2402模组带触摸层QT输入还需要单独配置。电阻触摸屏在IMX6ULL上通常接SPI或者ADC驱动用ads7846设备树里注册触摸节点后会生成一个输入设备事件节点一般是/dev/input/event0。这时候QT需要设置触摸参数export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS/dev/input/event0如果是电容触摸屏芯片常见的有GT9147、GT911、FT5x06等通过I2C接口连接设备树里挂好驱动后同样走evdev输入事件。电容屏不需要校准电阻屏必须先跑ts_calibrate生成校准参数否则触摸和显示坐标对不上。没有触摸时鼠标可以用QT自带的鼠标插件或者通过tslib模拟。项目源码里如果只显示界面不需要交互可以完全不管输入直接跑纯显示程序。5. 调试中常见的问题与排障实录5.1 白屏、暗屏的常见原因白屏是SPI LCD遇到最多的问题我的经验是先从最简单的可能查起。背光不亮导致的“黑屏”很多人误以为白屏。先看背光GPIO是否被正确拉高最简单的方法是用万用表量背光引脚电压。如果设备树led-gpios没写fbtft不会管背光需要手动GPIO控制或者硬件上拉。真正白屏通常意味着ILI9341没有执行显示命令。检查几点RST引脚是否有正常复位脉冲复位后有没有延时足够久SCLK和MOSI是否接线正确有没有接反初始化序列是否完整0x29显示命令有没有发出去SPI速率是否过高导致命令传输错误可以先降到1MHz试那次调MSP2402白屏最后定位到就是设备树里reg属性没写对导致SPI子设备匹配不上系统在spidev下创建了/dev/spidev3.0但fbtft没有任何反应。改好reg后再启动一切正常。5.2 花屏和闪屏排查花屏比白屏好定位至少说明屏在工作问题基本出在数据链路。最常见的花屏原因是SPI时钟太高。杜邦线连接时线路电感电容会把波形拉得很难看10MHz时钟下信号振铃严重跳变沿不稳定花屏非常普遍。解决办法是把spi-max-frequency降到5MHz或更低或者换成短而粗的飞线有条件的话直接画PCB走线会好很多。还有一种花屏是数据命令切换时序不对。DC引脚在传输第一个数据bit之前必须已经稳定如果DC由GPIO控制且切换太慢ILI9341会把命令当数据解释。fbtft内部已经处理了这个问题如果是自己写用户态驱动这里要注意。闪屏则多半和刷新策略有关。QT在linuxfb下做部分刷新但如果界面全是大面积变化SPI全屏刷新帧率只有20-30fps视觉上就会闪烁。可以试试把fps参数调低一点减少刷屏频率或者减少QT动画幅度。5.3 颜色错乱与镜像显示颜色不对大多数是BGR和RGB顺序问题。ILI9341的MADCTL命令里有一个BGR位针对不同屏模组0x36设置的参数不同。fbtft设备树里可以设置bgr字段或者在用户态直接改颜色空间配置。我调试时先在QT里画一幅红绿蓝三色条看到红蓝互换就改bgr改完重启确认。镜像问题也是MADCTL的MX、MY位控制的。设备树rotate 90可以整体旋转但个别方向会有镜像。比如rotate 90后左右反了可以再给MADCTL加一个镜像位。fbtft里通常可以通过fb_var_screeninfo的rotate字段或者屏模组厂家的默认初始化参数来调和。5.4 SPI信号质量与布线经验最后讲一点硬件层面的心得。SPI_CLK线上串一个小电阻是嵌入式里常见的做法一般22Ω左右。这个电阻能抑制信号振铃减少过冲尤其对杜邦线连接场景效果明显。靠近屏端放也可以靠近主控放也可以我习惯放在主控侧。CS片选线上拉一个10k电阻到VCC防止控制器复位时CS电平不定导致屏幕误触发。如果CS悬空上电瞬间屏可能收到随机数据进入奇怪状态。地线一定不要省。MOSI、SCLK、DC、CS全部高速切换参考地回路阻抗高的画噪声会耦合到信号线上。我试过只接一根细地线花屏概率直线上升接两根粗地线后问题消失。最后再分享一个实用小经验调试初期不要直接用QT先在内核起来后用命令行工具测屏。往/dev/fb0填充纯色、画几条对角线确认SPI链路完全稳定后再启动QT应用。这样一旦出问题你能快速知道是QT层的问题还是底层驱动的问题不会被一堆报错带偏方向。SPI小屏调试本身不难难的是把各个环节拆开独立验证这一步做好了后面任何界面问题都好解决。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C8051F驱动256x64 OLED:并口/SPI配置与显存优化实践 2026/8/31 22:28:37

C8051F驱动256x64 OLED:并口/SPI配置与显存优化实践

简介:本资源是面向嵌入式开发初学者与C8051F单片机实践者的OLED显示驱动实战代码包,聚焦清达光电HGS256641(25664分辨率)OLED模块在Silicon Labs C8051F平台上的底层驱动实现,解决SPI通信配置、初始化时序控制、ASCII字…

阅读更多 →
STUSB4500 No Power故障排查:USB-C受电板无输出电压解决指南 2026/8/31 22:28:37

STUSB4500 No Power故障排查:USB-C受电板无输出电压解决指南

STUSB4500 No Power,这五个单词基本能概括我上周处理的一整块调试时间。朋友拿来一块基于 STUSB4500 的 USB-C 受电板,插上一颗 65W PD 适配器,Type-C 口的 VBUS 上能测到 5V,可板子后端输出就是一点

阅读更多 →
从安装到零成本推理:Hermes Agent v0.20.6 架构拆解、免费模型接入与真实性能评测 2026/8/31 22:28:37

从安装到零成本推理:Hermes Agent v0.20.6 架构拆解、免费模型接入与真实性能评测

摘要 本文基于 Nous Research 开源的 Hermes Agent v0.20.6(MIT License)在 Windows 原生环境下的真实安装、配置与实测过程,从四个维度展开: 安装体系的工程化设计——一套可跨平台、可断点续跑、面向"无人值守"的 Sta…

阅读更多 →
Hypermesh隐式分析位移边界条件设置详解与常见错误排查 2026/8/31 22:28:37

Hypermesh隐式分析位移边界条件设置详解与常见错误排查

在Hypermesh里设置隐式分析的位移边界条件,最容易出错的往往不是“不会操作”,而是“条件设定不符合求解器逻辑”。位移边界条件不是简单地给节点一个数值,它同时影响刚度矩阵、载荷步、反力和收敛行为,设置错误可能导致刚体位移或…

阅读更多 →
STM32U5固件升级后ADC4无法启动?时钟配置顺序是关键 2026/8/31 22:28:37

STM32U5固件升级后ADC4无法启动?时钟配置顺序是关键

一个困扰了我三天的问题:项目代码在 STM32U59A 上跑得好好的,ADC1 采样一切正常,ADC4 却没有完成过一次转换。更诡异的是,硬件没有变、CubeMX 工程没有变、PCB 没有动,只把 STM32CubeU5 固件包从 1.3.0 升到了 1.5.0&a…

阅读更多 →
STM32H750以太网失联排查:Cache一致性与DMA描述符配置详解 2026/8/31 22:25:36

STM32H750以太网失联排查:Cache一致性与DMA描述符配置详解

1. 问题现象:明明链路正常,可设备就是“失联”了做嵌入式网络开发的朋友应该都遇到过这种让人抓狂的场景:STM32H750板子刚上电,ping 192.168.1.100 一切正常,ARP也能正确解析,数据收发顺畅得很。结果跑了十…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞