行业资讯

1.69英寸SPI LCD驱动全解析:从硬件选型到DMA优化实战

发布时间:2026/8/3 5:29:49
1.69英寸SPI LCD驱动全解析:从硬件选型到DMA优化实战 1. 项目概述为什么是1.69英寸SPI LCD如果你正在为一个嵌入式项目寻找一块小巧、省电、驱动简单的显示屏那么1.69英寸的SPI接口LCD绝对是一个值得深入研究的选项。它不像那些动辄5寸、7寸的“大家伙”需要复杂的RGB接口和高速内存也不像I2C屏那样在刷新率和分辨率上有所妥协。这块屏的定位非常精准在有限的引脚资源和主控性能下提供一块足够清晰、刷新流畅、且易于集成的视觉交互窗口。我手头这块典型的1.69英寸LCD分辨率通常是240x280或240x240色彩深度为16位或18位即RGB565或RGB666。SPISerial Peripheral Interface作为其通信接口意味着你只需要3到4根数据线MOSI, SCLK, DC, CS有时再加一根RST就能完全控制它。这对于引脚紧张的单片机比如STM32F103的某些小封装型号、ESP8266/ESP32甚至是Arduino Nano来说简直是福音。你不需要为并行总线预留8位或16位的数据端口也无需担心高速信号带来的PCB布局难题。那么谁适合用这块屏呢首先是各类便携式穿戴设备、智能家居中控的副屏、小型工控仪表显示单元以及所有对体积、功耗和开发复杂度有严格限制的嵌入式创客项目。它的核心价值在于用极简的硬件连接换取一个功能完整的图形输出能力。接下来我将从硬件选型、驱动原理、软件实现到实战调优完整拆解如何玩转这块屏。2. 核心硬件解析与选型要点2.1 显示屏模组本身驱动IC与接口市面上常见的1.69英寸SPI LCD其核心是一块液晶面板搭配一个驱动芯片。最常见的驱动芯片是ST7789、ILI9341虽然它更常用于2.8寸屏但也有小尺寸变体或GC9A01。选型时驱动芯片是关键它决定了你后续的驱动库和初始化序列。你需要从卖家提供的资料或芯片数据手册中确认以下几点分辨率与色彩格式确认是240x280还是240x240。色彩格式支持RGB56516位色还是RGB66618位色。RGB565是嵌入式领域最常用的格式因为它刚好占用两个字节处理效率高。SPI模式与速率SPI有4种模式CPOL, CPHA组合驱动芯片会指定一种常见的是Mode 0CPOL0, CPHA0或Mode 3。必须在主控初始化SPI时匹配。最大SPI时钟速率如80MHz决定了你的刷新速度上限。引脚定义SCLK (Serial Clock) SPI时钟线。MOSI (Master Out Slave In) 主控输出数据到屏幕。DC (Data/Command) 至关重要的引脚。用于区分当前发送的是“命令”如设置地址窗口还是“数据”实际的像素颜色。拉低为命令拉高为数据。CS (Chip Select) 片选低电平有效。当总线上有多个SPI设备时用于选择屏幕。RST (Reset) 硬件复位低电平有效。通常上电后需要拉低一段时间再拉高以确保驱动芯片状态可靠。BL (Backlight) 背光控制。可能是高电平使能也可能是PWM调光。这是影响功耗和观感的重要部分。注意有些廉价的模块为了省引脚可能省略了DC和RST而使用特定的数据包协议来区分命令/数据或者只依赖软件复位。这会给驱动编写带来额外复杂度优先选择带有独立DC和RST引脚的模块。2.2 主控MCU的选择与资源评估选择主控时SPI LCD的驱动对性能有一定要求尤其是你想实现流畅动画或快速刷屏时。基础需求一个硬件SPI外设至少支持Master模式、足够的GPIO用于DC, CS, RST, BL、以及足够的RAM和Flash。性能进阶如果你希望获得更高的帧率DMA直接存储器访问功能几乎是必选项。DMA可以在不占用CPU的情况下搬运显存数据到SPI外设让CPU腾出手来处理业务逻辑或图形计算。这也是网络热词中“stm32h750 dma 驱动 spi lcd 问题”备受关注的原因——高性能主控搭配DMA是优化体验的关键。内存考量对于240x280 RGB565的屏幕一帧图像需要240 * 280 * 2 134,400字节约131KB的显存。如果你的主控如STM32F103内部RAM不足可以考虑使用局部刷新只更新屏幕上变化的部分区域而非全屏刷新。使用外部RAM如SDRAM像STM32H750这类高性能MCU可以外扩SDRAM作为显存。使用单缓冲直接流式写入不分配完整显存绘制图形时直接通过SPI发送像素数据。这需要图形库有相应的流式输出支持且无法实现复杂的双缓冲防撕裂。常见主控方案对比STM32F1系列如F103C8T6硬件SPI速率可达36MHz但RAM较小20KB通常只能用于静态显示或极小区域动态更新。适合简单界面。STM32F4系列如F407性能更强RAM更大192KB可以轻松分配完整显存配合DMA能实现流畅刷新。ESP32系列集成Wi-Fi/蓝牙双核SPI速率高且通常有足够PSRAM可扩展作为显存是物联网显示终端的绝佳选择。GD32、AT32等国产替代与STM32 Pin-to-Pin兼容性价比高驱动代码通常可移植。2.3 电源与背光电路设计显示屏模组通常需要3.3V供电逻辑部分背光LED可能是3.3V或5V驱动。务必查阅数据手册。电源稳定性当屏幕全白所有像素点亮时瞬时电流可能达到100mA以上。确保你的电源电路尤其是LDO能提供足够且稳定的电流否则可能导致MCU复位或屏幕闪烁。背光控制如果BL引脚支持PWM调光强烈建议连接到MCU的一个PWM输出通道。这样你就可以通过代码无级调节屏幕亮度适应不同环境光线这也是提升产品质感的一个小细节。如果只是简单的开关控制用一个GPIO口即可。3. 驱动原理深度剖析从SPI协议到帧缓冲3.1 SPI通信协议在LCD驱动中的具体应用SPI是一种全双工、同步的串行通信总线。在驱动LCD时我们通常只使用主控发送MOSI功能屏幕作为只接收的Slave设备。关键点在于DC引脚的作用它本质上扩展了SPI的数据协议。当DC为低电平时通过MOSI发送的一个字节8位被屏幕解释为命令码Command例如0x2A可能代表“设置列地址”。当DC为高电平时发送的字节则被解释为数据Data该数据可能是命令的参数也可能是像素的颜色值。一个典型的设置屏幕显示区域Setting Column Address的序列如下DC拉低通过SPI发送命令字节0x2A。DC拉高通过SPI发送4个数据字节起始列高8位、起始列低8位、结束列高8位、结束列低8位。接着DC拉低发送设置行地址的命令0x2B再拉高发送4个行地址数据字节。最后DC拉低发送开始写入显存GRAM的命令0x2C。此后只要保持DC为高通过SPI发送的所有数据字节都会被依次存入上一步设定的矩形区域并显示在屏幕上。对于RGB565格式每个像素点需要连续发送2个字节先高8位后低8位。SPI的四种模式这由时钟极性CPOL和时钟相位CPHA决定。必须与屏幕驱动芯片要求的一致。通常ST7789等芯片在上升沿采样数据这意味着在SCLK的上升沿MOSI上的数据必须已经稳定。这对应着CPOL0, CPHA0模式0或CPOL1, CPHA1模式3。具体需查手册但模式0最为常见。3.2 显存GRAM与地址窗口机制屏幕驱动芯片内部有一个图形显存GRAM。这个显存的大小正好对应屏幕的分辨率。我们通过SPI写入的数据最终就是存放在这个GRAM的特定位置。地址窗口Address Window是一个核心概念。在向屏幕发送像素数据前我们必须先通过0x2A和0x2B命令设定一个矩形的“窗口”。设定后后续发送的像素数据流会从该窗口的左上角开始按行优先的顺序自动填充。每填满一行列地址自动复位到起始列行地址加一。这极大地简化了操作你只需要设定一次窗口然后就可以连续发送一整块区域甚至全屏的像素数据而无需为每个像素指定坐标。3.3 DMA如何加速SPI数据传输没有DMA时CPU需要执行以下操作从内存中读取一个颜色数据2字节- 等待SPI发送缓冲区空 - 将数据写入SPI数据寄存器 - 重复数十万次对于一帧图像。这期间CPU被完全占用。启用DMA后流程变为CPU配置好SPI和DMA告诉DMA源地址显存数组、目标地址SPI数据寄存器地址、传输数据量。CPU启动SPI和DMA传输。DMA控制器自动从内存搬运数据到SPI外设完全不需要CPU干预。CPU可以立即去执行其他任务比如准备下一帧的图形数据实现双缓冲或者处理网络数据、传感器读数等。当DMA传输完成一整帧数据后会产生一个中断CPU在中断服务程序里进行帧同步如交换双缓冲指针等操作。这就是“stm32h750 dma 驱动 spi lcd 问题”的核心价值所在。H750的高性能SPI可达150MHz以上配合DMA可以轻松实现60fps甚至更高的刷屏率为流畅的UI动画打下基础。常见问题通常集中在DMA传输完成中断的处理、内存对齐Cache一致性以及SPI时钟配置上。4. 软件驱动实现全流程4.1 底层硬件抽象层HAL驱动编写无论你用标准外设库、HAL库还是LL库底层驱动函数都需要实现几个核心功能1. 引脚初始化void LCD_GPIO_Init(void) { // 初始化 SCLK, MOSI, CS, DC, RST, BL 对应的GPIO // 将SCLK和MOSI配置为复用推挽输出连接到SPI外设 // 将DC, CS, RST, BL配置为通用推挽输出 // 初始状态CS高不选中RST高BL低关闭背光 }2. SPI外设初始化void LCD_SPI_Init(void) { SPI_HandleTypeDef hspi; hspi.Instance SPI1; hspi.Init.Mode SPI_MODE_MASTER; hspi.Init.Direction SPI_DIRECTION_2LINES; // 全双工但只发不收 hspi.Init.DataSize SPI_DATASIZE_8BIT; // 以8位为单位发送 hspi.Init.CLKPolarity SPI_POLARITY_LOW; // CPOL 0 hspi.Init.CLKPhase SPI_PHASE_1EDGE; // CPHA 0 模式0 hspi.Init.NSS SPI_NSS_SOFT; // 软件控制CS引脚 hspi.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_2; // 系统时钟/2追求速度 hspi.Init.FirstBit SPI_FIRSTBIT_MSB; // 先发送最高位 hspi.Init.TIMode SPI_TIMODE_DISABLE; hspi.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; HAL_SPI_Init(hspi); }3. 基本读写函数void LCD_Write_Cmd(uint8_t cmd) { LCD_DC(0); // DC拉低写命令 LCD_CS(0); // 选中设备 HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); LCD_CS(1); } void LCD_Write_Data(uint8_t data) { LCD_DC(1); // DC拉高写数据 LCD_CS(0); HAL_SPI_Transmit(hspi1, data, 1, HAL_MAX_DELAY); LCD_CS(1); } void LCD_Write_Data_16bit(uint16_t data) { uint8_t buf[2]; buf[0] data 8; // 发送高字节 buf[1] data 0xFF; // 发送低字节 LCD_DC(1); LCD_CS(0); HAL_SPI_Transmit(hspi1, buf, 2, HAL_MAX_DELAY); LCD_CS(1); }4. 初始化序列Reset Initialization这是最繁琐但必须精确的一步。不同驱动芯片的初始化序列不同通常由厂家提供或从开源驱动库中获取。序列包含一系列命令和数据用于设置屏幕的扫描方向、颜色格式、伽马校正、电源控制等。void LCD_Init(void) { // 1. 硬件复位 LCD_RST(0); HAL_Delay(100); // 保持低电平至少10ms LCD_RST(1); HAL_Delay(120); // 等待复位稳定 // 2. 发送初始化命令序列 LCD_Write_Cmd(0x01); // Software reset HAL_Delay(150); LCD_Write_Cmd(0x11); // Sleep out HAL_Delay(120); LCD_Write_Cmd(0x3A); // Interface Pixel Format LCD_Write_Data(0x55); // 0x55 for 16bit/pixel (RGB565) // ... 发送更多初始化命令 LCD_Write_Cmd(0x29); // Display ON HAL_Delay(100); // 3. 开启背光 LCD_BL(1); }4.2 基于DMA的刷屏函数优化这是提升性能的关键。我们以填充整个屏幕一种颜色为例1. 准备显存Frame Buffer// 在内存中分配一个显存数组大小为屏幕分辨率 * 2字节 uint16_t frame_buffer[LCD_HEIGHT][LCD_WIDTH]; // 二维数组便于按坐标操作 // 或者一维数组 uint16_t frame_buffer[LCD_HEIGHT * LCD_WIDTH];2. DMA刷屏函数void LCD_Refresh_DMA(uint16_t *buf, uint32_t size) { // 1. 设置地址窗口为全屏 LCD_Set_Address(0, 0, LCD_WIDTH-1, LCD_HEIGHT-1); // 2. 发送写GRAM命令 (0x2C) LCD_Write_Cmd(0x2C); // 3. 启动DMA传输将buf中的数据通过SPI发送出去 LCD_DC(1); // 后续都是数据 LCD_CS(0); HAL_SPI_Transmit_DMA(hspi1, (uint8_t*)buf, size * 2); // size是像素数乘以2是字节数 // 注意这里CS在DMA传输完成中断中再拉高更安全 } // DMA传输完成中断回调函数 void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { if(hspi-Instance SPI1.Instance) { LCD_CS(1); // 传输完成取消片选 // 可以在这里设置一个标志位通知主循环一帧刷新完成 g_frame_ready 1; } }3. 双缓冲Double Buffering防撕裂这是实现流畅动画的高级技巧。准备两个显存缓冲区frame_buffer_front和frame_buffer_back。绘制阶段CPU在frame_buffer_back后缓冲中绘制下一帧图像。交换阶段当后缓冲绘制完成且前缓冲frame_buffer_front的DMA传输也已完成时交换两个缓冲区的指针。显示阶段启动DMA将新的frame_buffer_front即刚才画好的后缓冲发送到屏幕。 这样屏幕永远只显示完整的、绘制好的一帧避免了绘制到一半的图像被显示出来造成的“撕裂”现象。4.3 图形库GUI的集成与使用直接操作像素点太低效。集成一个轻量级GUI库能极大提升开发效率。常用的有LVGL当前最热门的开源嵌入式GUI库功能强大支持动画、主题、多种控件对SPI LCD和DMA有很好的支持。u8g2专注于单色显示屏但也支持彩色API简单资源占用极小。TouchGFXST主推的商用级GUI效果炫酷但需要授权且对硬件要求高。以集成LVGL为例关键步骤是提供其所需的“显示驱动”和“刷屏回调函数”在LVGL的显示驱动初始化中注册一个flush_cb回调函数。当LVGL需要刷新一块区域时会调用这个回调并传入一个包含像素数据的数组和区域信息。在flush_cb函数内部你调用前面写好的LCD_Set_Address和LCD_Refresh_DMA或非DMA版本函数将这块区域的数据发送到屏幕。发送完成后调用lv_disp_flush_ready通知LVGL刷新完成。这样你就可以使用LVGL丰富的API来创建按钮、标签、图表等界面元素而无需关心底层像素如何发送。5. 实战调试与性能优化技巧5.1 上电无显示系统化排查流程电源与背光首先用万用表测量屏幕VCC和GND引脚是否有稳定的3.3V背光引脚BL电压是否正常高电平或PWM信号可以尝试强制给BL高电平看是否有背光亮起。复位时序确保复位序列正确。有些屏幕对复位低电平的持续时间很敏感太短或太长都不行。严格按照数据手册的时序操作必要时用逻辑分析仪抓取RST引脚波形。SPI信号使用逻辑分析仪或示波器连接SCLK和MOSI线。上电初始化阶段应该能看到密集的SPI数据波形。检查SCLK频率是否在芯片支持的范围内初始阶段不宜过高。SPI模式CPOL/CPHA是否正确。波形不对通常表现为屏幕花屏、错位或完全无反应。DC引脚是否在正确的时间切换电平。初始化序列这是最可能出问题的地方。逐条核对初始化命令和数据特别是关键命令如睡眠退出Sleep Out、像素格式设置Pixel Format、显示开Display ON。一个命令错误就可能导致屏幕处于未知状态。最好能找到官方示例代码或经过验证的开源代码进行比对。软件片选与硬件片选如果你使用软件控制CSSPI_NSS_SOFT确保在每个命令/数据包前后正确控制CS引脚。如果使用硬件NSS检查SPI配置是否正确。5.2 提升刷新率的实战策略刷新率FPS SPI时钟频率 / (每帧像素数 * 每像素位数 * 开销系数)。最大化SPI时钟在保证信号完整性的前提下将SPI的预分频器BaudRatePrescaler调到最小。STM32H7的SPI可以轻松跑到100MHz以上。启用DMA这是最有效的措施解放CPU。减少传输开销合并传输设置地址窗口后发送像素数据时尽量使用一次性发送大量数据的API如HAL_SPI_Transmit_DMA而不是逐像素调用LCD_Write_Data_16bit。后者会产生大量DC和CS的控制开销。优化DC控制在全屏刷新时可以在发送0x2C命令后将DC引脚置高然后发送一整帧数据期间不再切换DC。这需要驱动函数配合。使用缩减更新区域UI变化时只刷新脏矩形区域Dirty Rectangle而不是全屏。LVGL等GUI库自动支持此优化。选择RGB565格式相比RGB66618位RGB56516位每个像素减少1字节传输量对240x280屏幕一帧可减少约26KB的数据量提升显著。5.3 降低系统功耗的考量对于电池供电设备屏幕是耗电大户。背光管理背光LED是主要功耗源。通过PWM动态调节亮度在环境光暗时调低亮度。在系统休眠时彻底关闭背光。利用睡眠模式大部分LCD驱动芯片支持睡眠Sleep In和深度睡眠模式。在长时间不刷新时发送睡眠命令可以将芯片功耗从毫安级降至微安级。唤醒时再发送睡眠退出Sleep Out命令。注意睡眠后需要重新初始化部分寄存器。降低刷新率对于静态显示内容可以大幅降低刷新率比如从60Hz降到1Hz。这需要GUI库支持按需刷新或定时刷新。5.4 抗干扰与PCB布局建议SPI速率较高时20MHz布线不当会引起显示异常雪花、条纹。等长与紧耦合SCLK和MOSI信号线应尽可能等长并平行走线且远离其他高速或噪声源如电机驱动、开关电源。串联匹配电阻在靠近MCU输出的SCLK和MOSI线上串联一个22Ω-100Ω的小电阻可以抑制信号过冲和振铃。电源去耦在屏幕模组的电源入口处紧贴引脚放置一个10μF的钽电容和一个0.1μF的陶瓷电容用于滤除低频和高频噪声。接地确保屏幕模组的地线与主控地线连接良好最好有独立的宽走线或铺铜连接。6. 进阶应用与项目构思掌握了基础驱动后这块小屏能玩出很多花样1. 便携式游戏机使用STM32F4或ESP32作为主控搭配摇杆和按键利用DMA双缓冲实现流畅的2D游戏画面如贪吃蛇、打飞机。关键在于高效的精灵图Sprite渲染和碰撞检测算法。2. 智能家居信息屏ESP32连接Wi-Fi从网络API获取天气、时间、新闻头条等信息通过LVGL制作精美的信息卡片界面。可以增加触摸功能电阻屏或电容屏模组实现交互。3. 微型示波器/频谱仪利用MCU的ADC采集信号进行FFT运算如网络热词“基于stm32的lcd信号波形和fft频谱显示”将时域波形和频域频谱实时绘制在屏幕上。这对MCU的运算能力和屏幕刷新率有较高要求。4. 自定义仪表盘用于小型机器人、无人机或智能车显示速度、电量、传感器状态、摄像头预览图等。需要将各种数据源进行融合并以直观的图形化方式呈现。5. 电子相框/动画展示盒从SD卡读取图片BMP、JPEG需解码或动画序列帧循环播放。可以研究如何用硬件解码如STM32的JPEG硬解或高效软件解码来减轻CPU负担。在实现这些项目时你会遇到更具体的问题例如在ESP32上如何将PSRAM配置为LVGL的显存或者如何优化STM32的LTDCSPI混合使用。但万变不离其宗核心依然是理解SPI通信、显存管理、DMA应用以及图形库的整合。这块1.69英寸的SPI LCD就像一扇小窗背后连接的是一个充满可能性的嵌入式图形世界。从点亮它的第一个像素开始你的项目就拥有了与用户视觉交互的灵魂。