详解LCD移植
LCD移植
1. Make文件设置设置LCD
LCD_MODULE = BROADMOBI68_09B_LCM //这个名字可以自己取,但是//这个名字要和\custom\drv\LCD\下的文件夹一致。
//一般可以不用改。到时直接修改这个文件夹下的代码就行了。
# Based on the LCM solutions (even multiple LCM modules for this project) # SHOULD BE ONE OF THE FOLLOWINGS, based on the LCM # mtkLCM - Mono, 102x64
# MTKLCM_COLOR - Color, 120x160, for MT6218_MW001 or MT6205_CEVB
# ORDNANCELCM - Mono, 112x64
# KLMLCM - Color, 128x128
# INFOLCM - Color, 128x128
# TOPPOLY_LCM - Color, 128x160, for MT6218B_EVB
# SONY_LCM
MAIN_LCD_SIZE = 320X480 //查LCD datasheet可以查到分辨率。
# To distinguish the main lcd size.
# We can use it to copy the matching resources, such themecomponents.h, Fontres.c, L_xxx.h, etc, to PLUTO_MMI folder
SUB_LCD_SIZE = NONE
# NONE, 48X64BW, 64X96, 96X64BW, 96X64, 128X128
COM_DEFS_FOR_BROADMOBI68_09B_LCM = BROADMOBI68_09B_LCM TFT_MAINLCD //如果//上面的LCD_MOULE设置改了,这个就要跟着该。
# TFT_MAINLCD – LCD类型
驱动代码:
mcu\custom\drv\LCD\$( LCD_MODULE)\lcd.c
mcu\custom\drv\LCD\$( LCD_MODULE)\lcd_hw.h
mcu\custom\drv\LCD\$( LCD_MODULE)\lcd_sw.h
mcu\custom\drv\LCD\$( LCD_MODULE)\lcd_sw_inc.h
mcu\custom\drv\LCD\$( LCD_MODULE)\lcd_rnd.h
2. 驱动开发。
a. 打开关闭DMA模式。
文件:mcu\custom\drv\LCD\$( LCD_MODULE)\lcd_sw.h
#if (defined(MT6226)||defined(MT6227)||defined(MT6228)||defined(MT6229)||defined(MT6268T)||defined(MT6230)||defined(MT6235)||defined(MT6235B)||defined(MT6238)||defined(MT6268A)||defined(MT6239)||defined(MT6268))
#define LCD_CMD_DMA_MODE //如果不需要则注解掉。一般打开,这样速度快。
#define LCD_DUMMYADDR 0x90000000
……
b. 设置LCD Bus Width。
这个定义要根据硬件上IM3~IM0的接法,具体查LCD datasheet。比如:
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_CLIp_image1.pngfile:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image2.png
看上图,IM3~IM0=”1010”,所以要如下定义:
#define MAIN_LCD_18BIT_MODE
c. 根据LCD参数设置主屏Command/Data Address.
查LCD Datasheet可以看到:
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image3.png
这里叫D/CX,也有叫RS的,反正是CMD和DATA的选择信号。看上图1为数据,0为命令,所以要做如下定义:
#define MAIN_LCD_CMD_ADDR LCD_PARALLEL0_A0_LOW_ADDR
#define MAIN_LCD_DATA_ADDR LCD_PARALLEL0_A0_HIGH_ADDR
//LCD_PARALLEL0_A0_LOW_ADDR/ LCD_PARALLEL0_A0_HIGH_ADDR在//lcd_if_xxxx_serials_hw.h中被定义,路径位于mcu\interface\hwdrv。具体使用那个文件//里的定义,请参考lcd_if_hw.h文件内容。
d. 设置color format
一般一个lcd,比如说有18bit的总线,但是根据IM3~IM0的接法,可以调整到8/9/16/18四种总线接法。但是呢,实际上肯定是18bit的接法,不然就浪费了,不让用这么好的屏干嘛啊,意思是一般都会用最大的总线支持的颜色类型。然后查lcd,可以查到:
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image4.png
Full color mode位262K色,所以应定义LCM_18BIT_18_BPP_RGB666_1(666=2的6次方乘3次,就是262K色)
#if (defined(MAIN_LCD_8BIT_MODE))
#define MAIN_LCD_OUTPUT_FORMAT LCM_8BIT_16_BPP_RGB565_1
#elif (defined(MAIN_LCD_9BIT_MODE))
#define MAIN_LCD_OUTPUT_FORMAT LCM_9BIT_18_BPP_RGB666_1
#elif (defined(MAIN_LCD_16BIT_MODE))
#define MAIN_LCD_OUTPUT_FORMAT LCM_16BIT_16_BPP_RGB565_1
#elif (defined(MAIN_LCD_18BIT_MODE))
//18位总线下最大支持RGB666,也就是262K色。
#define MAIN_LCD_OUTPUT_FORMAT LCM_18BIT_18_BPP_RGB666_1
#endif
// LCM_8BIT_16_BPP_RGB565_1这些值在lcd_if.h中被定义。
e. 设置Sub LCD的参数—和上面主屏一样的方法。
#ifdef DUAL_LCD
#ifdef SERIAL_SUBLCD
#define SUB_LCD_CMD_ADDR LCD_SERIAL0_A0_LOW_ADDR
#define SUB_LCD_DATA_ADDR LCD_SERIAL0_A0_HIGH_ADDR
#else
#define SUB_LCD_CMD_ADDR LCD_PARALLEL1_A0_LOW_ADDR
#define SUB_LCD_DATA_ADDR LCD_PARALLEL1_A0_HIGH_ADDR
#endif
#if (defined(SUB_LCD_8BIT_MODE))
#define SUB_LCD_OUTPUT_FORMAT LCM_8BIT_16_BPP_RGB565_1
#elif (defined(SUB_LCD_9BIT_MODE))
#define SUB_LCD_OUTPUT_FORMAT LCM_9BIT_16_BPP_RGB565_1
#elif (defined(SUB_LCD_16BIT_MODE))
#define SUB_LCD_OUTPUT_FORMAT LCM_16BIT_16_BPP_RGB565_1
#elif (defined(SUB_LCD_18BIT_MODE))
#define SUB_LCD_OUTPUT_FORMAT LCM_18BIT_18_BPP_RGB666_1
#endif
#endif
f. 实现LCD_CtrlWrite_XXX/ LCD_DataWrite_XXX函数。
LCD_DataWrite_XXX 和 LCD_CtrlWrite_XXX一样。所以只说LCD_CtrlWrite_XXX是如何实现的。
首先要明白我们的寄存器一般都是16位数据的,但是我们现在的总线接法有8位,9位,16位,18位这四种。这个函数的功能就是要将寄存器的数据送到总线上去。很显然,8位和9位的总线无法一次性将寄存器的数据获取,所以要分2次进行。而16位和18位就可以一次将寄存器的数据获取。
8位:分2次,先传高八位,然后传低8位。
#define LCD_CtrlWrite_XXX(_data) \
{\
SET_LCD_CMD_PARAMETER(0,LCD_CMD,((_data & 0xFF00)>>8));
SET_LCD_CMD_PARAMETER(1,LCD_CMD,(_data & 0xFF));
LCD_SEND_DMA_CMD(2);\
}\
9位:分2次,先传高8位,有问题了,总线是9位的,咋办,遇到这种情况,一般都是将数据映射到高位,也就是将数据映射到D17~D10,把D9空缺。D0~D8在硬件上就没接,一般都是这么接的,接高位。具体LCD datasheet有说明。
然后传低8位,做法和高8位一样。
#define LCD_CtrlWrite_XXX(_data) \
{\
//把高8位的数据映射到总线9位中的高8位。
SET_LCD_CMD_PARAMETER(0,LCD_CMD,((_data & 0xFF00)>>7));
SET_LCD_CMD_PARAMETER(1,LCD_CMD,((_data & 0xFF)<<1));
LCD_SEND_DMA_CMD(2);\
}\
16位:正好16位,不用移位。
#define LCD_CtrlWrite_XXX(_data) \
{\
SET_LCD_CMD_PARAMETER(0,LCD_CMD, _data);
LCD_SEND_DMA_CMD(1);\
}\
18位:这个有点特殊,把16位数据映射到18位的总线上,有2位是空缺的,空哪2位的,那就空D0和D9吧,这是惯例。具体可以问问LCD的厂商。
#define LCD_CtrlWrite_XXX(_data) \
{\
SET_LCD_CMD_PARAMETER(0,LCD_CMD,(((_data&0xFF00)<<2)|((_data&0xFF)<<1)));
LCD_SEND_DMA_CMD(1);\
}\
g. 实现LCD_Init_XXX函数。
参考厂商给的初始化代码吧,如果你牛X,那就参考LCD的datasheet,应该会有说明如何初始化。我拿到的一份datasheet,看了半天,没有看到如果初始化的东西。
h. 实现LCD_BlockWrite_XXX函数。
这个函数主要作用就是将刷屏的坐标传入到相应的寄存器。
首先要查LCD datasheet中存该坐标的寄存器是哪个,怎么存。比如查到:
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image5.png
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image6.png
可以看到,寄存器2A可以存startx,endx的数据,而寄存器2B则是存starty,endy的数据。所以可以写如下代码:
SET_LCD_CMD_PARAMETER(0,LCD_CMD,0x002A);
SET_LCD_CMD_PARAMETER(1,LCD_DATA,((start_x+0x0000) >>8)&0x00FF);
SET_LCD_CMD_PARAMETER(2,LCD_DATA,(start_x+0x0000)&0x00FF);
SET_LCD_CMD_PARAMETER(3,LCD_DATA,((end_x+0x0000) >>8)&0x00FF);
SET_LCD_CMD_PARAMETER(4,LCD_DATA,(end_x+0x0000)&0x00FF);
SET_LCD_CMD_PARAMETER(5,LCD_CMD,0x002B);
SET_LCD_CMD_PARAMETER(6,LCD_DATA,((start_y+0x0000) >>8)&0x00FF);
SET_LCD_CMD_PARAMETER(7,LCD_DATA,(start_y+0x0000)&0x00FF);
SET_LCD_CMD_PARAMETER(8,LCD_DATA,((end_y+0x0000) >>8)&0x00FF);
SET_LCD_CMD_PARAMETER(9,LCD_DATA,(end_y+0x0000)&0x00FF);
i. 实现LCD_EnterSleep_XXX/LCD_ExitSleep_XXX函数。
这个也是查LCD datasheet,看看要那个命令。
void LCD_EnterSleep_XXX(void)
{
LCD_CtrlWrite_XXX(0x10); //Sleep in
Delayms(5); //这个数字要查看data sheet的说明。
}
void LCD_ExitSleep_XXX(void)
{
LCD_CtrlWrite_XXX(0x11); //Sleep out
Delayms(120);//看datasheet说明
}
比如我拿到的LCD datasheet有这样的说明:
It is necessary to wait 5 msec before sending the next command. The time allows the supply
voltages and clock circuits to stabilize.
Also, wait 120 msec after sending Sleep Out command is necessary(when in Sleep In Mode) before
Sleep In command is sent.
j. 其它一堆函数,就参考MTK自带的LCD驱动吧,所有屏没区别,一样的,照搬就行。
k. 设置操作时序。
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image7.png
在lcd.c文件中的init_lcd_interface函数中设置:
// CS to WR setup time,是指片选信号拉低到V1L开始到WRX信号拉低到V1L结束,//等于Tcs – TWRL
SET_LCD_PARALLEL_CE2WR_SETUP_TIME((kal_uint32)2);
// CS to WR hold time,WRX拉高后,片选保持时间,等于TCSH
SET_LCD_PARALLEL_CE2WR_HOLD_TIME(1);
//data write wait state period指的是写信号有效的时间,即拉低的时间,图中的TWRL
SET_LCD_PARALLEL_WRITE_WAIT_STATE(5);
//CS to RD setup time.是指片选有效到读信号的建立时间,图中为TRCS – TRDL
SET_LCD_PARALLEL_CE2RD_SETUP_TIME(2);
//是指读信号被拉低的时间,图中的TRDL /TRDLRM
SET_LCD_PARALLEL_READ_LATENCY_TIME(20);
//它是指两个连续的写信号之间的保护周期数,也就是在两个连续的写信号之间片选信号拉//高的周期数,这个设定是根据BB 的datasheet,比如在MT6253上,如下图
file:///C:/DOCUME~1/sunzheng/LOCALS~1/Temp/ksohtml/wps_clip_image8.png
//图中的PERIOD数就是在 SET_LCD_ROI_CTRL_CMD_LATENCY(0)里面设置的周期数,它就是//在两个连续的写之间CS拉高的周期数,图中的+1,+2是mt6253上硬件默认埋的周期数
//你可以不用管,也不要被它迷惑,你要看你所用平台的datasheet里面Write timing diagram.
//因为这个只和BB有关,所以你不能进行更改。MTK release的版本已经帮你修改好。
SET_LCD_ROI_CTRL_CMD_LATENCY(0);
l. 设置功能函数。
LCD_Funcs LCD_func_ILI9327 = {
LCD_Init_ILI9327,
LCD_PWRON_ILI9327,
LCD_SetContrast_ILI9327,
LCD_ON_ILI9327,
LCD_BlockWrite_ILI9327,
LCD_Size_ILI9327,
LCD_EnterSleep_ILI9327,
LCD_ExitSleep_ILI9327,
LCD_Partial_On_ILI9327,
LCD_Partial_Off_ILI9327,
LCD_Partial_line_ILI9327,
/*Engineering mode*/
LCD_GetPARM_ILI9327,
LCD_SetBias_ILI9327,
LCD_Contrast_ILI9327,
LCD_LineRate_ILI9327,
LCD_Temp_Compensate_ILI9327
#ifdef LCM_ROTATE_SUPPORT
,LCD_Set_Scan_Direction_ILI9327
#endif
#ifdef LQT_SUPPORT/*Do not remove LQT code segment*/
,LCD_gamma_test
,LCD_flicker_test
#endif
};
#ifdef DUAL_LCD
LCD_Funcs LCD_func_NT75751 = {
LCD_Init_NT75751,
LCD_PWRON_NT75751,
LCD_SetVoltLevel_NT75751,
LCD_ON_NT75751,
LCD_BlockWrite_NT75751,
LCD_Size_NT75751,
LCD_EnterSleep_NT75751,
LCD_ExitSleep_NT75751,
0,
0,
0,
/*Engineering mode*/
LCD_GetParm_NT75751,
LCD_SetBias_NT75751,
LCD_Contrast_NT75751,
LCD_LineRate_NT75751,
LCD_Temp_Compensate_NT75751
#ifdef LCM_ROTATE_SUPPORT
,LCD_Set_Scan_Direction_NT75751
#endif
};
void LCD_FunConfig(void)
{
MainLCD = &LCD_func_ILI9327;
#ifdef DUAL_LCD
SubLCD = &LCD_func_NT75751;
#endif
}
这个是功能机的LCM吧