Android系统下的基于MIPI-DSI协议的LCM的研究

0 引言

随着智能手机的高速发展,手机内部含有越来越多不同接口的设备,同时又要满足低功耗、高分辨率以及小体积的显示模块的发展,本文就将探讨新型显示接口技术MIPI-DSI命令模式的LCM驱动设计与调试。一方面,DSI兼容DBI(显示总线接口)、DPI(显示像素接口)、和DCS(显示命令集)。另一方面DSI让手机设备的接口在降低成本、复杂度、功耗以及EMI的同时,也能够增加带宽,从而极大的提高了手机性能。

本文在联发科的MT6572平台进行LCM(LCD module)驱动的设计,在联发科技提供的Android4.1和内核Linux 3.10下进行开发。MTK6572是一款28制程的双核基带芯片,单核的主频可达1.2Ghz,内核Cortex-A7基于ARMv7架构,同时内部有Mali-400图形处理器。同时,MT6572最高支持分辨率720P级的屏幕。LCM是台湾奇景光电股份有限公司的3.5寸液晶屏的TFT LCD模组HX8357d。

1 DSI协议

1.1DSI的连接

DSI协议属于接口通信协议,它是位于显示模组和处理器之间的一种可扩展通道的高速串行接口,其支持一条时钟通道和1-4条数据通道,图1是DSI的物理连接图。DSI根据其兼容的外设的不同架构,具有视频模式(video mode)和命令模式(command mode)这两种操作模式。

命令模式要求LCM有显示缓存,主机通过命令间接控制外设。LCM芯片有一个FMARK脚,用来与主控同步,当主机端接收到LCD发出的TE信号,才会开始往FrameBuffer写数据;当LCD接收到来自主控的刷新命令,LCD才开始从显示缓存中读数据。视频模式是指在主机和外设之间用实时像素流的方式传输,并且只能工作在高速传输模式,不需要有显示缓存。本文采用命令模式进行操作。图2命令模式的示意图。

1.2DSI协议数据的结构

DSI协议下数据包的传输如图3示,该协议规定了短数据包和长数据包这两种数据包。图中LPS(low powerstate)表示低功耗模式,SOT为传输开始,SP为短数据包,EOT为传输结束,LP为长数据包,数据包的前后配置了数据低功耗还是高速、长包还是短包的标志位。

如图4是只包含4字节数据包头的短数据包结构。分别包含ID(数据标识符),有效数据和ECC(错误检查和纠正)。短数据包可以操作寄存器、传送命令。图5是6-6554lB 大小的长数据包结构,首先其拥有4B的数据包头:ID、WC(传输数据的大小)和ECC;然后是有效数据和数据包页脚。长数据包可以传输控制命令及大量数据,结合不同的参数和命令可以配置不同长短的长数据包。

1.3DSI协议数据包的传输方式

DSI协议数据包的传输以同步方式在主机和LCD端进行数据传输,其传输模式有LP(Low Power)和HS(High Speed)这两种。其中LP采用数据速率小于10Mbps的单端信号进行传输,HS模式下采用数据速率80M~1Gbps的低压差分信号。MIPI总线有大量数据传输时使用HS传输,其他时候使用LP传输,两者结合能够让手机降低功耗的同时降低EMI。本文程序就是设计两者结合,在dsi_drv.c的DSI_TXRX_Control函数的定义中,设置tmp_reg.HSTX_CKLP_EN = 1,从而让在LCM每一帧画面之间工作在LP模式。

2硬件电路设计

MT6572可支持3条数据通道的DSI接口,本设计使用一条通道。硬件原理图如图6所示,有时钟差分信号DSI_CLK+和DSI_CLK-,双向数据通道DSI_D0+和DSI-D0-。FMARK引脚用来发送TE信号给主机,通知主机往frame buffer写数据。IC_ID引脚用来读取LCM的硬件ID,从而在兼容多个LCM时候根据ID选择正确的驱动程序。

3 LCM驱动的设计

LCM驱动要完成lk和kernel这两部分的设计。而在turkey版本的Android系统中,lk阶段的的LCM驱动程序是到kernel中程序的链接,这样只需要设置kernel中的LCM驱动就可以。系统中需要设置的LCM驱动有关的文件目录如下:

3.1配置文件

mediatek\config\y25\ProjectConfig.mk是配置文件,主要配置如下:

/*分别选择lk、kernel阶段的LCM驱动*/

CUSTOM_LK_LCM= hx8357d_hvga_dsi_cmd

CUSTOM_KERNEL_LCM= hx8357d_hvga_dsi_cmd

BOOT_LOGO=hvga         选择需要使用的logo

其中,hx8357d_hvga_dsi_cmd是添加的驱动所在文件夹的文件名。若想兼容两个不同的LCM,则在上述驱动名称后面加一个空格,再添加另一个文件名,系统即可根据读取的LCM的ID自动选择对应的驱动程序。

3.2LCM驱动的声明

mediatek\custom\common\kernel\lcm\mt65xx_lcm_list.c用于在lcm_driver_list结构体指针数组中声明hx8357d_hvga_dsi_cmd_lcm_drv结构体指针。Lcm_driver_list用于将LCM封装的信息传递给DSI控制器层的驱动。

3.3LCM驱动程序的设计

mediatek\custom\common\kernel\lcm\hx8357d_hvga_dsi_cmd\hx8357d_hvga_dsi_cmd.c

此为LCM的驱动程序,因为不同的LCM有不同的的分辨率、初始化序列、时序等,因此为了使程序有更好的可移植性和可读性,把这些部分分立出来。对于接口相同的LCM,就可以根据不同的型号进行不同的参数配置,这也是驱动程序分层思想的优点。LCM的配置主要是使用封装好的三个结构体。按照设置顺序,首先,LCM的初始化序列中的命令参数和初始化参数的配置是利用结构体LCM_setting_table进行封装,然后lcm_init()函数通过DSI的写函dsi_set_cmdq_V3将参数写入LCM;其次,LCM_PARAMS结构体对DSI控制器的初始化参数进行封装,需要注意的是命令模式下不需要设置VSPW、VBPD、VFPD及HSPW、HBPD、HFPD;最后LCM_DRIVER结构体对LCM的底层调用接口函数指针和名称进行封装,DSI控制器层的驱动会调用这些函数对LCM和DSI控制器进行初始化。其主要部分程序如下设置:

struct LCM_setting_table {

unsigned char cmd;  //将要下的命令

unsigned char count;//命令的参数个数

unsigned char para_list[64];//参数列表

};

static struct LCM_setting_tablelcm_initialization_setting[] = {

{

/*设置LCM刷新频率55HZ*/

{0xB0,2,{0x55,0x01}},  

};

static void lcm_init(void)

{

dsi_set_cmdq_V3(lcm_initialization_setting,sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1);         

}

Typedef struct

{      

LCM_TYPE type;             

Unsigned int width;       //LCM的宽

Unsigned int height;      //LCM的高

/*初始化DSI控制器参数的结构体*/

LCM_DSI_PARAMS dsi;

} LCM_PARAMS;

static void lcm_get_params(LCM_PARAMS*params)

{

/*设置LCM工作在DSI模式*/

params->type= LCM_TYPE_DSI; params->width  = 320;

params->height = 480;   

/*设置dbi (dsi兼容dbi)在TE工作模式*/

params->dbi.te_mode =

LCM_DBI_TE_MODE_VSYNC_ONLY;

/*设置LCM工作在命令模式*/

params->dsi.mode   = CMD_MODE;

/*设置LCM使用一条数据通道传输*/

params->dsi.LANE_NUM  = LCM_ONE_LANE;

/*配置DSI的传输频率*/ 

params->dsi.PLL_CLOCK   = 111; 

}

LCM_DRIVER hx8357d_hvga_dsi_cmd_lcm_drv =

{

/*驱动的名称*/

.name= "hx8357d_hvga_dsi_cmd",

/*初始化DSI控制器的参数配置*/

.get_params = lcm_get_params,

.init  =   lcm_init,    //LCM的初始化

/*用于多个LCM兼容时候读取硬件ID*/

.compare_id = lcm_compare_id, };

4 LCM驱动的调试

(1)命令模式会有画面刷新有残留(tearing effect,即TE)的问题。根本原因是主控往FrameBuffer写图像数据的速度与LCM从FrameBuffer读数据(刷屏)的速度不一致造成的,解决此问题必须设置主机端在两个TE周期内刷新完一帧数据。首先,配置LCD的刷新频率略小于主机端往FrameBuffer发送数据频率的2倍,其次通过设置FMARK迟滞几个HSYNC周期再输出TE信号来延迟主控开始写数据到FrameBuffer的时间。通过以上配置,避免FrameBuffer的读写数据产生交叉,从而避免由于刷新频率不一致产生的TearingEffect。本例中在拍照模式时候就会有TE问题,在确认开启TE SYNC功能之后,抓取图7所示的TE信号波形图,检测到TE信号正常送出。由于拍照时候数据传输的特殊性,此时camera相当于是主机端,刷新数据的流程相当于camera—FrameBuffer—LCM。而是camera刷新频率是30,LCM刷新频率设置的是60,图7是TE信号波形图,可以看出LCM刷新频率过大,在程序中设置LCM刷新频率为55Hz,最终解决了问题。

(2)在lk阶段读不到LCM的硬件ID的问题。从硬件角度读不到ID有两种可能。一个是BTA function没有成功,导致IC没有送出ID,通过图8可以看到BTA已经完成,总线控制权成功交给了IC;另一个是IC没有正确送出ID,导致读ID失败,图9 可以看到BTA后,IC有将ID=0x99正确送出。

通过上述排查,可以确认是软件由软件产生的问题,分析程序的日志如下:

DISP/DSI+000c : 0x80000001,//准备好读数据

/*1c表示 PacketType ,02表示数据包长度,短数据包的值000c*/  

DISP/DSI+0074 : 0x0c00021c,

/*读取的长数据包的值0x99*/

DISP/DSI+0078 : 0x3efd0099,

/*等待软件接收到读到的数据的信号*/

DISP/DSI+0160 : 0x00010400,

/*0xD0寄存器已经发出去读到的数据*/

DISP/DSI_CMD+0000(0x1400c180): 0x00d00604,

分析日志可以发现:从寄存器看,CMDQ里面已经读到了数据,但是软件没有收到数据。最终可以知道,lk读不到id问题在于软件延时处理慢,通过增大polling次数解决。在mediatek\platform\mt6572\lk\dsi_drv.c文件中修改函数DSI_dcs_read_lcm_reg_v2的定义,设置read_timeout_ms= 200; 把polling的次数由20改为200,从而保证读到正确数据,最终解决了问题。

5 结语

本文描述了Android系统下的基于MIPI-DSI协议的LCM的驱动设计,最终完成了MT6572平台上的LCM驱动的设计,并且让屏幕能够正常的流畅显示画面。通过以上的设计过程的分析,一方面可以明显感觉到Android系统下的驱动开发的清晰的层次结构与简便的程序设计,Android的短周期的开发速度更是不断推进智能手机的迅速发展,另一方面也能感觉到DSI协议的极大优越性,并且相信以后DSI协议也会有进一步的发展。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值