菜鸟学习笔记——lcd底层驱动总结 - Tech盐

时间:2024-04-14 21:50:42

菜鸟学习笔记——lcd底层驱动总结

几种较常用的LCD控制器接口:
    Full bus interface
    simple bus interface
    4 pin SPI interface
    3 pin SPI interface
    I2C bus interface
 
 
这里我们使用的是full bus 的接口
 
接口原理的示意图如下
 
 
从lcd的角度看就是这些信号,其实就相当于8080总线或者6800总线(关于6800总线和8080总线的区别请看这里http://floatingstars.blog.163.com/blog/static/18517516120133289450594/)
 
以ILI9341为例,其使用8080总线接口,其基本Control signals如下:
    1.片选CSX信号;
    2.写诗能WRX信号:
    3.读使能RDX信号;
    4.区分数据命令的D/CX信号;
    5.复位RESX信号。
            Tips:带X表示低电平有效
 
8080总线时序图如下:
 
 
对于初次接触这种总线的同学来说,可能不太理解,这里简单说明一下。看到WRX信号线第一个小箭头垂直方向其他信号状态,CSX低电平表示选中这个器件,数据的读写有效;D/CX为低电平,说明写入的是命令地址(下一个WRX箭头时,为高电平,说明写入的是数据);对于RDX而言,因为是写入操作,所以置高就可以了。
 
如果是用MCU,通过GPIO口可以模拟上边的时序操作,但是会比较麻烦,而且,由于这种总线速度很快,时序上面要非常小心才能保证不出问题,如果要尝试的话,一定要参考所用mcu关于gpio接口的时序说明,对应目标器件的时序说明,程序执行的周期等等。
 
以stm32为例,一般的做法是将LCD挂载到芯片外设FSMC(Flex Static Memory Controller,静态存储控制器)上,这样,时序方面的问题就都交给芯片去完成了,对于开发而言,真的是爽翻天      =。=||
 
说句题外话,现在像stm32芯片的开发,很多同学都直接学的基于库函数开发,这种方法的确非常好,简单高效不容易出错,不过这个样子可能对硬件底层的一些东西理解起来就比较困难了,个人觉得还是有必要拿出handbook仔细看一遍关于FSMC的章节,最好的话,甚至应该玩玩FPGA,然后尝试用verilog写一个LCD的驱动接口,实现的功能不用太复杂,只要能成功看到现象,就会对硬件底层的那些时序啊(建立时间保持时间,边沿有效之类等等)有个概念上的飞跃。
 
 
 
如果理解了如何在物理层面是如何驱动lcd的,那么软件层面上,你只需要把各种类型的操作划分为几个不同的宏,就可以轻松控制lcd了
 
 
 
 
举个例子,
  
    int a = 1;  
 
大家知道计算机在保存这个a的是这样一个操作,给a一个内存地址(eg:0x60000000)然后把a的值0x1保存到对应的内存地址中,现在结合一下之前那个8080的时序图再理解一下这个操作;现在,假如我想在lcd上实现某个功能,根据lcd的datasheet这个功能需要对0x60000000地址的寄存器写入0x1这个值,相当于只要定义好这个操作的地址    #define lcd_wr_1 (u32)0x60000000)    然后 来一句  (*(__IO u16 *)(lcd_wr_1)) = ((u16)(1)),就可以完成这个操作了,非常容易。  如果第一次看到这个指针操作,可能不太理解,其实很容易,括号里面(__IO u16 *)的作用相当于把0x60000000这个值转换成一个16位的地址,然后外面的*表示对这个地址采取指针运算,相当于往这个地址里放数据类型为u16的1这个值,如果这个地址映射到了外存储区,芯片上的FSMC外设会自动帮你转换成一次如之前时序图上的那样的一个操作,lcd就被驱动起来了。    (关于u32的说明,因为stm32是32位处理器,所以地址值的大小以32位数据保存;关于u16的说明,FSMC接口与lcd链接的数据线采用16线,相当于一次可写入的数据为16位;关于__IO的说明,__IO 是volatile的宏定义,表示这个地址的存放的内容是易变的,防止编译器编译的时候为了优化把有些操作优化掉
 
 
 
所以mcu(stm32)上对lcd的驱动流程大致就是:
    把lcd连接到对应接口----->配置fsmc------>定义好各个操作的寄存器地址------->把读写操作封装起来(例如#define WR_Data(value)  (*(__IO u16 *)(lcd_wr_1)) = ((u16)(value))  )  ------>根据lcd的datasheet封装好各个操作
 
就是这么简单,不辜负哦具体配置的时候还是有很多问题需要多加考虑的,这里不再详述,只是想把大致原理概括一下   ^~^