驱动IC使用CO5300。按照厂家所给接线图,基于esp32S3 按如下规则接线。
编号 | ESP32-S3 GPIO | 模块引脚名称 | 功能说明 | 分类 |
---|---|---|---|---|
1 | GPIO19 | LCD_RESET | LCD 复位 | LCD 控制 |
2 | GND | GND | 地线 | 电源 |
3 | GPIO20 | LCD_TE | 撕裂检测,可选 | LCD 控制 |
4 | GPIO21 | LCD_CS | LCD 片选 | QSPI |
5 | GPIO47 | SPI_CLK | QSPI 时钟 | QSPI |
6 | GPIO48 | SPI_SI01 | QSPI IO1 | QSPI |
7 | GPIO41 | SIOO (IO0) | QSPI IO0 | QSPI |
8 | GND | GND | 地线 | 电源 |
9 | — | NC | 无连接 | 无需连接 |
10 | — | NC | 无连接 | 无需连接 |
11 | 3.3V / 5V | VBAT | 主供电 | 电源 |
12 | 3.3V / 5V | VBAT | 主供电(同上) | 电源 |
13 | GND | GND | 地线 | 电源 |
14 | GND | GND | 地线 | 电源 |
15 | 3.3V | VDD | IO电压参考 | 电源 |
16 | 3.3V | TP_VDD | 触摸供电 | 电源 |
17 | GPIO35 | TP_INT | 触摸中断 | 触摸(I2C) |
18 | GPIO36 | TP_RST | 触摸复位 | 触摸(I2C) |
19 | GPIO37 | TP_SDA | 触摸数据线 | 触摸(I2C) |
20 | GPIO38 | TP_SCL | 触摸时钟线 | 触摸(I2C) |
21 | GND | GND | 地线 | 电源 |
22 | GPIO39 | SPI_SIO3 | QSPI IO3 | QSPI |
23 | GPIO40 | SPI_SI02 | QSPI IO2 | QSPI |
24 | 3.3V | VCI_EN | 电源使能,高电平有效 | 控制 |
厂家给的屏幕引脚定义如下:
按硬件接好线,然后进行驱动移植。 首先移植屏幕显示驱动。CO5300 屏幕所用到的是这款驱动IC。先阅读厂家给的代码。
QUAD SPI 接口中,命令/读写操作用的是 1 根线(串行),而 像素数据的写入用的是 4 根线(并行),能加快数据传输速度。
-
命令阶段:标准 SPI(MOSI)
-
像素数据阶段:切换为 QSPI 模式,使用 SIO0~SIO3
依据来源于数据手册这段话:
命令控制SPI,发送一字节函数
对于段中的这句话理解是:
SCL is driven from high to low then pulled back to high during the write cycle.
👉 SPI 的 SCL 时钟线(对应 ESP32 上的 SPI_CLK
):
-
写周期中,时钟信号从高 → 低 → 再回到高,用于时序控制
⚠️ 注意:这与标准 SPI 模式 0(CPOL=0, CPHA=0)相符,CO5300 SPI 时序为:上升沿采样(rising edge)。
了解了屏幕是如何写入数据后,我们现在看看SPI具体写入哪些数据。
QUAD SPI接口包含三种操作模式,标准SPI、双SPI和四SPI。这些模式的结构如下。
这里展示了如何从上电默认的一线spi 转换到其他模式。其中要RGB为什么会有两组命令,我猜想是为了区分和控制RGB888和RGB565。
使用流程举例(以 QSPI 为例)
MCU 上电后,默认使用标准 SPI
发送配置命令(如设置分辨率、偏压、帧率等)
发
0x38
命令 → 启用 QSPI 模式发
0x32
命令 → 通知屏幕:我要写图像数据了(QSPI,RGB888)开始通过
SIO0 ~ SIO3
发像素数据
那么我们看到厂家给的代码
在这里 0x02是什么意思呢?看到数据手册当中的这个表。
是控制或者像素点写入命令!为何代码中又又0x00呢,我猜想是占位符的作用。这个时候我们去看一下一线写入时序图。
可以看到发送0x02。但是上图还不能确定为什么要写0x00,看下图四线的就知道了,地址实际上是使用到1字节,前后两字节用作填充的。故而在SPI_SendData(i);前后各有一字节的0x00。
接着我们看一下QSPI 4-wire write 是如何实现的:
SCLK上升沿有效,地址是三字节。一个时钟周期并行发送4个bit。
我们接着看QSPI 4-wire 在代码中如何实现写的,看下图代码(这里由于代码比较长截图不方便我放在代码框中)。
//这个是四线spi的传输数据 高字节在前
void SPI_WriteData1(unsigned char i)
{
SPI_CLK=0;_nop_(); _nop_();
if(i&0x80) SPI_D3=1;
else SPI_D3=0;
if(i&0x40) SPI_D2=1;
else SPI_D2=0;
if(i&0x20) SPI_D1=1;
else SPI_D1=0;
if(i&0x10) SPI_DI=1;
else SPI_DI=0;
SPI_CLK=1;//_n
_nop_();_nop_();
SPI_CLK=0;_nop_(); _nop_();
if(i&0x08) SPI_D3=1;
else SPI_D3=0;
if(i&0x04) SPI_D2=1;
else SPI_D2=0;
if(i&0x02) SPI_D1=1;
else SPI_D1=0;
if(i&0x01) SPI_DI=1;
else SPI_DI=0;
SPI_CLK=1;_nop_();_nop_();
}
除了数据传输,后面我们来研究一下RGB数据是如何传输的,这个主要是图像数据传输。我们这里主要是去看RGB565,先看时序图。
0x32表示采用四线 ,0x2C/0x3C表示地址选择,地址阶段为 24 个时钟(= 3 字节)随后开始写像素数据。
0x12表示采用四线 ,地址阶段为 6个时钟(= 0.75 字节)随后开始写像素数据。
这里就有疑问了为什么会有两个写地址呢?原因如下:
0x32
是万能 QSPI 写命令,适用于所有图像传输;
0x12
是轻量快速命令,适用于小区域图像刷新。
二者写的是一样的像素格式(如 RGB565),只是地址阶段不同。
我们继续往下看,上面说的都是写命令,我们接着写读取命令,读取的时候是one-wire SIDO接口输出
通过这个我们可以读取到很多数据。后面在去学习如何读取屏幕数据。
我们先了解一下 TE(Tearing Effect) 这个信号引脚的相关知识。
这是指 屏幕在绘制一行像素前后,还会有短暂的“空白区域”,就是 HBP 和 HFP。这些区域不会显示内容,是给驱动 IC 做同步用的。
↓ 这一帧结了
┌───────────────┐
│ VBP 区域 │ ← 屏幕在这个阶段没有画图(可以安全更新)
│───────────────│
│ 图像有效区域 │ ← 一行一行地刷图
│───────────────│
│ VFP 区域 │
└───────────────┘
↑ 下一帧要开始了
消隐区内更新数据是“安全”的,避免图像撕裂。
这个芯片当中给了几种模式,那么我在这里就选取其中mode1。
在 TE 模式 1 下,输出的 TE 信号只包含**垂直同步(V-sync)和垂直消隐(V-Blanking)**信息。也就是说,这个信号只告诉你“我现在是不是在消隐期”。也就是:
-
tvdh(高电平):LCD 没有从帧缓存更新内容(处于消隐区)✅ ← 主机可以写数据
-
tvdl(低电平):LCD 正在从帧缓存更新内容(正在刷新)❌ ← 避免写入,防撕裂
其他模式后续再说。
←---------------- 水平方向 ----------------→
| HBP(水平后消隐) | 有效显示像素区 | HFP(水平前消隐) |
模式 | 含义 | 适合用途 |
---|---|---|
Mode 1 | 只含 V-Sync(整帧刷新区间) | 最基础的防撕裂,同步整帧 |
Mode 2 | 含 V + H 同步,行和帧都考虑 | 精细同步,适合高帧率动画 |
Mode 3 | 刷到第 N 行时输出 TE 脉冲(由寄存器设置) | 自定义同步点,精准控制刷新时机 |
有了上述知识后,我们开始学习CO5300的具体命令。下面这个图就是命令框图,但是是mipi接口
我们用到的是SPI,这个是读取0x3A这个寄存器中显示像素点格式。
这个是读取显示图像的格式。
为了更好的在ESP32上编写自己的驱动,需要了解一下esp32spi相关函数,这里具体举一下传输函数的例子。
spi_device_queue_trans这个相当于是中断,非阻塞,异步传输
spi_device_transmit这个相比下是中断,阻塞,同步传输