4. MCU与屏幕的接口匹配:SPI/QSPI/8080并口模式配置
花屏问题里,有一类特别隐蔽——就是MCU和屏幕之间的接口没对上。说白了,两边握手的方式不一样,数据传过去就乱了。我见过不少项目,代码逻辑查了三遍都没问题,最后发现是SPI的时钟极性配反了。
这一章,咱们就把接口匹配这件事彻底讲透。你搞清楚了,至少能排除一半的花屏原因。
4.1 三种主流接口:SPI、QSPI、8080并口
先看一张总览图,把三种接口的核心差异搞清楚。
4.2 SPI模式配置:CPOL和CPHA是花屏的隐形杀手
SPI接口有4种模式,由时钟极性(CPOL)和时钟相位(CPHA)决定。很多工程师在这里栽过跟头——包括我自己。
CPOL:空闲时时钟线的电平。
CPOL=0,空闲时低电平;CPOL=1,空闲时高电平。
CPHA:数据在哪个时钟沿被采样。
CPHA=0,第一个时钟沿采样;CPHA=1,第二个时钟沿采样。
| 模式 | CPOL | CPHA | 采样沿 | 常见屏幕驱动 |
|---|---|---|---|---|
| 模式0 | 0 | 0 | 上升沿 | ILI9341, ST7789, SSD1306 |
| 模式1 | 0 | 1 | 下降沿 | 部分老款驱动 |
| 模式2 | 1 | 0 | 下降沿 | 某些特殊传感器 |
| 模式3 | 1 | 1 | 上升沿 | 部分高速屏 |
核心原则:MCU的SPI模式必须和屏幕数据手册里写的一模一样。差一个沿,数据就全错了。
我的经验:ILI9341和ST7789这类主流小屏,90%都工作在模式0。我习惯先把模式0试一遍,不行再换模式3——这两个是最常见的。
4.3 实战:STM32 HAL库配置SPI
拿STM32举例,配置SPI的代码长这样。注意看CPOL和CPHA的赋值。
// SPI句柄初始化
SPI_HandleTypeDef hspi1;
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; // CPOL = 0
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspi1);
这里有个坑——SPI_POLARITY_LOW对应CPOL=0,SPI_PHASE_1EDGE对应CPHA=0。如果你配反了,屏幕能收到数据,但全是错的。花屏就来了。
我曾经踩过的坑:有一次我用的屏幕数据手册写的是“SPI mode 3”,但我习惯性配成了mode 0。结果屏幕能亮,能显示,但颜色完全不对——红色变成了蓝色,绿色变成了紫色。查了整整一天,最后用逻辑分析仪抓波形才发现,时钟沿差了半个周期。
4.4 QSPI配置:四线模式下的额外注意事项
QSPI比SPI多了3根数据线,速度更快,但配置也更讲究。
- 时钟频率:QSPI通常跑40~80 MHz,注意PCB走线长度,超过10cm就要考虑信号完整性。
- 采样模式:和SPI一样,CPOL/CPHA必须匹配。QSPI屏幕通常也工作在模式0。
- DDR模式:部分QSPI控制器支持双沿采样(DDR),时钟上升和下降都传数据。这个模式容易出问题,我建议新手先避开。
- IO引脚顺序:QSPI的IO0~IO3必须和屏幕一一对应,不能乱接。接反了数据就乱了。
// QSPI配置示例(STM32H7系列)
QSPI_HandleTypeDef hqspi;
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 2; // 分频系数
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = POSITION_VAL(0x800000); // 8MB
hqspi.Init.ChipSelectHighTime = 2;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0; // CPOL=0, CPHA=0
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
HAL_QSPI_Init(&hqspi);
我个人的习惯:QSPI初始化后,先发一个读ID的命令(0x9F),看看返回的数据对不对。如果读回来的ID和屏幕手册对不上,那肯定是配置有问题,别急着调LVGL。
4.5 8080并口模式:时序参数要抠细
8080并口是并行传输,速度最快,但时序参数也最多。主要关注这几个:
| 参数 | 含义 | 典型值 | 配错后果 |
|---|---|---|---|
| WR周期 | 写脉冲宽度 | 50~100 ns | 数据写不进去,花屏 |
| RD周期 | 读脉冲宽度 | 50~100 ns | 读回数据错误 |
| 数据建立时间 | 数据在WR上升沿前需稳定 | 10~20 ns | 数据采样错误 |
| 数据保持时间 | 数据在WR上升沿后需保持 | 5~10 ns | 数据丢失 |
| CS片选建立时间 | CS拉低到WR有效 | 10~20 ns | 片选未稳定就操作 |
这些参数在屏幕的数据手册里都有。你想想看,如果MCU的FSMC/FMC控制器配的时序比屏幕要求的快,数据还没稳定就被采样了——花屏就来了。
// STM32 FMC配置8080并口示例
FMC_NORSRAM_TimingTypeDef Timing;
Timing.AddressSetupTime = 3; // 地址建立时间
Timing.AddressHoldTime = 1; // 地址保持时间
Timing.DataSetupTime = 4; // 数据建立时间
Timing.BusTurnAroundDuration = 1;
Timing.CLKDivision = 0;
Timing.DataLatency = 0;
Timing.AccessMode = FMC_ACCESS_MODE_A;
HAL_SRAM_Init(&hsram1, &Timing, NULL);
注意:这些时序参数的单位是HCLK周期。如果你的HCLK是200 MHz,一个周期就是5 ns。配成3就是15 ns。一定要换算成实际时间,和屏幕手册对比。
4.6 排查流程:接口问题导致花屏的定位方法
如果你遇到花屏,怀疑是接口配置问题,按这个流程走:
- 确认接口类型:看屏幕数据手册,确认是SPI、QSPI还是8080。
- 核对CPOL/CPHA:SPI/QSPI的话,确认模式0/1/2/3。
- 检查时钟频率:降低分频系数,让SPI跑慢一点(比如1 MHz)。如果慢速下正常,说明是信号质量问题。
- 用逻辑分析仪抓波形:看SCLK、MOSI、CS的时序对不对。这是最直接的方法。
- 读屏幕ID:发读ID命令,看返回值是否匹配。不匹配就是配置错了。
- 检查接线:特别是QSPI的IO顺序和8080的数据线顺序。
一句话总结:接口匹配是屏幕正常工作的前提。CPOL/CPHA配错、时钟太快、时序参数不对——任何一个都能导致花屏。先确认接口配置,再调LVGL,能省下大量排查时间。