SylixOS的LCD驱动移植
来源:互联网 发布:天猫淘宝双十一晚会 编辑:程序博客网 时间:2024/06/14 17:39
1. 原理概述
1.1 显示原理
如图 1-1所示,LCD驱动会申请一块FB内存,应用程序向FB内存中搬运显示的数据,屏幕上就会有对应的显示。
图 1-1显示原理
1.2 时序Timing
每一个LCD屏幕都会有自定义的时序,这些数据一般都会在屏幕的数据手册中提供,LCD控制器需要根据这些时序产生对应的行场,屏幕在获得正确的行场后才能正常显示。
LCD显示的时序如图 1-2所示,其中屏幕可见区域大小为xres * yres。
图 1-2 LCD显示时序
显示时序图中有相关概念,如表 1-1所示。
表 1-1时序使用的相关概念
名词对应缩写说明left_marginHBP(Horizontal Back Porch)每行开始时需要插入的像素时钟周期数right_marginHFP(Horizontal Front Porch)每行结束时需要插入的像素时钟周期数upper_marginVBP(Vertical Back Porch)垂直同步周期之后帧开头时的无效行数lower_marginVFP(Vertical Front Porch)本帧结束到下一帧垂直同步周期开始之
前的无效行数hsync_lenHPW (HSYNC plus width)表示水平同步信号的宽度(单位:像素时钟周期)vsync_lenVPW (VSYNC width)表示垂直同步脉冲的宽度(单位:显示一行的时间)
如表 1-2和表 1-3所示,E50A2V1屏幕的数据手册中有水平timing和竖直timing的定义,根据数据手册中的参数设置对应的LCD控制器寄存器即可。
此外需要配置LCD控制器总时钟DCLK,E50A2V1为30MHz。
表 1-2 Horizontal timing
Parameter
Symbol
Min. Spec.
Typ. Spec.
Max. Spec.
Unit
Horizontal Display Areathd 800 DCLKDCLK frequencyfclk-3050MHzOne Horizontal Lineth8899281143DCLKHS pulse widththpw148255DCLKHS Back Porch(Blanking)thb 88 DCLKHS Front Porchthfp140255DCLKDE mode Blankingth-thd85128512DCLK表 1-3 Vertical timing
Parameter
Symbol
Min. Spec.
Typ. Spec.
Max. Spec.
Unit
Vertical Display Area
tvd 480 THVS period timetv513525768THVS pulse widthtvpw33255THVS Back Porch(Blanking)
tvb 32 THVS Front Porchtvfp113255THDE mode Blankingtv-tvd445255TH
1.3 RGB和灰度
1.3.1 RGB888和RGB565
对于彩色图像,每个像素通常用三个分量表示,即R(Red)、G(Green)、B(Blue)三个分量,每个分量用一个字节表示,因此每个分量的取值范围从0到255。
RGB888每个像素由3个字节组成,R、G、B各占8bit;
RGB565 每个像素由2个字节组成,R占5bit,G占6bit,B占5bit。
1.3.2 灰度
灰度表示一个像素最多能显示的颜色数量。
对于RGB888来说,一共可以显示256 * 256 * 256 = 16777216种色彩,那么灰度就是16777216。
对于RGB565来说,一共可以显示32 * 64 * 32 = 65536种色彩,那么灰度就是65536。
2. 技术实现
2.1 LCD驱动框架
lcd驱动实现基本功能,只要实现如图 2-1中的四个函数即可。
图 2-1 LCD驱动需要关注的四个函数
2.1.1 函数__lcdOpen
这个函数需要向系统申请一块用于FB的内存,并且根据timing初始化行场信号,最后开启背光。
2.1.2 函数__lcdClose
这个函数是lcdOpen的逆向过程,主要操作就是关闭背光。
2.1.3 函数__lcdGetVarInfo
这个函数用于获取和屏幕相关的一些参数,比如屏幕的高度和宽度、RGB格式和灰度等。
2.1.4 函数__lcdGetScrInfo
这个函数用于获取和FB相关的一些参数,比如FB的大小。
2.2 调试过程
调试的过程首先要确认屏幕的背光是否开启,如果背光不亮屏幕上是不会有任何显示的。在确认背光开启之后再进行后面几步的测试。
2.2.1 通过示波器确认行场信号
1. 确认DCLK
通过示波器测量DCLK引脚,正常显示的时候应该会产生30MHz的波形。
2. 确认HSYNC
通过示波器测量HSYNC引脚,正常显示的时候应该会产生波形。
3. 确认VSYNC
通过示波器测量VSYNC引脚,正常显示的时候应该会产生波形。
2.2.2 编写测试程序
可以编写一个绘制BMP图形的测试用例,另外利用PhotoShop或其他制图工具,参考实际的分辨率大小制作一张对应的BMP图片。
例如:E50A2V1的分辨率为800 x 480,RGB格式为RGB565,制作这样的一张图片。接着如代码清单 1所示,在代码中打开BMP图片后跳过头部信息,将实际内容拷贝到FB中,那么在屏幕上就应该有对应的图形显示了。
代码清单 1测试程序基本流程
/* * 打开位图 */ pFp = fopen(pBmpfile, "rb"); …… /* * 读取位图文件头 */ iRc = fread(&FileHead, sizeof(BITMAPFILEHEADER), 1, pFp); …… /* * 读取文件信息头 */ iRc = fread((char*)&InfoHead, sizeof(BITMAPINFOHEADER), 1, pFp); …… /* * 跳过文件头 */ fseek(pFp, (INT)charToLong(FileHead.cfoffBits, 4), SEEK_SET); …… /* * 逐行、逐像素绘制图片 */ while (!feof(pFp)){ iRc = fread((CHAR *)&pix, 1, sizeof(UINT16), pFp); if (iRc != sizeof(UINT16)){ break; } lLocation = iLineX * iBitsPerPixel /8+(iLineY)* iXres * iBitsPerPixel /8; usTmp = pix.blue <<0| pix.green <<5| pix.red <<11; *((UINT16 *)(__GpcFb + lLocation))= usTmp; iLineX++; if(iLineX == iWidth){ iLineX =0; iLineY++; if(iLineY == iHeight +1){ break; } } }
3. 代码实现
3.1 驱动代码
3.1.1 __lcdOpen的具体实现
__lcdOpen调用了API_VmmPhyAllocAlign向系统申请了一块FB的内存,具体实现如代码清单 2所示。
代码清单 2 __lcdOpen的具体实现
static INT __lcdOpen (PLW_GM_DEVICE pgmdev, INT iFlag, INT iMode){ if (GpvFbMemBase == LW_NULL) { GpvFbMemBase = API_VmmPhyAllocAlign(800 * 480 * 3, /* 最大800 * 400分辨率 */ 4 * 1024 * 1024, /* 4M字节对齐 */ LW_ZONE_ATTR_DMA); if (GpvFbMemBase == LW_NULL) { __lcdDisable(); printk(KERN_ERR "__lcdOpen() low vmm memory!\n"); return (PX_ERROR); } __lcdInit(); } __lcdEnable(); return (ERROR_NONE);}
3.1.2 __lcdGetVarInfo的具体实现
返回了屏幕的实际高度、灰度等数值,具体实现如代码清单 3所示。
代码清单 3 __lcdGetVarInfo的实现
static INT __lcdGetVarInfo (PLW_GM_DEVICE pgmdev, PLW_GM_VARINFO pgmvi){ if (pgmvi) { pgmvi->GMVI_ulXRes = curDisplayDev.uiDevWidth; /* 屏幕实际宽度 */ pgmvi->GMVI_ulYRes = curDisplayDev.uiDevHeight; /* 屏幕实际高度 */ pgmvi->GMVI_ulXResVirtual = curDisplayDev.uiDevWidth; /* 屏幕虚拟区域宽度 */ pgmvi->GMVI_ulYResVirtual = curDisplayDev.uiDevHeight; /* 屏幕虚拟区域高度 */ pgmvi->GMVI_ulXOffset = 0; /* 屏幕x坐标偏移 */ pgmvi->GMVI_ulYOffset = 0; /* 屏幕y坐标偏移 */ /* * BPP和掩码设置 */ switch (curDisplayDev.uiStreamColorFormat) { …… case FORMAT_RGB565: pgmvi->GMVI_ulBitsPerPixel = 16; pgmvi->GMVI_ulBytesPerPixel = 2; pgmvi->GMVI_ulRedMask = 0xF800; pgmvi->GMVI_ulGreenMask = 0x07E0; pgmvi->GMVI_ulBlueMask = 0x001F; break; …… } /* * 灰度设置 */ switch (curDisplayDev.uiColorsType) { case COLORTYPE_4K: pgmvi->GMVI_ulGrayscale = 4096; break; …… } pgmvi->GMVI_ulTransMask = 0; pgmvi->GMVI_bHardwareAccelerate = LW_FALSE; pgmvi->GMVI_ulMode = LW_GM_SET_MODE; pgmvi->GMVI_ulStatus = 0; } return (ERROR_NONE);}
3.1.3 __lcdGetScrInfo的具体实现
代码清单 4 __lcdGetScrInfo的具体实现
static INT __lcdGetScrInfo (PLW_GM_DEVICE pgmdev, PLW_GM_SCRINFO pgmsi){ UINT32 uiDevWidth = curDisplayDev.uiDevWidth; UINT32 uiDevHeight = curDisplayDev.uiDevHeight; if (pgmsi) { pgmsi->GMSI_pcName = "/dev/fb0"; pgmsi->GMSI_ulId = 0; /* * 内存区域大小设置 */ switch (curDisplayDev.uiStreamColorFormat) { …… case FORMAT_RGB565: pgmsi->GMSI_stMemSize = uiDevWidth * uiDevHeight * 2; pgmsi->GMSI_stMemSizePerLine = uiDevWidth * 2; break; …… } pgmsi->GMSI_pcMem = (caddr_t)GpvFbMemBase; } return (ERROR_NONE);}
3.2 timing配置
struct dev_panel_t { CHAR cPanelName[32]; UINT32 uiPanelId; #define COLORTYPE_4K (0) #define COLORTYPE_64K (1) #define COLORTYPE_256K (2) #define COLORTYPE_16M (3) UINT32 uiColorsType; #define FORMAT_YUV422 (0)#define FORMAT_YCBCR422 (1)#define FORMAT_RGB888 (2)#define FORMAT_RGB666 (3)#define FORMAT_RGB565 (4)#define FORMAT_RGB444_L (5)#define FORMAT_RGB332 (6)#define FORMAT_RGB444_H (7) UINT32 uiStreamColorFormat; UINT32 uiDevWidth; UINT32 uiDevHeight; UINT32 uiPixelClock; UINT32 uiHFrontPorch; UINT32 uiHBackPorch; UINT32 uiHSyncWidth; UINT32 uiVFrontPorch; UINT32 uiVBackPorch; UINT32 uiVSyncWidth; #define DATAWIDTH8or9 (0)#define DATAWIDTH16or18 (1) UINT32 uiDataBusWidth; #define MAPNORMAL (0)#define MAPJEIDA (1) UINT32 uiMappingMode; UINT32 uiDataInterlaced; UINT32 uiSyncInterlaced; UINT32 uiVerticalPol; UINT32 uiHorizontalPol; UINT32 uiDEPol; #define DEVICE_SYNC_YUV422 (0)#define DEVICE_SYNC_YUV444 (1)#define DEVICE_SYNC_UNIPAC (4)#define DEVICE_SYNC_EPSON (5)#define DEVICE_SYNC_HIGHCOLOR (6)#define DEVICE_MPU (7) UINT32 uiDevType; UINT32 uiGpioBlkEn; };typedef struct dev_panel_t __LCD_DEV_PANEL;typedef struct dev_panel_t* __PLCD_DEV_PANEL;
代码清单 6 E50A2V1的屏参
#define E50A2V1 (0)static __LCD_DEV_PANEL DEF_LCD_E50A2V1_800x480 = { "E50A2V1", E50A2V1, COLORTYPE_16M, FORMAT_RGB565, 800, 480, 3000000, 88, 40, 48, 32, 13, 3, DATAWIDTH16or18, MAPNORMAL, 0, 0, 0, 0, 0, DEVICE_SYNC_HIGHCOLOR, NUC970_GPIO_NUMR(__BANK_G, 3) };
- SylixOS的LCD驱动移植
- LCD驱动的移植
- SylixOS音频驱动移植
- 移植tiny210 的lcd驱动
- SylixOS SPI Flash驱动移植
- SylixOS基于Nuc970平台的SD驱动移植
- LCD驱动移植笔记
- 移植LCD驱动
- 6410 LCD驱动移植
- 6410 LCD驱动移植
- LCD驱动移植
- LCD 背光驱动移植
- OK6410 LCD驱动移植
- LCD驱动移植
- Wince LCD驱动移植
- wince lcd驱动移植
- s5pv210 LCD驱动移植
- AM1808 LCD驱动移植
- Good Study
- HTML简介
- JavaScript中的原型和继承
- zookeeper-通信协议
- 高清屏概念解析与检测设备像素比的方法
- SylixOS的LCD驱动移植
- unity3d 协程的初步理解 - 支持返回值/支持异常处理/支持泛型
- mysql的一些函数
- jquery对复选框(checkbox)的操作汇总
- Eclipse和对应的Jdk版本匹配
- zookeeper-系统模型
- Windows 一键安装 OpenSSL
- [使用 Weex 和 Vue 开发原生应用] 1 如何配置开发环境
- linux c之access方法介绍