理解LCD屏幕的驱动原理与调试过程,示例的驱动IC为GC9308,展示整个屏幕的驱动过程。

更新时间:2023-07-08 05:57:50 阅读: 评论:0

理解LCD屏幕的驱动原理与调试过程,⽰例的驱动IC为GC9308,展⽰整个屏幕的驱动
过程。
起因
最近拿到了⼀个⽐较新的驱动 IC 的 LCD 了,此前 K210 上⾯使⽤的都是 ST7789V ILI9342C SH1106 这类驱动 IC 的屏幕模块。
这次来了⼀个 GC9308 ,我想我需要认识⼀下屏幕驱动的整体架构,也就是拿起数据⼿册当作学习教材来学了,实际上学完以后,懂了以后都不难,重点在如何总结这些屏幕的驱动逻辑,以此打下往后的屏幕驱动理解基础。
我需要读懂图像的⼆进制定义、还有传输⽅式,我找了⼀本中⽂的屏幕数据⼿册来读,了解⼀下相关的流程和细节
本⽂我只会交待软件层⾯的理解,硬件⽅⾯的定义和特性我⽆法给出准确的解释,姑不会提及。
屏幕的发展历程
让我们看⼀下这个⼤哥的故事,就很好的说明了这段 LCD MCU 发展的历史。
记得在很早的时候,那时候还都是FSTN的显⽰屏满天飞的时候(也是⼩弟刚刚毕业开始作⼿机的时候)。LCD的驱动电路有很多是两⽚芯⽚的,⼀⽚LCDC,⼀⽚LCD Driver,⼀般的LCDC⾥⾯有⼀个display的buffer。LCDDriver是电路驱动液晶显⽰部分的电路,没有什么好讲的。更早的时候,LCD上就⼀⽚LCDDriver就⾏了,程序员需要控制两个(H,V)场扫描信号,⽽且程序员希望在某个坐标显⽰,都需要编程控制驱动电路来实现,后来发现显⽰屏越来越⼤,⽽MCU以及程序员没有这个能⼒和精⼒来对LCD进⾏这类的同步控制,于是LCDC就诞⽣出来承担起这些个功能。后来加上了buffer,就是说程序员可以把⼤批的显⽰内容以显⽰矩阵(display matrix)的形式写到buffer⾥,让LCDC来读取buffer⾥的数据再由LCDDriver显⽰到显⽰屏上。后来这个buffer越来越⼤,除了显⽰矩阵以外还放很多命令,所以也不能⽼把它笼统的叫buffer啊,所以就对放显⽰矩阵的存储空间有了⼀个专⽤的名字叫做GRAM。到现在嘛,这些驱动/控制电路以及buffer都合起来放在⼀⽚芯⽚中,统称为driver IC啦。也就是LCM上那颗COG的芯⽚,相信看这⽚回帖的兄弟们都看到过。⽽且这颗driver IC的功能越来越nb,有什么dimm功能啊,gamma功能啊,什么省电啊等等乱七⼋糟的功能,不过⼤多功能程序员都不需要去详细了解,现在的程序员都很轻松啦,只需要⽤很简单的⼏条命令就可以控制这颗driver IC来驱动LCD。
更多的内容可以⾃⼰去跳转阅读。
如何理解现在的 LCD 屏幕的驱动架构
因为我是在学习和整理过后进⾏消化的知识,所以我会对我所掌握的内容做⼀个重新编排,我认为理解⼀个模块或事物,应当从它的 本质架构 或 程序设计 上去理解它,这样的理解会存在⼀个同类事物的共性,如屏幕的驱动共性。
以往供应商给到我的数据⼿册全是英⽂的,这个确实影响到了我对屏幕的认知,⼀⽅⾯是英⽂的翻译和中⽂的专业术语不对称,存在理解误差。另⼀⽅⾯是英⽂的描述在初学阶段并不能驻留在脑⼦⾥,如果是为了效率学习,母语的学习效率将会极⾼,因为专业术语有铺垫,所以我找了⼀本中⽂的屏幕数据⼿册来作为原始的基础学习的材料。
想要进⼀步的理解复杂功能,必然要先建⽴⼀个基础知识体系,让⼀个从来没有开发过屏幕驱动,只会调调代码的朋友去开发⼀款全新的 LCD 驱动代码,例如对接⼀款全新的 LCD 屏幕,通过 MCU 接⼝驱动⼀款 8bit 数据总线 16bit 颜⾊的 LCD 屏幕,并同步⽀持 GUI 的基础绘图操作,从初始化到绘图显⽰图像等功能实现,那么要如何去解决这个问题呢?
也许你和我⼀样是个软件⼯程的开发者,知道去使⽤类似的 code 来复现驱动逻辑,但你未必知道你所⽤的硬件之中的定义,对应的功能⼜是哪些,你如果不了解你的驱动芯⽚,你⼜该如何写它呢?也许逻辑是对的,但是对这款芯⽚也⼀样适⽤吗?
这也是我最初的困惑,在我没有深⼊学习之前,我是可以通过抄代码逻辑来完成对⼀款屏幕的驱动,漫画小女孩
卡通性感美女然⽽现在我拿到的是⽹络上连代码都没有的 IC ,就有那么⼀些迷茫,现在我把这些学习和理解的过程记录下来,给未来可能出现同样问题的你,建⽴⼀个容易理解的体系概念。
为了确保⾃⼰提供的内容是准确且符合客观事实的,所有讯息的参考依据都是来源于数据⼿册,这意味着数据⼿册就是我们最好的学习材料 XD 。
LCD 屏幕的初始化流程
按道理来说,任何⼀个屏幕都应该在这⾥完成对屏幕的初始化,产⽣雪花屏的效果,不然后⾯的内容都可以不⽤做了,但这⾥的内容我打算是放到最后的实践章节来讲的,所以放⼀张图占位就好了嘻嘻。
所谓的雪花屏就是背后那些密密⿇⿇的的⽩⾊⾊块,这表⽰ LCD 屏幕初始化完毕。
LCD 屏幕的体系架构
我认为先基础理解这个是重中之重,关于这个结构的问题,在我看的这么 5 本屏幕数据⼿册之中来看,体系架构是在进化的,但本质是不变的,所以可以放⼼的去获取⾃⼰所需要的部分。
整体的架构框图(Block diagram)
现在我们很少会直接去使⽤这⾥⾯的内容了,因为所谓的屏幕供应商⼚家会根据你的屏幕接⼝定制你所需要的线序,减少我⽅驱动开发⼈员的对驱动硬件层⾯的理解,从⽽让软件开发⼈员只需要关注写图像数据这件事情。
像我们必然会确认的⼏个关键信息,如这图的 A0(DC) \ IM0:2 \ WR \ RES \ D0:7 等引脚资源,基本就可以判断出这个 lcd 的⽀持层次和范围,还可以进⼀步判断 它的 Display
Data Ram 的信息,但事实上,知道还是不知道都不影响我们对它的驱动,只是帮助我们快速感知这个屏幕的架构情况,所以知道了部分就可以继续往下看了。
显⽰内存(DDRAM)的线路地址映射关系
关于显⽰内存,有的数据⼿册可能会称为 Graphics RAM (GRAM),但⼤体意思是不变的,为避免误解我附个图。
虽然说法都有点不太⼀样,但这并不影响我们对它的理解,它实际上的⽤途就是⼀块⽤于显⽰的内存,它代表了 驱动 IC 的会通过读取它的数据进⾏屏幕的扫描显⽰,⽽我们要做的就是对它写⼊显⽰的数据和对应的⾏列起始地址(address),有得会称为⾏计、列数器(counter),其实效果如下图。
如何设置显⽰的内容呢?这就要看懂它的 DDRAM 的地址关系,将数据写⼊到对应的 DDRAM 中就可
以做到了(驱动 IC 会从中读取数据显⽰到屏幕的这个过程),所以我们必然要理解这个内容,它的结构图如下。
⾄此可以理解的是,驱动 IC 的⼯作内容,接着我们深⼊理解⼀下 DDRAM 的线路地址,关于它的寻址⽅式。
这是⼀张很形象的 SH1106 的地址寻址图,关于图像的存储⽅式和⾏列寻址⽅式,我现在来解释⼀下上⾯这张图想要表达的意思。
⾸先我们知道这是单⾊的 LCD 屏幕,所以看到的图像中标记的红线表⽰每⼀次传输的 D0:7 列数据(colum address),显⽰出来就是对应的图像像素点(1 bit),有得⼜会叫列计数器,实际上都是指这个列数据的索引数据,同样的还有⾏数据(line address),那么我们继续理解它的 页⾯地址(page) 这个实际上是可以这样形象的理解的。
如果不做出说明和讲解的话,这些张图可能很难让⼈理解,不妨想象⼀下屏幕就是⼀款打印机,它想要显⽰数据就需要打印⼀张纸(page)出来,打印的纸张将根据起始的⾏地址来按⾏打印每⾏的⼀列数据,这样最后打印出来的内容就是屏幕所显⽰的数据拉,不妨结合下图来感受和理解这个存储结构。
它实际上就是想说明下述效果。
现在你是否能够理解了呢?如果理解了,你再看看这张图,是不是就能理解了呢?(页⾯地址并不是每款都会去设计的,因为不⼀定需要多级缓存,通常双缓冲⾜以)
那么理解了这个对我们有什么意义呢?⾄少你现在应该知道如何控制代码去给这些驱动 IC 设置想要显⽰的数据了,它们基本都是相通的,不⾜为奇。
LCD 屏幕的数据总线接⼝类型
既然我们知道应该如何去设置显⽰内存了,那么就得看看我们应该如何连接我们的 LCD 驱动 IC 了。
数据总线这个⽤词是来源于微机原理,其实就是⼀堆⽤于传输数据的数据线,指都有哪些通信⼿段,或者说传输接⼝。
⾸先确认 im 的配置,这个配置通常由硬件上的接线决定,如下图我们得知。
只有先确认了我们的连接的配置才会进⼀步的配置寄存器、写⼊显⽰数据,同样的也要进⼀步确认我们的 Data 是 8-bit 还是 9-bit,这会再下⾯做出说明。
MCU
MCU接⼝标准名称是 I80 ,因为主要针对单⽚机的领域在使⽤,因此得名。后在中低端⼿机⼤量使⽤,其主要特点是价格便宜的。MCU-LCD接⼝的标准术语是 Intel 提出的 8080 总线标准,因此在很多⽂档中⽤ I80 来指 MCU-LCD 屏。
MUC接⼝主要⼜可以分为 8080 模式和 6800 模式,这两者之间主要是时序的区别;数据位传输有 8 位, 9 位, 16 位, 18 位, 24 位; 连线分为:CS/,RS(寄存器选
择),RD/,WR/,再就是数据线了。
优点是:控制简单⽅便,⽆需时钟和同步信号。缺点是:要耗费 GRAM ,所以难以做到⼤屏(3.8⼨以上)。对于 MCU 接⼝的 LCM ,其内部的芯⽚就叫 LCD 驱动器。主要功能是对主机发过的数据/命令,进⾏变换,变成每个象素的RGB数据,使之在屏上显⽰出来。这个过程不需要点、⾏、帧时钟。
I(intel)8080模式
CS ⽚选信号
RS (D/I 数据/指令选择线, 置1为写数据, 置0为写命令)
/WR (为0表⽰写数据)
/RD (为0表⽰读数据)
RESET 复位LCD(⽤固定命令系列 0 1 0来复位)
M(Motorola) 6800 模式
M6800模式⽀持可选择的总线宽度 8/9/16/18-bit (默认为8位),其实际设计思想是与 I80 的思想是⼀样的,主要区别就是该模式的总线控制读写信号组合在⼀个引脚上
人生格言简短
(/WR),⽽增加了⼀个锁存信号(E)数据位传输有8位,9位,16位和18位。
事实上关于这种我们可以直接在数据⼿册中的时序图得到理解,它们⼀般也会⼀起提供对应的 timing 或者 pau ,翻译过来都是时序的意思,后者有时序⽚段的意思。
可以看出它有⼀根 DC 脚,如果有这个脚则意味着,在代码上要通过控制这个引脚来完成本次传输的数据是 命令 Command 还是 数据 Data 了,⽽所谓的 9-bit 就是指这个省略了这个引脚,在数据 D0:7 部分改成了 D0:8 ,其中第⼀个数据⽤做命令和数据的标识区分,如下图所⽰。
也就是说,它的主体逻辑其实很简单,就 RST 控制硬件复位、DC 引脚只要能区分数据就⾏,可有可⽆(如 9-bit 不需要),接着是 WR ⽤于提⽰该发送 D0:X 的数据了,以及 RD 提醒 IC 可以发数据过来给我接收了。
剩下的⽆⾮就是具体问题具体分析,遇到问题仔细对时序就好了,例如下图这样。
这并不难理解,让我们继续。
SPI
在这之前我⼀直认为 SPI 就是指 摩托罗拉公司推出的标准 SPI 协议,标准的 CS \ MOSI \ MISO \ CLK 四个引脚,但后来才知道有如下拓展 SPI 接⼝。
但其实最重要的是 SPI 的翻译为 spi rialport interface 接⼝,意味着就是串⾏数据通信的⽅式,这与 Parallel Interface 是 并⾏接⼝ 相对,这在下⾯的说明就会体现出来了。
4 线串⾏接⼝( 4 线 SPI)
串⾏接⼝由串⾏时钟 SCL,串⾏数据 SI,A0 和CS 组成。在 SCL 的每个上升沿按照 D7,D6,......和 D0 的顺序将 SI 移⼊ 8 位移位寄存器。每隔 8 个时钟对 A0 进⾏采样,并将移位寄存器中的数据字节同⼀时钟写⼊显⽰数据 RAM (A0 = 1)或命令寄存器( A0 = 0)。
3 线串⾏接⼝( 3 线 SPI)
西游记精彩片段
3 线串⾏接⼝由串⾏时钟 SCL,串⾏数据 SI 和CS 组成。在 SCL 的每个上升沿按照 D/ C ,D7,D6,......和 D0 的顺序将 SI 移⼊ 9 位移位寄存器。 D/ C 位(9 位中的第⼀位)将确定传输的数据被写⼊显⽰数据 RAM (D/ C = 1)或命令寄存器( D/ C = 0)。
不难看出,它和 8-bit 与 9-bit 的区别有异曲同⼯之妙,但为什么它叫 SPI 呢,实际上这是与并⾏相对的地⽅,⽐如将 D0:7 的数据压缩到了⼀条 SI 通道中传输了。
I2C
I2C 并不是每个屏幕都会⽀持,因为它接⼝简单,速度不快,所以只会出现在⼀下微⼩的屏幕上,但不同的是,它要通过硬件来标记从机产⽣的地址。
拿 SH1106 为例来说,它⽀持读写访问。 R/ W 位是从机地址的⼀部分。 在 I2C 总线上传输任何数据之前, 应⾸先寻址应响应的设备。 SH1106 保留两个 7 位从地址(0111100 和 0111101 )。通过将输⼊ SA0 连接到逻辑 0(VSS)或 1(VDD1)来设置从地址的最低有效位。
⾄今位置的接⼝传输的数据基本都没有太⼤的区别,都是传输像素点的颜⾊数据。
RGB
现在就说点不同的屏幕接⼝,通常 RGB 接⼝结构,区别有下述。医疗期工资
对于RGB接⼝的LCM,主机输出的直接是每个象素的RGB数据,不需要进⾏变换(GAMMA校正等除外),对于这种接⼝,需要在主机部分有个LCD控制器,以产⽣RGB数据和点、⾏、帧同步信号。
也就是说,传统的MCU屏显⽰数据写⼊DDRAM,⽽RGB屏数据不写⼊DDRAM,直接写屏,读写速度更快。
VSYNC 模式:
该模式其实就是就是在MCU模式上加了⼀个VSYNC信号,应⽤于运动画⾯更新,这样就与上述两个接⼝有很⼤的区别。该模式⽀持直接进⾏动画显⽰的功能,它提供了⼀个对MCU 接⼝最⼩的改动,实现动画显⽰的解决⽅案。在这种模式下,内部的显⽰操作与外部VSYNC信号同步。可以实现⽐内部操作更⾼的速率的动画显⽰。但由于其操作⽅式的不同,该模式对速率有⼀个限制,那就是对内部SRAM的写速率⼀定要⼤于显⽰读内部SRAM的速率。
通常我们在 LCD 数据⼿册中看到的多数指这种 VSYNC 模式,了解它的⼯作机制也是⼀样通过看数据⼿册才能得知,如下图所⽰。
在理解上图之前,需要确定下述两个概念。
垂直同步脉冲(Vertical synchronization, Vsync)是加在两帧之间。跟⽔平同步脉冲类似,但它指⽰
着前⼀帧的结束,和新⼀帧的开始。 垂直同步脉冲是⼀个持续时间⽐较长的脉冲。
⽔平同步脉冲(Horizontal synchronization pul, Hsync)加在两个扫描⾏之间。它是⼀个短⼩的脉冲,在⼀⾏扫描完成之后,它就会出现,指⽰着这⼀⾏扫描完成,同时它也指⽰着下⼀⾏将要开始。
然后我附图说明这个关系。
但是很可惜的是,这⾥我⽆法解释的更为细致的原因了,想知道更多的,只能请你⾃⼰去查阅 ILI9342C 数据⼿册的 VSYNC Interface ⼀章中对时序的计算和屏幕的扫描⽅式,要特别注意 Back porch (2 lines) 和 Front porch (2 lines) 的⽤途。
VSYNC Interface 的 RGB 接⼝要看懂还挺难的,我看了⼀点就懵逼了,还有公式换算,应该是期望在 VSYNC 同步触发前应当把 帧 数据写⼊屏幕,原谅我没有真正的实践这个,只能理解到这⾥了。
LCD 屏幕的像素点与颜⾊值定义的关系
如果你已经得知如何去确认通信接⼝和模式,那么就要确认的就是通信的数据格式了,通常我们的通信的总线通道(D0:7)并没有那么宽,但我们也⼀样可以传输更多的数据,这就需要去看数据⼿册的数据定义了,它很贴⼼的把 RGB 颜⾊的范围定义通过颜⾊表⽰出来了。
实际上我们传输的数据假设为⼀个 16bit 的变量,则如下图还原,其他同理。
其实我们通常使⽤的 16-bit 的 color 值就是指 RGB16 的意思。
RGB16
所以这段魔幻代码的操作你就知道为什么了。
//获取⾼字节的5个bit
R = color & 0xF800;
//获取中间6个bit
G = color & 0x07E0;
//获取低字节5个bit
B = color & 0x001F;
RGB32
关于 BGR 的问题
是 RGB 还是 BGR 这个问题还是历史遗留因素,那如果真的发现颜⾊值不对的时候,应当检查寄存器的配置,确认颜⾊模式。
因为这个屏幕考虑到早期的代码因素,所以才会存在这种差异性,这也意味着我们后来写的代码,还是得分清楚,是 RGB 还是 BGR。
⾄此你已经知道了,屏幕通信过程中的颜⾊值情况,也就明⽩了如何应该如何传输像素点的颜⾊值,剩下的就是如何传输的功能问题了。
LCD 屏幕的初始化流程
这个不同屏幕有不同的初始化流程,但都有⼀个标准和⼤概的范围,也和硬件有关,有时候还不如不接,让屏幕⾃⾏进⼊初始化?(迷惑
我分别截图⼏个⼿册的情况和举实例吧。
其实不难,主要是硬件⽅⾯设计好就可以了。
关于 I8080 传输数据的细节
需要注意的是,这个传输数据对时序的要求还挺⾼的。
LCD 屏幕绘图接⼝的主体逻辑
设置填充的区域
设置⼀下⾏地址和列地址的起始位置和停⽌位置。
void lcd_t_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
uint8_t data[4] = {0};
x1 += lcd_ctl.start_offt_w;
x2 += lcd_ctl.start_offt_w;
y1 += lcd_ctl.start_offt_h;
y2 += lcd_ctl.start_offt_h;
data[0] = (uint8_t)(x1 >> 8);
data[1] = (uint8_t)(x1);
data[2] = (uint8_t)(x2 >> 8);
data[3] = (uint8_t)(x2);
闺蜜tft_write_command(HORIZONTAL_ADDRESS_SET);
tft_write_byte(data, 4);
data[0] = (uint8_t)(y1 >> 8);
data[1] = (uint8_t)(y1);
data[2] = (uint8_t)(y2 >> 8);
data[3] = (uint8_t)(y2);
tft_write_command(VERTICAL_ADDRESS_SET);
tft_write_byte(data, 4);
tft_write_command(MEMORY_WRITE);
}
填充内容的⽅式
如果是 fill 的操作的话,将持续发送该颜⾊填充到指定的区域即可。
void lcd_fill_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
if((x1 == x2) || (y1 == y2))
return;
uint32_t data = ((uint32_t)color << 16) | (uint32_t)color;
lcd_t_area(x1, y1, x2-1, y2-1);
tft_fill_data(&data, (x2 - x1) * (y2 - y1) / 2);
浩浩荡荡
}
如果是 draw 的操作的话,将缓冲区中的颜⾊数据持续的到指定的区域即可完成数据的显⽰。
杨柳飘絮
void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr)
{
lcd_t_area(x1, y1, x1 + width - 1, y1 + height - 1);
tft_write_word(ptr, width * height / 2);
}
GC9308 调试⽰例与后记
补充说明,后来的 LCD 屏幕都多了⼀个叫 LUT 的映射表,实际上就是⼀个 16-bit to 18-bit color depth conversion 的转换函数。
软件⽅⾯⽐较⿇烦的地⽅在于 SPI 的通信模式、像素点的颜⾊值转换、驱动的基础颜⾊定义、驱动的寄存器配置,基本上确认了这些⼤多数问题都可以解决。硬件⽅⾯设计有缺陷,个⼈判断应该是功耗
不⾜,屏幕闪⽩线或起雾,看起来就好像要断电熄灭了⼀样。
唯⼀不满意的地⽅就是没有办法量出 K210 输出 并⼝数据 的信号,因为没有转接板可以接出来,这令我⼗分苦恼。

本文发布于:2023-07-08 05:57:50,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1084966.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数据   屏幕   驱动   理解   需要   传输   知道   硬件
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图