3.5寸SPI LCD屏驱动全解析:从树莓派到STM32的底层开发指南

发布时间:2026/8/1 12:59:07
3.5寸SPI LCD屏驱动全解析:从树莓派到STM32的底层开发指南 1. 项目概述一块3.5寸LCD屏的“树莓派”之旅如果你手头恰好有一块标着“3.5inch RPi LCD (G)”的屏幕正琢磨着怎么让它亮起来那你来对地方了。这玩意儿在开源硬件圈里挺常见一块3.5英寸、分辨率320x480的TFT LCD自带电阻触摸接口是标准的SPI。它的核心是ST7796S驱动芯片和XPT2046触摸控制器名字里的“RPi”直指树莓派意味着官方或社区提供了针对树莓派GPIO的即插即用驱动让点亮它变得像搭积木一样简单。但它的价值远不止于此ST7796S这颗驱动芯片性能不俗支持RGB565/666接口而SPI模式只是其“节能省引脚”的工作状态XPT2046更是电阻触摸界的常青树。这意味着这块屏不仅是树莓派的专属配件更是我们深入理解SPI通信、LCD驱动乃至嵌入式GUI开发的绝佳实验平台。无论你是想快速在树莓派上做个显示终端还是打算用STM32、ESP32甚至FPGA来驯服它探索其底层时序这篇文章都将为你拆解清楚从接线、驱动到深度定制的每一步。2. 核心硬件与接口深度解析2.1 屏幕模组本体ST7796S驱动芯片探秘这块3.5寸屏的核心是ST7796S。这是一款262K色18位数据线的TFT LCD控制器。它支持多种接口模式包括并行的RGB接口和串行的SPI接口。在“3.5inch RPi LCD (G)”这个模组上为了节省树莓派宝贵的GPIO引脚设计者选择了SPI接口模式。需要注意的是SPI模式通常无法达到RGB接口的全带宽但对于320x480这种分辨率的静态图像或简单动画刷新40MHz甚至更高的SPI时钟下体验是足够流畅的。ST7796S内部有独立的显存GRAM我们通过SPI发送的命令和数据最终就是写入这片GRAM控制器再自动将GRAM中的内容映射到屏幕的每一个像素上。它有一系列初始化命令Initialization Command用于设置颜色格式、扫描方向、电源控制等。市面上很多驱动代码其核心就是按照ST7796S数据手册的时序要求通过SPI发送这一连串的初始化命令序列。注意不同批次或供应商的“3.5inch RPi LCD”其ST7796S的初始化序列可能有细微差别。如果发现屏幕点亮后颜色异常、花屏或只有背光亮首先应怀疑初始化代码是否完全匹配你的屏幕。通常供应商会提供参考代码。2.2 触摸功能核心XPT2046电阻触摸控制器屏幕下方的“G”通常代表带有电阻式触摸屏Resistive Touch。负责这项功能的是XPT2046芯片。它同样通过SPI接口与主控通信。与ST7796S不同XPT2046的SPI通信是典型的“查询”模式主控发起一次转换请求XPT2046在忙碌BUSY期间完成模数转换然后主控读取转换结果。XPT2046可以测量触摸点的X、Y坐标以及触摸压力通过测量Z轴。其精度通常能达到12位4096级。电阻屏的优势是成本低、抗干扰强任何物体均可触控缺点是透光率稍差且需要轻微压力。驱动XPT2046的关键在于理解其命令字Control Byte的格式以及如何将读取到的原始AD值通过校准算法转换成屏幕上的像素坐标。一个典型的坐标读取流程如下拉低片选CS。发送控制字例如启动通道选择Y坐标读取。读取高字节同时发送时钟。读取低字节同时发送时钟。拉高片选。对读取的12位数据进行处理可能需丢弃最低几位。2.3 接口定义与电气连接这块屏的接口通常是排针或排母引脚定义大同小异。一个典型的40Pin引脚定义适配树莓派会包含以下关键信号引脚号标号功能树莓派GPIO说明1, 173.3V电源正极3.3V逻辑与背光电源2, 45V背光电源可选5V部分模组背光需5V驱动6, 9, 14, 20, 25, 30, 34, 39GND电源地GND必须可靠连接19MOSISPI主出从入GPIO10 (MOSI)主控数据输出到屏幕21MISOSPI主入从出GPIO9 (MISO)触摸芯片数据输出到主控23SCLKSPI时钟GPIO11 (SCLK)通信时钟24CSLCD片选GPIO8 (CE0)选择LCD驱动芯片26DC数据/命令选择GPIO25高电平数据低电平命令22RST复位GPIO27硬件复位低电平有效18BL背光控制GPIO24PWM或高低电平控制亮度13T_CS触摸片选GPIO7 (CE1)选择触摸控制器芯片接线要点与避坑指南电源是关键务必确保3.3V和GND连接牢固。电流不足会导致屏幕工作不稳定、花屏或无法启动。如果屏幕背光单独由5V供电且电流需求较大可能超过树莓派单引脚供电能力建议使用外部5V电源并与树莓派共地。SPI冲突树莓派默认只有一个SPI总线SPI0其CE0和CE1是硬件片选。如果你同时连接了其他SPI设备如RFID读卡器需要注意片选冲突。LCD和触摸屏可以共享MOSI、MISO、SCLK但必须使用不同的GPIO作为片选如表中所示。复位与背光RST引脚在上电后需要一个由低到高的跳变过程来完成复位。有些驱动代码会手动控制这个引脚。BL背光控制如果接的是PWM引脚则可以实现亮度调节如果只是接普通GPIO则只能开关背光。3. 在树莓派上的快速点亮与驱动配置3.1 启用树莓派SPI接口树莓派系统默认可能未开启SPI。通过命令行即可轻松启用sudo raspi-config依次选择Interface Options-SPI-Yes启用。重启后可以通过以下命令检查SPI设备是否出现ls /dev/spi*如果看到/dev/spidev0.0和/dev/spidev0.1说明SPI0已启用其中.0对应CE0.1对应CE1。3.2 使用预编译驱动最简方法对于只是想快速用起来的用户最方便的方法是使用屏幕供应商或社区提供的预编译驱动/配置文件。通常这会是一个脚本执行后会自动下载并安装内核模块如fbtft。修改/boot/config.txt添加设备树覆盖Device Tree Overlay配置。配置触摸屏的坐标映射将/dev/input/eventX关联到屏幕。执行完驱动安装脚本并重启后屏幕应该就能作为系统的第二个显示器或主显示器正常工作触摸功能也即插即用。你可以通过xinput_calibrator工具进行触摸校准以获得更准确的点击体验。实操心得使用预编译驱动虽然省事但可能会遇到内核版本不兼容、与其他显示配置冲突等问题。如果安装后黑屏或无法启动可以尝试在启动时按住Shift键进入恢复模式通过命令行回滚配置。更可控的方式是手动配置这能让你更清楚底层发生了什么。3.3 手动配置FBTFT驱动进阶控制如果你想更深入地控制或者预编译驱动不工作可以尝试手动配置Linux内核的FBTFT框架。这需要编辑/boot/config.txt文件# 添加以下行 dtparamspion dtoverlaygpio-backlight # 关键加载针对ST7796S SPI的FBTFT设备树覆盖 # 注意覆盖层名称可能因内核版本和屏幕变体而异例如“pitft35-resistive” dtoverlaypitft35-resistive,speed32000000,rotate90 # 解释speed设置SPI时钟频率Hzrotate设置旋转角度重启后屏幕会作为一个帧缓冲设备如/dev/fb1出现。你可以使用fbi或自己编写的程序向/dev/fb1写入图像数据来显示。手动配置触摸触摸屏通常会生成一个输入设备如/dev/input/event1。你需要使用evdev驱动并通过xinput或修改X11配置将其映射到正确的屏幕。对于非桌面环境或嵌入式GUI如Qt Embedded则需要在应用层直接读取evdev事件并处理。4. 基于MCU如STM32的底层驱动开发将这块屏幕连接到STM32等单片机是学习嵌入式GUI和SPI通信的经典实践。这里我们以STM32的HAL库为例讲解驱动要点。4.1 SPI外设初始化配置首先需要初始化两个SPI外设或一个SPI分时复用一个用于LCDST7796S一个用于触摸XPT2046。它们的配置有共同点也有区别。LCD用SPI配置要点模式SPI_MODE3CPOL1 CPHA1或MODE0具体需查ST7796S手册常见为MODE3。数据大小8位SPI_DATASIZE_8BIT。时钟极性与相位根据数据手册设置。时钟预分频器决定SCLK频率。ST7796S的SPI接口最高时钟可达几十MHz。在STM32上根据系统时钟如72MHz设置分频如SPI_BAUDRATEPRESCALER_2得到36MHz。初始化和写入GRAM时可以用较低速刷图时再切换到高速。NSS片选管理设置为软件管理SPI_NSS_SOFT用普通GPIO口控制CS引脚。触摸用SPI配置要点XPT2046通常也支持MODE0或MODE3。其时钟频率要求较低一般2MHz左右即可。关键是需要全双工模式因为在发送控制字的同时需要接收来自触摸芯片的转换数据。// STM32 HAL库 SPI初始化示例片段LCD hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; hspi1.Init.Direction SPI_DIRECTION_2LINES; hspi1.Init.DataSize SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity SPI_POLARITY_HIGH; // CPOL1 hspi1.Init.CLKPhase SPI_PHASE_2EDGE; // CPHA1 hspi1.Init.NSS SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_8; // 初始用较低速 hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; hspi1.Init.TIMode SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial 10; if (HAL_SPI_Init(hspi1) ! HAL_OK) { Error_Handler(); }4.2 ST7796S的初始化与基本绘图函数驱动LCD的核心是编写两个底层函数写命令LCD_Write_Cmd和写数据LCD_Write_Data。通过控制DC数据/命令选择引脚的电平来区分。void LCD_Write_Cmd(uint8_t cmd) { LCD_DC_CMD(); // 设置DC引脚为低电平 LCD_CS_LOW(); // 拉低片选 HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); LCD_CS_HIGH(); } void LCD_Write_Data(uint8_t dat) { LCD_DC_DATA(); // 设置DC引脚为高电平 LCD_CS_LOW(); HAL_SPI_Transmit(hspi1, dat, 1, HAL_MAX_DELAY); LCD_CS_HIGH(); } void LCD_Write_Data_16bit(uint16_t dat) { uint8_t buf[2]; buf[0] dat 8; // 发送高字节 buf[1] dat 0xFF; // 发送低字节 LCD_DC_DATA(); LCD_CS_LOW(); HAL_SPI_Transmit(hspi1, buf, 2, HAL_MAX_DELAY); LCD_CS_HIGH(); }有了这两个函数就可以按照ST7796S数据手册提供的初始化序列一步步发送命令和数据。初始化通常包括软件复位、设置像素格式如RGB565、设置显示方向横屏/竖屏、打开显示等。设置窗口与写GRAM刷屏更新图像的效率是关键。ST7796S允许我们设置一个矩形窗口通过CASET和RASET命令然后连续向GRAM写入数据RAMWR命令数据会自动填充该窗口。这是实现局部刷新和快速全屏刷新的基础。void LCD_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_Write_Cmd(0x2A); // CASET LCD_Write_Data(x1 8); LCD_Write_Data(x1 0xFF); LCD_Write_Data(x2 8); LCD_Write_Data(x2 0xFF); LCD_Write_Cmd(0x2B); // RASET LCD_Write_Data(y1 8); LCD_Write_Data(y1 0xFF); LCD_Write_Data(y2 8); LCD_Write_Data(y2 0xFF); LCD_Write_Cmd(0x2C); // RAMWR }调用LCD_SetWindow后连续调用LCD_Write_Data_16bit对于RGB565格式即可填充窗口。为了极致优化可以将SPI切换为DMA模式并一次性发送整个帧缓冲区。4.3 XPT2046触摸数据读取与校准触摸驱动的核心是读取原始的AD值并通过校准将其转换为屏幕坐标。读取原始坐标函数uint16_t TP_Read_AD(uint8_t cmd) { uint8_t buf[3]; uint16_t ad_value 0; TP_CS_LOW(); HAL_SPI_TransmitReceive(hspi2, cmd, buf, 3, HAL_MAX_DELAY); // 发送命令同时接收3字节 TP_CS_HIGH(); ad_value ((buf[1] 8) | buf[2]) 3; // 组合有效数据位 return ad_value; } uint8_t TP_Read_XY(uint16_t *x, uint16_t *y) { uint16_t x_ad, y_ad; // 通常需要多次采样取平均以抗干扰 x_ad TP_Read_AD(CMD_RDX); y_ad TP_Read_AD(CMD_RDY); // 检查是否在合理范围内非触摸时XPT2046会返回接近0或4095的值 if(x_ad 100 x_ad 3900 y_ad 100 y_ad 3900) { *x x_ad; *y y_ad; return 1; // 触摸有效 } return 0; // 无触摸 }触摸校准电阻屏必须校准。经典的四点校准法需要用户在屏幕四个角依次点击程序记录下点击时读取的原始AD值(Xraw, Yraw)和对应的理论屏幕像素坐标(Xdisp, Ydisp)。 通过这两组映射关系可以计算出校准参数通常是一个仿射变换矩阵包含缩放和偏移。一个简化的线性模型如下Xdisp A * Xraw B Ydisp C * Yraw D通过解方程求出A、B、C、D四个参数后续所有触摸点都通过这个公式转换。更精确的校准可以考虑更复杂的模型以纠正屏幕的非线性误差。5. 性能优化与高级应用探讨5.1 使用DMA提升SPI刷屏效率当需要刷新全屏或大块区域时频繁调用HAL_SPI_Transmit会产生大量CPU中断开销严重限制帧率。此时直接内存访问DMA是救星。配置SPI DMA在CubeMX中为SPI的TX流启用DMAMemory-to-Peripheral。然后你可以准备一个完整的帧缓冲区frame buffer里面按顺序存放着屏幕上每个像素点的RGB565数据。DMA刷屏流程设置好显示窗口LCD_SetWindow(0,0,width-1,height-1)。启动SPI发送命令0x2CRAMWR。紧接着不是用HAL_SPI_Transmit发送数据而是用HAL_SPI_Transmit_DMA将帧缓冲区的地址和长度像素数*2字节传给它。DMA控制器会在后台自动将数据从内存搬运到SPI数据寄存器无需CPU干预。CPU可以在此期间处理触摸、逻辑等任务。通过DMA传输完成中断或回调函数得知一帧数据发送完毕可以准备下一帧。踩坑记录使用DMA时务必确保帧缓冲区位于DMA可访问的内存区域如STM32的普通SRAM并且其生命周期覆盖整个DMA传输过程不能是局部变量。另外SPI时钟频率和DMA带宽要匹配过高的SPI速度可能导致DMA来不及供数造成显示撕裂。此时可以尝试启用SPI的FIFO或适当降低SPI时钟。5.2 驱动常见问题与排查技巧在驱动开发过程中你几乎一定会遇到以下问题。这里提供一个速查表现象可能原因排查步骤白屏或背光亮但无显示1. 初始化序列错误或缺失。2. 电源不稳定。3. 复位信号异常。1. 用逻辑分析仪抓取SPI时序核对发送的命令序列是否与数据手册一致。2. 测量3.3V电压检查电源电流是否足够可并联电容试试。3. 检查RST引脚上电时序确保有从低到高的跳变。花屏、错位、颜色异常1. 像素格式设置错误如RGB565设成RGB666。2. 扫描方向MADCTL设置错误。3. 显存GRAM写入地址错误。1. 确认初始化命令中颜色格式设置字节。2. 尝试修改MADCTL寄存器的值旋转屏幕看是否正常。3. 检查CASET/RASET窗口设置函数坐标计算是否正确。触摸完全无反应1. 触摸SPI通信失败。2. 触摸芯片电源或基准电压异常。3. 触摸屏物理损坏。1. 用逻辑分析仪检查触摸SPI的CS、CLK、MOSI、MISO信号。2. 测量XPT2046的VCC和VREF引脚电压。3. 轻微按压屏幕四边看是否有某个区域有反应。触摸坐标不准、漂移1. 未校准或校准参数错误。2. 电源噪声干扰。3. 采样次数不足噪声大。1. 重新执行四点校准程序。2. 为触摸芯片的电源引脚增加滤波电容。3. 增加单次坐标的采样次数如8次并取中值滤波。刷屏速度慢闪烁1. 未使用DMACPU搬运数据耗时太长。2. SPI时钟频率设置过低。3. 刷新策略不佳全屏刷新太频繁。1. 启用SPI TX DMA。2. 在屏幕和主控允许范围内提高SPI波特率预分频。3. 采用局部刷新只更新变化区域。与其它SPI设备冲突片选CS信号管理混乱。确保同一时间只有一个设备的CS引脚被拉低。仔细检查所有SPI设备的CS引脚GPIO初始化状态默认应为高电平。5.3 超越基础GUI集成与项目构想当你成功驱动了屏幕和触摸一个充满可能性的世界就打开了。你可以在此基础上集成轻量级GUI库。LVGL这是一个高度可裁剪、硬件要求极低的开源嵌入式图形库。它提供了丰富的控件按钮、图表、列表等和动画效果。将LVGL的显示驱动回调函数指向你的LCD_SetWindow和刷屏函数将输入设备回调指向你的触摸坐标读取函数就能快速构建出漂亮的交互界面。emWin/STemWin如果你是STM32用户并且芯片有足够的Flash/RAM可以尝试Segger的emWin。它功能强大但通常需要授权。ST为其部分MCU提供了免费的STemWin库。自己实现对于简单需求如绘制几个按钮和进度条完全可以自己用基础绘图函数画线、矩形、填充、显示位图和状态机逻辑来实现这样代码最精简控制力最强。项目构想方向智能家居中控屏用树莓派这块屏运行Kivy或PyQt做一个本地控制界面连接MQTT获取传感器数据控制智能设备。嵌入式数据仪表用STM32读取传感器如温湿度、压力在屏幕上实时绘制曲线图、仪表盘。复古游戏机利用STM32的性能驱动屏幕显示配合按键实现一些简单的像素游戏。FPGA显示验证终端通过FPGA模拟SPI主控将内部逻辑分析仪的数据或图像处理结果实时显示在这块屏上作为调试终端。驱动一块SPI LCD屏从点亮的瞬间到实现流畅的交互整个过程是对嵌入式开发中硬件接口、驱动编写、性能优化和系统集成能力的综合锻炼。无论是用树莓派快速原型验证还是用MCU深入底层这块“3.5inch RPi LCD (G)”都是一个绝佳的起点。当你看到自己编写的代码让像素逐一亮起触摸精准响应时那种成就感正是嵌入式开发的乐趣所在。