因为之前的显示屏2013年11月份要停产,信利提供对应的替代品为TDA-QVGA0320A60411,所以就需要在之前支持三种屏的支持上,再增加对TDA-QVGA0320A60411的支持。
1. TDA-QVGA0320A60411概述
TDA-QVGA0320A60411显示屏厂家提供的接口图如下:
图1
此显示屏采用的驱动IC: HX8347-I,先来介绍HX8347-I的一些重要知识点。
1.1 HX8347-I支持的接口组
支持Command-Parameter接口和Register-Content接口,此两种接口由IFSEL信号脚来决定,如下图所示:
图2
由此可见HX8347-I默认选择Register-Content接口组。
1.2 HX8347-I支持的系统接口
在Register-Content接口组模式下,HX8347-I有一个用于command/GRAM数据传输的系统接口(system interface)电路和一个在动画显示时用于显示数据传输的RGB接口电路。
⑴系统接口
系统接口能够访问内部命令和内部18-bit/pixel的GRAM,HX8347-I的系统接口支持用于18-/16-/9-/8位总线宽度的并行总结接口,这就是I80接口。如下图所示:
图3
一般情况下显示屏数据手册中会说明IM[3:0]的值,这里选择是0010(因为接口有限,显示屏厂家根据客户的设计来选择对应的值,然后封装好),也就是I80 MCU16位并行接口。上图也表达了这样的信息:
①CPU引出的数据线低八位VD[7:0]连接到D[8:1],数据线的高八位VD[15:8]连接到D[17:10]
②CPU通过D[8:1]把初始化数据写入到HX8347-I寄存器中,通过D[17:10]和D[8:1]把显示数据写入到GRAM中。
图4
⑵RGB接口
RGB接口只能访问显示数据,所在在RGB接口模式下,输入的显示数据不能写到GRAM,而是直接显示。显示屏厂家可以基于HX8347-I封装为RGB接口来给客户使用。
1.3
2. 系统兼容TDA-QVGA0320A60411的思路及实现
可以通过读取HX8347-I的ID code来区分,ID code可以通过读取R00h寄存器读取出来,见下图:
图5
由上图可知HX8347-I的ID code值为0x95。
2.1 HX8347-I并行总线系统接口操作
图6
我们CPU显示控制器采用的是I80来连接显示屏的系统接口,此情况下NWR_SCL、NRD和DNC_SCL主要用于:
⑴NWR_SCL:I80并行总线系统接口写使能引脚,低电平有效。
⑵NRD:I80并行总线系统接口读使能引脚,低电平有效。
⑶DNC-SCL:连接到显示屏引脚的RS,作为数据/命令选择脚。
还有一个很重要的引脚NCS
⑷NCS:当NCS为低电平时,HX8347-I的并行和串行总线系统接口有效,此时接口电路的数据传输有效,也就是说要进行数据传输(比如写寄存器或是显示画面时),一定要让NCS为低电平。
RS---Data/commandselect
It has an Index Register (IR) inHX8347-I to store index data of internal control
register and GRAM. Therefore, the IRcan be written with the index pointer of the control register through data busby setting DNC_SCL=0. Then the command or GRAM data can be written to registerat which that index pointer pointed by setting DNC_SCL=1.
2.2 IR寄存器
HX8347-I的IR(Index Register)寄存器用于保存内部控制寄存器和GRAM寄存器的索引数据。那么,在DNC_SCL=0时,软件通过数据总线可以把控制寄存器索引指针写入到IR中。紧接着,命令或GRAM数据在DNC_SCL=1时被写入到索引指针指向的寄存器中。寄存器读写时序图如下:
图7
2.3 读取HX8347-I的ID code
根据图7的时序图,可以总结出读取ID code的流程图如下:
图8
对应于代码中的实现如下:
UINT32 HX8347_SSD1289_Readreg(UINT32 addr)
{
UINT32 data = 0;
s2450LCD->SIFCCON0 |= (1<<8); // nCS0(Main) enable
s2450LCD->SIFCCON0 |= (1<<0); // command mode enable
s2450LCD->SIFCCON0 &= ~(1<<1); // RS low
s2450LCD->SIFCCON0 |= (1<<6); // nWR enable
s2450LCD->SIFCCON1 = addr;
s2450LCD->SIFCCON0 &= ~(1<<6); // nWR disable
s2450LCD->SIFCCON0 |= (1<<1); // RS high
s2450LCD->SIFCCON0 |= (1<<7); // nRD enable
data = s2450LCD->SIFCCON2;
s2450LCD->SIFCCON0 &= ~(1<<7); // nRD disable
s2450LCD->SIFCCON0 &= ~(1<<0); // command mode disable
s2450LCD->SIFCCON0 &= ~(1<<8); // nCS0(Main) disable
return data;
}
读取ID code:
HX8347_SSD1289_Readreg(0x00)
2.4 初始化HX8347-I寄存器
根据显示屏厂家提供的初始化代码,修改后的代码如下:
void LDI_CtrlWrite(UINT32 addr)
{
s2450LCD->SIFCCON0 |= (1<<8); // nCS0(Main) enable
s2450LCD->SIFCCON0 |= (1<<0); // command mode enable
s2450LCD->SIFCCON0 &= ~(1<<1); // RS low
// delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON0 |= (1<<6); // nWR enable
// delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON1 = addr;
// delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON0 &= ~(1<<6); // nWR disable
// delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON0 &= ~(1<<0); // command mode disable
s2450LCD->SIFCCON0 &= ~(1<<8); // nCS0(Main) disable
}
void LDI_DataWrite(UINT32 data)
{
s2450LCD->SIFCCON0 |= (1<<8); // nCS0(Main) enable
s2450LCD->SIFCCON0 |= (1<<0); // command mode enable
s2450LCD->SIFCCON0 |= (1<<1); // RS high
//delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON0 |= (1<<6); // nWR enable
// delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON1 = data;
// delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON0 &= ~(1<<6); // nWR disable
//delayLoop(LCD_DELAY_1MS/10);
s2450LCD->SIFCCON0 &= ~(1<<0); // command mode disable
s2450LCD->SIFCCON0 &= ~(1<<8); // nCS0(Main) disable
}
void InitLDI_I80_HX8347I_TFT5K0418(void)
{
RETAILMSG(1, (TEXT("eboot--->InitLDI_I80_HX8347I_TFT5K0418() \r\n")));
LDI_CtrlWrite(0x00EA);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x00EB);LDI_DataWrite(0x0020);
LDI_CtrlWrite(0x00EC);LDI_DataWrite(0x000C);
LDI_CtrlWrite(0x00ED);LDI_DataWrite(0x00C4);
LDI_CtrlWrite(0x00E8);LDI_DataWrite(0x0040);
LDI_CtrlWrite(0x00E9);LDI_DataWrite(0x0038);
LDI_CtrlWrite(0x00F1);LDI_DataWrite(0x0001);
LDI_CtrlWrite(0x00F2);LDI_DataWrite(0x0010);
LDI_CtrlWrite(0x0027);LDI_DataWrite(0x00A3);
LDI_CtrlWrite(0x40);LDI_DataWrite(0x01); //
LDI_CtrlWrite(0x41);LDI_DataWrite(0x00); //
LDI_CtrlWrite(0x42);LDI_DataWrite(0x00); //
LDI_CtrlWrite(0x43);LDI_DataWrite(0x10); //
LDI_CtrlWrite(0x44);LDI_DataWrite(0x0E); //
LDI_CtrlWrite(0x45);LDI_DataWrite(0x24); //
LDI_CtrlWrite(0x46);LDI_DataWrite(0x04); //
LDI_CtrlWrite(0x47);LDI_DataWrite(0x50); //
LDI_CtrlWrite(0x48);LDI_DataWrite(0x02); //
LDI_CtrlWrite(0x49);LDI_DataWrite(0x13); //
LDI_CtrlWrite(0x4A);LDI_DataWrite(0x19); //
LDI_CtrlWrite(0x4B);LDI_DataWrite(0x19); //
LDI_CtrlWrite(0x4C);LDI_DataWrite(0x16); //
LDI_CtrlWrite(0x50);LDI_DataWrite(0x1B); //
LDI_CtrlWrite(0x51);LDI_DataWrite(0x31); //
LDI_CtrlWrite(0x52);LDI_DataWrite(0x2F); //
LDI_CtrlWrite(0x53);LDI_DataWrite(0x3F); //
LDI_CtrlWrite(0x54);LDI_DataWrite(0x3F); //
LDI_CtrlWrite(0x55);LDI_DataWrite(0x3E); //
LDI_CtrlWrite(0x56);LDI_DataWrite(0x2F); //
LDI_CtrlWrite(0x57);LDI_DataWrite(0x7B); //
LDI_CtrlWrite(0x58);LDI_DataWrite(0x09); //
LDI_CtrlWrite(0x59);LDI_DataWrite(0x06); //
LDI_CtrlWrite(0x5A);LDI_DataWrite(0x06); //
LDI_CtrlWrite(0x5B);LDI_DataWrite(0x0C); //
LDI_CtrlWrite(0x5C);LDI_DataWrite(0x1D); //
LDI_CtrlWrite(0x5D);LDI_DataWrite(0xCC); //
LDI_CtrlWrite(0x001b);LDI_DataWrite(0x001E);
LDI_CtrlWrite(0x001A);LDI_DataWrite(0x0001);
LDI_CtrlWrite(0x0024);LDI_DataWrite(0x0012); //VMH
LDI_CtrlWrite(0x0025);LDI_DataWrite(0x0050); //VML
LDI_CtrlWrite(0x0023);LDI_DataWrite(0x0095); //FOR flick adjust LDI_DataWrite(0x00A0);9E
LDI_CtrlWrite(0x0016);LDI_DataWrite(0x0048); //0x0000
LDI_CtrlWrite(0x0018);LDI_DataWrite(0x0066);
LDI_CtrlWrite(0x0019);LDI_DataWrite(0x0001);
LDI_CtrlWrite(0x0001);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x001D);LDI_DataWrite(0x0077); // Set the operating frequency of the step-up circuit 1 and extra step-up circuit 1 for DDVDH voltage generation
LDI_CtrlWrite(0x001E);LDI_DataWrite(0x0077); // Set the operating frequency of the step-up circuit 2 and 3 for VGH, VGL and VCL voltage generation
LDI_CtrlWrite(0x001F);LDI_DataWrite(0x0088);
//Delayms(5);
DelayX1ms(5);
LDI_CtrlWrite(0x001F);LDI_DataWrite(0x0080);
//Delayms(5);
DelayX1ms(5);
LDI_CtrlWrite(0x001F);LDI_DataWrite(0x0090);
//Delayms(5);
DelayX1ms(5);
LDI_CtrlWrite(0x001F);LDI_DataWrite(0x00D0);
//Delayms(5);
DelayX1ms(5);
LDI_CtrlWrite(0x0017);LDI_DataWrite(0x0005);
LDI_CtrlWrite(0x0036);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x0028);LDI_DataWrite(0x0038);
//Delayms(40);
DelayX1ms(5);
LDI_CtrlWrite(0x0028);LDI_DataWrite(0x003f);
LDI_CtrlWrite(0x0029);LDI_DataWrite(0x0033);
LDI_CtrlWrite(0x0002);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x0003);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x0004);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x0005);LDI_DataWrite(0x00EF);
LDI_CtrlWrite(0x0006);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x0007);LDI_DataWrite(0x0000);
LDI_CtrlWrite(0x0008);LDI_DataWrite(0x0001);
LDI_CtrlWrite(0x0009);LDI_DataWrite(0x003F);
LDI_CtrlWrite(0x0022);
}
其中LDI_CtrlWrite和LDI_DataWrite函数是用于写IR和写数据到IR指向的寄存器的值。比如:
LDI_CtrlWrite(0x00EA);LDI_DataWrite(0x0000);
这句代码的意义是把0x0000写入到0x00EA寄存器中。
上面初始化代码最后一行LDI_CtrlWrite(0x0022);非常重要,先来看数据手册中的描述:
图9
对于写操作LDI_CtrlWrite(0x0022)来说,在把显示数据写入GRAM之前,通过WDR先把显示数据转化为18bit总线数据格式,如下图所示:
图10
图10左边的17H寄存器可以取值为03h、05h、06h和07h,比如我们上面的初始化代码中调用:LDI_CtrlWrite(0x0017);LDI_DataWrite(0x0005);,再结合右边Color这一列,也就是说我们从CPU显示控制器送出去的16位显示数据,在调用LDI_CtrlWrite(0x0022)之后,通过WDR寄存器把这16位显示数据转换为:
DB[17:13]---R[4:3]
DB[12:10]---G[5:3]、DB[8:6]---G[2:0]
DB[4:0] ---B[4:0]
也就是把上面RGB数据通过对应的数据引脚DB再写入到GRAM中。
在对显示屏初始化结束的时候,调用LDI_CtrlWrite(0x0022),相当于打开显示数据可以发送到GRAM中显示的开关,这样后面CPU在刷屏或是更新显示画面时,画面数据就能有效送到HX8347-I的GRAM中,然后就能够正常显示。假如没有调用LDI_CtrlWrite(0x0022),有效的显示画面数据就无法送到GRAM中,所以GRAM中像素数据应该是无法确定的,经过验证此时显示花屏。
3. 实现过程中遇到的问题及解决
在系统挂起唤醒后显示屏显示白屏,为什么会出现这样的情况呢?先来看数据手册的描述:
图11
在挂起时,显示屏的电源是关闭的,在唤醒后重新上电,并初始化显示屏,但一定要在初始化之前先复位,这样就解决了这个问题。