在嵌入式的主流 LCD屏中主要支持两大类的硬件接口,一种是常见的RGB接口,另外一种是MCU接口.后面因为最早是针对单片机的领域在使用,因此得名.后在中低端手机大量使用,其主要特点是价格便宜的.
MCU-LCD接口的标准术语是Interface 80,因此在很多文档中用I80 来指MCU-LCD屏。
MCU-LCD屏它与RGB-LCD屏主要区别在于显存的位置.RGB-LCD的显存是由系统内存充当的,因此其大小只受限于系统内存的大小,这样 RGB-LCD可以做出较大尺寸,象现在4.3"只能算入门级,而MID中7",10"的屏都开始大量使用.而MCU-LCD的设计之初只要考虑单片机的 内存较小,因此都是把显存内置在LCD模块内部.然后软件通过专门显示命令来更新显存,因此MCU屏往往不能做得很大.同时显示更新速度也比RGB- LCD慢.
量示数据传输模式也有差别。
RGB屏只需显存组织好数据。启动显示后。LCD-DMA会自动把显存通过RGB接口送到LCM。
而MCU屏则需要发送画点的命令来修改MCU内部RAM。(即不能直接MCU屏RAM)
所以RGB显示速度明显比MCU快,而且播放视频方面,MCU-LCD也比较慢.
S3C6410 即支持RGB-LCD屏,也支持MCU-LCD屏.而对MCU-LCD屏的显示模块的显存显示,它除了支持传统的绘制命令,也支持一种特有的类似RGB- LCD屏的显示模式。即显示数据仍然在系统内存中组织,显示时通过DMA传输到显示器控制器,由硬件来产生绘制命令。相对纯软件绘制模式,这种方法速度更 快。
MCU-LCD管脚分析
---------------------------------------------------------------------
两种屏通过管脚直接就可以看出来的。RGB屏管脚主要分为两类
控制脚是VSYNC/HSYNC/VDEN/VCLK S3C6410最高支持24个数据脚,数据脚是 VD[23-0];
MCU接口标准名称是 I80 Interface.
MCU管脚的控制脚有5个
-
CS 片选信号
-
RS (置1为写数据,置0为写命令)
-
/WR (为0表示写数据)
-
/RD (为0表示读数据)
-
RESET 复位LCD( 用固定命令系列 0 1 0来复位)
数据脚一般是18个,即DB[17:0],这样表示大部MCU最高支持18bpp
S3C6410 I80管脚
S3C6410采用非标准命令,因此有如下对应关系,控制脚
-
SYS_CSx 对应CS
-
SYS_OE 对应RD
-
SYS_WE对应WR
-
SYS_RS对应RS
-
这里没有对应RESET,直接采用某一个IO口来代替。
在mini6410中 这里采用VD[21]即GPJ5来充当RESET脚
-
数据脚 输出VDOUT[17:0],与RGB管脚不一样的是,MCU-LCD还带有 VDIN[17:0],即显存中的数据可以通过命令读取出来。
mini6410 LCM接口
我们测试是采用学生公司的MCU LCM,爱诺信2.8"的mcu屏。因为接口不是完全兼容,因此只能用采用复杂连线板来匹配。开发板使用的是mini6410。
注意这里RGB-LCD和I80接口是复用的。一块S3C6410同时支持两个LCD,mini6410用排线引出来LCD,这里我们把原来的4.3 "LCD的取下,然后再用自制排线接上。
这个LCM按其管脚要求配置成 16bpp(565)。这是LCM一侧的跳线配置。
相应的,在S3C6410一侧使用VD[0-15]
因此在S3C6410 一侧,采用VD[0-15]来与其对接
I80 硬件连线
mini6410板上,我们这样进行连线。
-
RESET : 这里使用VD[21]来当RESET线,即 GPJ5的output脚.
-
CS0: 这里复用了HSYNC信号脚,即使用GPJ8
-
OE: 在引脚上悬空,即始终为高,这样不影响结果。
-
WE: 复用了VCLK信号脚,即采用 GPJ11脚
-
I80 硬件波形分析
---------------------------------------------------------
启动波形
根据I80的要求,每次如果需要RESET LCD屏,需要用软件发送 101序列。
这是MCU-LCD IC里的RESET波形图
这里我们实测LCD屏的启动波形
MCU-LCD初始化屏幕,一般出现如下画面表示硬件连线正确,并且初始化成功.
写入波形
在MCU-LCD中,用RS脚来区别是向MCU屏发送命令还是数据。而且通常每一种MCU屏有一组初始化命令,它具体的序列取决了不同硬件,所以不同型号的MCU-LCD屏初始化命令序列是不一样的,这个要由生产厂家来提供。
参考S3C6410提供的I80标准波形,在写入时,WE必须是低电平,RS取决于写入命令还数据。CS是片选有效,是低电平有效。
以下是LCM模块提供写命令时序图,基本跟S3C6410的波形一致。
以下波形是实测MCU-LCD波形,可以看到比较明显在,在MCU-LCD初始化时,CS脚被频繁的置低有效。这是在发送一系列的初始化命令,然后随后一直为高,表示在发送显示数据。
这是放大后波形
S3C6410 MCU-LCD编程
-----------------------------------------------------------------------------
MCU需要专门的绘点函数修改LCM内部RAM。。在S3C6410我们有两种方法来绘制MCU-LCD,一种是通用通用方法,在单片机以32位CPU都可以使用。另外一种是S3C6410的扩展,称为I80 RGB Trigger模式,它是先在系统内存组织好显存.然后通过DMA传输到LCM内部存储器上。这种模式的显示速度大大优于专门画点命令的函数,应该做较多优化。
我们两种模式都实测了,前者是绘制的速度相当于之慢,无法实用(可能跟算法效率也有关系),因此我们有实用价值主要采用RGB 捕获模式的流程。
我们后面主要是这个流程,这个在S3C6410算法最早由梁熠章实现验证。
按照S3C6410的要求,MCU-LCD编程流程如下.这个算法里很多流程比如WINDOWS/OSD的操作可以直接重用RGB-LCD的代码。
因此我们首先按MCU-LCD的屏的要求,
1.首先是发送RESET信号,这个取决于硬件连续。在我们板上使用 GPJ5来充当RESET脚
//MCU屏要求,每次Reset要求送一个 1,0,1的波形
void LCD_MCU_Reset()
{
#ifdef LCD_TYPE_MCU_NOAIS28
rGPJCON = (rGPJCON & ~(0x3<<10)) | (0x1<<10);
rGPJDAT |= (0X1<<5);
Delay(100);
rGPJDAT &= ~(0X1<<5);
Delay(100);
rGPJDAT |= (0X1<<5);
Delay(100);
#endif
}
|
2.是配置LCD类型为 I80接口.
这里有两步,一是配置 将rMIFPCON的SEL_BYPASS[3] 设为0 ,旁路掉Modem引脚.
rMIFPCON &= ~(0x1 << 3);
二是将接口配置为I80 的接口.
rSPCON = (rSPCON & ~3) | (0x00 << 0);
三.设置MCD-LCD硬件参数
这里仍然采用RGB-LCD的经验值来进行调整,频率采用 HCLK的16分之一.bpp采用16.
信号捕获模式完全等同于RGB模式,
rVIDCON1 = IVCLK_RISE_EDGE | IHSYNC_NORMAL | IVSYNC_NORMAL | IVDEN_NORMAL ;
2.8"分辨率分别是240x320。用VIDTCON2配置
rVIDTCON2 = LINEVAL(pDevice->height -1 ) | HOZVAL(pDevice->width -1);
另外I80有自己的专用时序参数,这里使用I80IFCONA0来配置,主要各段时序的时间长度,这由具体板的参数来读取。我们取一组经验值
rI80IFCONA0 = (LCD_CS_SETUP << 16)| (LCD_WR_SETUP << 12) | (LCD_WR_ACT << 8)|(LCD_WR_HOLD << 4)|(1<<2)|(1<<0);
四.诺爱信2.8"的LCD 初始化命令
这是产家规定一组序列参数
LCD_MCU_Write_Register(0x00E3,0x3008);
LCD_MCU_Write_Register(0x00E7,0x0012);
LCD_MCU_Write_Register(0x00EF,0x1231);
LCD_MCU_Write_Register(0x0001,0x0100);
LCD_MCU_Write_Register(0x0002,0x0700);
LCD_MCU_Write_Register(0x0003,0x1030);
LCD_MCU_Write_Register(0x0004,0x0000);
LCD_MCU_Write_Register(0x0008,0x0207);
LCD_MCU_Write_Register(0x0009,0x0000);
LCD_MCU_Write_Register(0x000A,0x0000);
LCD_MCU_Write_Register(0x000C,0x0000);
LCD_MCU_Write_Register(0x000D,0x0000);
LCD_MCU_Write_Register(0x000F,0x0000);
LCD_MCU_Write_Register(0x0010,0x0000);
LCD_MCU_Write_Register(0x0011,0x0007);
LCD_MCU_Write_Register(0x0012,0x0000);
LCD_MCU_Write_Register(0x0013,0x0000);
Delay(10);
LCD_MCU_Write_Register(0x0010,0x1490);
LCD_MCU_Write_Register(0x0011,0x0227);
Delay(10);
LCD_MCU_Write_Register(0x0012,0x001A);
Delay(10);
LCD_MCU_Write_Register(0x0013,0x0700);//1000
LCD_MCU_Write_Register(0x0029,0x0001);//
0015
LCD_MCU_Write_Register(0x002B,0x000C);
Delay(10);
LCD_MCU_Write_Register(0x0020,0x0000);
LCD_MCU_Write_Register(0x0021,0x0000);
LCD_MCU_Write_Register(0x0030,0x0000);
LCD_MCU_Write_Register(0x0031,0x0607);
LCD_MCU_Write_Register(0x0032,0x0305);
LCD_MCU_Write_Register(0x0035,0x0000);
LCD_MCU_Write_Register(0x0036,0x1604);
LCD_MCU_Write_Register(0x0037,0x0204);
LCD_MCU_Write_Register(0x0038,0x0001);
LCD_MCU_Write_Register(0x0039,0x0707);
LCD_MCU_Write_Register(0x003C,0x0000);
LCD_MCU_Write_Register(0x003D,0x000F);
LCD_MCU_Write_Register(0x0050,0x0000);
LCD_MCU_Write_Register(0x0051,0x00EF);
LCD_MCU_Write_Register(0x0052,0x0000);
LCD_MCU_Write_Register(0x0053,0x013F);
LCD_MCU_Write_Register(0x0060,0xa700);
LCD_MCU_Write_Register(0x0061,0x0001);
LCD_MCU_Write_Register(0x006A,0x0000);
LCD_MCU_Write_Register(0x0080,0x0000);
LCD_MCU_Write_Register(0x0081,0x0000);
LCD_MCU_Write_Register(0x0082,0x0000);
LCD_MCU_Write_Register(0x0083,0x0000);
LCD_MCU_Write_Register(0x0084,0x0000);
LCD_MCU_Write_Register(0x0085,0x0000);
LCD_MCU_Write_Register(0x0090,0x0010);
LCD_MCU_Write_Register(0x0092,0x0600);
LCD_MCU_Write_Register(0x0093,0x0003);
LCD_MCU_Write_Register(0x0095,0x0110);
LCD_MCU_Write_Register(0x0097,0x0000);
LCD_MCU_Write_Register(0x0098,0x0000);
LCD_MCU_Write_Register(0x0007,0x0133);
|
五.S3C6410 I80命令的发送
I80就是由命令和数据都是通过MCU接口发送到LCM进行解释。命令的含意取决于具体的LCM,不一定相同。S3C6410只是实现发送机制
一个I80命令/数据由多个寄存器来设置,
命令值本身,由LDI_CMDx来设定,x取值是 0 - 11(即一次性最多发送12个命令)
命令的模式,即这一次发送中哪一个命令有效/以及采用哪一个模式,它由LDI_CMDCON0对应位来生效,命令发送有两种模式,一种单独手工发送,一种自动成批发送
命令的类型,即每一个发送是命令还是数据,由LDI_CMDCON1来配置
I80IFCONB0 /1来设置命令的总体配置,包括自动命令的帧数,或者普通命令的开始
#define LCD_MCU_START_WRITE() rI80IFCONB0 |=(1<<9)
void LCD_MCU_Write_Cmd(unsigned short cmd)
{
rLDI_CMD0 = cmd;
//等Normal command 变为0
while(!( (rI80IFCONB0& (1<<9)) == 0));
rLDI_CMDCON0 = (rLDI_CMDCON0 & (0x0)) |((0x01)<<0); //01
: Normal Command Enable
rLDI_CMDCON1 = (rLDI_CMDCON1 & (0x0)) |((0x0)<<0); //Command
0 RS control,送命令
LCD_MCU_START_WRITE();
Delay(10);
}
void LCD_MCU_Write_Data(unsigned short data)
{
rLDI_CMD0 = data;
//等Normal command 变为0
while(!( (rI80IFCONB0& (1<<9)) == 0));
rLDI_CMDCON0 = (rLDI_CMDCON0 & (0x0)) |((0x01)<<0); //01
: Normal Command Enable
rLDI_CMDCON1 = (rLDI_CMDCON1 & (0x0)) |((0x1)<<0); //Command
0 RS control ,送数据
LCD_MCU_START_WRITE();
Delay(10);
}
|
七.显存数据组织
采用16bpp(565)的形式在显存中组织.处理流程与RGB 16bpp几乎完全一样,采用short来发送点数据
它会自动生成MCU命令来传输.
组织好用TRIGCON来触发显示.
rTRIGCON |= (1<<1)|(1 << 0);
然后用VIDCON0中打开输出显示
rVIDCON0 |= (1 << 1) | ( 1 << 0); //.Display On: ENVID & ENVID_F set to 1