//TITLE:
// 漫谈LCD调试(一)
//AUTHOR:
// norains
//DATE:
// Friday 23-July-2008
//Environment:
// NONE
//========================================================================
对于嵌入式设备来说,在主芯片的输出格式固定的前提之下,调LCD也就是剩下初始化寄存器而已。而寄存器的初始化数值或代码,在相应的datasheet中已经写得非常详细,只要按部就班即可。也许有朋友可能觉得奇怪,既然LCD的初始化代码都是固定不变的,为何在出厂的时候不直接固化到LCD中呢?其实我们可以从另一个角度来看,初始化寄存器的数值充其量也就十几B,远远达不到1KB。如果仅仅为这几十B的数据而添加一个存储设备,无形中增加了成本。所以很多LCD在使用之前都需要初始化其寄存器。
在WINCE环境之下,初始化LCD其实很简单。无非是三步走:
1.找到合适添加初始化代码的地方。
2.将PIN作为GPIO。
3.写入寄存器数值。
也许这三步中的最大难点可能就是如何写寄存器。在进行这一步之前,我们必须要知道写寄存器的时序。
我们以Innolux PT035TN01 V.6为例,该LCD的写寄存器时序为(如图1):
首先说明的是,图中的SPENB,SPDA,SPCK分别是LCD的其中三个PIN。从图中我们可以看出,当SPENB为low时,数据开始有效;当SPCK为上升沿时,对SPDA开始进行采样。
对LCD的寄存器进行写操作,并不需要太复杂的协议。以本文所举的例子而言,只需要和SPENB,SPDA,SPCK连接的这三个CPU PIN能做为GPIO即可。剩下的,仅仅是代码如何组织而已。
对应时序图,代码的流程可以这样组织:
1.SPENB,SPDA,SPCK作为GPIO。
2.SPENB输出LOW
3.SPCK输出LOW
4.SPDA输出D15
5.SPCK输出HIGH
6.重复3~5,直到address输出完毕
7.SPCK输出LOW
8.SPDA输出HIGH,代表是要写入数据。
9.SPCK输出HIGH
10.SPCK输出LOW
11.SPDA输出任意数据,作为HI-Z
12.SPCK输出HIGH
13.SPCK输出LOW
14.SPDA输出D7
15.SPCK输出HIGH
16.重复13~15,直到DATA数据全部输出
17.SPENB输出HIGH
18.延迟
19.如果还要继续写LCD寄存器数值,重复1~18即可
对于这18个步骤,可以具现到该伪代码:
WriteRegister(unsigned char reg,unsigned short value)
{
//Enable the CS
GPIO_OUTPUT_LOW(LCDIF_SPCK);
GPIO_OUTPUT_LOW(LCDIF_SPDA);
GPIO_OUTPUT_LOW(LCDIF_SPENB);
DWORD dwMask = 0;
//Register Address
for(dwMask = 0x20; dwMask != 0; dwMask >>= 1)
{
GPIO_OUTPUT_LOW(LCDIF_SPCK);
if (reg & dwMask)
{
GPIO_OUTPUT_HIGH(LCDIF_SPDA);
}
else
{
GPIO_OUTPUT_LOW(LCDIF_SPDA);
}
GPIO_OUTPUT_HIGH(LCDIF_SPCK);
}
// W/R control bit
GPIO_OUTPUT_LOW(LCDIF_SPCK);
GPIO_OUTPUT_HIGH(LCDIF_SPDA);
GPIO_OUTPUT_HIGH(LCDIF_SPCK);
//Hi-Z bit
GPIO_OUTPUT_LOW(LCDIF_SPCK);
GPIO_OUTPUT_LOW(LCDIF_SPDA);
GPIO_OUTPUT_HIGH(LCDIF_SPCK);
//Data for the W/R operation to the address indicate by Address phase
for(dwMask = 0x80; dwMask != 0; dwMask >>= 1)
{
GPIO_OUTPUT_LOW(LCDIF_SPCK);
if (value & dwMask)
{
GPIO_OUTPUT_HIGH(LCDIF_SPDA);
}
else
{
GPIO_OUTPUT_LOW(LCDIF_SPDA);
}
GPIO_OUTPUT_HIGH(LCDIF_SPCK);
}
//Disable the CS
GPIO_OUTPUT_LOW(LCDIF_SPCK);
GPIO_OUTPUT_HIGH(LCDIF_SPENB);
//Delay
Sleep(10);
}