1. ST7789驱动TFT屏幕的常见困惑
第一次接触ST7789驱动TFT屏幕的开发者,大概率会遇到这样的场景:你拿着芯片手册和屏幕厂家的规格书反复对比,却发现引脚定义对不上号,接口描述像在打哑谜。这种"文档打架"的情况我遇到过不下十次,最夸张的一次是某款1.54寸屏的RESET引脚居然被厂家标成了"NC"(不连接),实际测试时却发现这个引脚必须接MCU的复位信号。
ST7789作为Sitronix公司的经典驱动芯片,支持多种接口模式:
- Parallel 8080(8/9/16/18位并口)
- SPI(3线/4线配置)
- RGB接口(带同步信号)
但问题在于:不同屏幕厂家对接口的命名和配置千差万别。比如同样是DCX引脚,有的厂家标为"RS",有的标为"A0";WRX引脚可能被标注为"WR"或"SCL"。更头疼的是IM[3:0]这组配置引脚,厂家经常在内部做固定连接,却不在显眼位置说明。
2. 数据手册的关键信息提取
2.1 接口模式配置矩阵
ST7789的IM3~IM0引脚组合决定了工作模式,这个真值表必须烂熟于心:
| IM3 | IM2 | IM1 | IM0 | 接口模式 |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 并行8080 8位 |
| 0 | 0 | 0 | 1 | 并行8080 9位 |
| 0 | 0 | 1 | 0 | 并行8080 16位 |
| 0 | 0 | 1 | 1 | 并行8080 18位 |
| 0 | 1 | 0 | 0 | 3线SPI |
| 0 | 1 | 0 | 1 | 4线SPI(模式Ⅰ) |
| 0 | 1 | 1 | 0 | 4线SPI(模式Ⅱ) |
| 0 | 1 | 1 | 1 | RGB接口 |
实战经验:90%的SPI接口屏幕会把IM3固定接地(低电平),IM0~IM2通过电阻配置。我曾遇到过一款屏在IM[3:0]=0101时无法通信,最后发现厂家要求必须设为0111(RGB模式),尽管实际用的是SPI。
2.2 引脚功能的多重身份
ST7789的引脚往往身兼数职,比如:
- DCX/RS:在并行模式下是数据/命令选择线,在SPI模式下可能变成写使能
- WRX/SCL:并行模式是写脉冲,SPI模式是时钟线
- RDX:并行模式是读使能,SPI模式下通常悬空
避坑技巧:用万用表蜂鸣档测量屏幕FPC连接器上IM引脚的实际连接电平。曾经有个项目调试两天无果,后来发现厂家把IM2和IM1都接到了VCC,却未在文档中注明。
3. SPI接口配置实战
3.1 四线SPI的硬件连接
以STM32F4系列为例,典型接线如下(注意厂家差异):
| STM32引脚 | 屏幕引脚标记 | 实际功能 |
|---|---|---|
| PA4 | CS | 片选(低有效) |
| PA5 | SCL/CLK | SPI时钟 |
| PA7 | SDA/MOSI | 主设备输出 |
| PA6 | NC | 主设备输入 |
| PB1 | DC/RS | 数据/命令选择 |
| NRST | RES | 硬件复位 |
| PC13 | BLK | 背光控制 |
关键细节:
- 部分屏幕的SDO(MISO)可以不接,但全双工通信时需要连接
- 复位引脚建议接MCU的GPIO而非直接接VCC,方便软件复位
- 背光控制如果是PWM调光,需接定时器通道引脚
3.2 初始化代码剖析
以下是经过验证的SPI初始化代码(HAL库版本):
void SPI_Init(void) { 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_LOW; // 时钟极性 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 时钟相位 hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制片选 hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 21MHz @84MHz主频 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; HAL_SPI_Init(&hspi1); // GPIO初始化 GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); }参数调优经验:
- SPI时钟超过30MHz可能导致通信不稳定,建议先用低速测试
- 如果出现雪花噪点,尝试调整CLKPolarity和CLKPhase组合
- DMA传输时记得配置FIFO阈值:
hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
4. 8080并行接口的特殊处理
4.1 线序核对要点
并口驱动要特别注意数据总线位序,曾遇到过一个坑:某屏幕的DB0~DB7对应MCU的D7~D0,正好反序。建议在初始化代码中加入位序映射:
// 错误示例(导致颜色错乱) #define LCD_DATA_PORT GPIOB // 正确做法(根据屏幕规格书调整) #define LCD_D0_PIN GPIO_PIN_8 #define LCD_D1_PIN GPIO_PIN_9 ... void WriteDataBus(uint8_t data) { HAL_GPIO_WritePin(LCD_DATA_PORT, LCD_D0_PIN, (data&0x01)?GPIO_PIN_SET:GPIO_PIN_RESET); HAL_GPIO_WritePin(LCD_DATA_PORT, LCD_D1_PIN, (data&0x02)?GPIO_PIN_SET:GPIO_PIN_RESET); // ...依次处理D2~D7 }4.2 时序参数配置
8080接口的建立时间(tDS)、保持时间(tDH)等参数在STM32中通过FSMC配置:
void MX_FSMC_Init(void) { SRAM_HandleTypeDef hsram1; FSMC_NORSRAM_TimingTypeDef Timing = {0}; hsram1.Instance = FSMC_NORSRAM_DEVICE; hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; /* 时序参数(单位:HCLK周期) */ Timing.AddressSetupTime = 1; // 地址建立时间 Timing.AddressHoldTime = 0; // 地址保持时间 Timing.DataSetupTime = 2; // 数据建立时间 Timing.BusTurnAroundDuration = 0; Timing.CLKDivision = 0; Timing.DataLatency = 0; Timing.AccessMode = FSMC_ACCESS_MODE_A; HAL_SRAM_Init(&hsram1, &Timing, &Timing); }实测建议:
- 对于240x320屏幕,DataSetupTime建议不小于2个时钟周期
- 如果出现局部花屏,尝试增加AddressSetupTime
- 使用逻辑分析仪捕捉WR和DATA信号时序,确保满足屏幕规格书要求
5. 显示异常排查指南
5.1 颜色错位问题
当出现红色和蓝色通道互换时,检查MADCTL寄存器的RGB/BGR位:
void SetRGBOrder(bool isBGR) { WriteCommand(0x36); // MADCTL WriteData(isBGR ? 0x08 : 0x00); // 设置RGB顺序 }5.2 屏幕偏移校正
部分屏幕的显示区域不从(0,0)开始,需要通过CASET和RASET寄存器调整:
void SetDisplayWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { WriteCommand(0x2A); // CASET WriteData(x1 >> 8); WriteData(x1 & 0xFF); WriteData(x2 >> 8); WriteData(x2 & 0xFF); WriteCommand(0x2B); // RASET WriteData(y1 >> 8); WriteData(y1 & 0xFF); WriteData(y2 >> 8); WriteData(y2 & 0xFF); }5.3 初始化序列优化
不同屏幕可能需要不同的初始化命令序列,以下是通用模板:
void ST7789_Init(void) { HardwareReset(); // 硬件复位 Delay(120); WriteCommand(0x11); // Sleep out Delay(120); WriteCommand(0x3A); // 颜色格式 WriteData(0x55); // 16位RGB565 WriteCommand(0x36); // 屏幕方向 WriteData(0x00); // 默认为竖屏 WriteCommand(0x21); // 开启反色 //WriteCommand(0x20); // 关闭反色 WriteCommand(0x29); // 开启显示 }调试技巧:用示波器抓取初始化过程中的CS和DC信号,确保每个命令的时序符合预期。遇到无法点亮的屏幕时,尝试注释掉部分初始化命令,逐步排查问题命令。