平顶山学院信息工程学院 张亚峰 王 冠
基于ARM的LCD显示液晶屏驱动的开发
平顶山学院信息工程学院张亚峰王冠
通过对LCD控制器各个子模块的研究,并对FrameBuffer在LCD的作用进行详细的分析,对于硬件引脚、驱动的端口及寄存器等进行设置,将驱动添加到内核,最终实现了基于ARM的LCD液晶屏驱动,使内核的启动信息在显示器上显示出来。
嵌入式系统;LCD液晶屏驱动;Exynos 4412处理器
随着信息技术的高速发展,人们使用的设备的智能化,与嵌入式系统在其中发挥的重要作用密不可分。虽然嵌入式系统的交互性比较强,液晶屏作为输出设备也被广泛应用,但关于液晶屏的深层次应用开发方面的研究却不多。本文通过对LCD显示液晶屏驱动的研究,加深对其认识,对其相关研究、开发材料加以补充。
本次开发使用的环境为ADS1.2,其具有强大的实时调试跟踪功能。使用的开发平台为Tiny4412。它是一款高性能的四核Cortex-A9核心板,处理器为Exynos 4412,具有极高的灵活性,三星Galaxy部分机型就采用该CPU设计。
Exynos4412的LCD 控制器由REGBANK、LCDCDMA、VIDPRCS、TIMEGEN组成,并有专门的端口来传送控制信号和其它数据。
REGBANK 有许多可编程寄存器组,它们用来配置LCD 控制器的调色板存储器。LCDCDMA 是一个专用DMA,并且是FIFO(First-In First-Out, 先入先出)存储器,它会自动传送帧数据到LCD 驱动器。TIMEGEN 由可编程逻辑组成,支持各种常见LCD 驱动器的定时与速率界面的不同要求。TIMEGEN 模块产生FRAME, VLINE, VCLK, VM 等信号。
3.1FrameBuffer的介绍
Framebuffer在LCD的驱动实现中起着中间层的作用,它将内存数据映射到进程地址空间之后,就可以直接进行读写操作,并立即反应在屏幕上[1]。它还完成对驱动的统一管理,向fbmem.c注册是任何一个FrameBuffer驱动在系统初始化时必须做的工作[2]。注册时,设备的驱动信息保存在一个数组体中。
struct dev_message *reg[ max]; / * 定义数组 */
int reg_num; /* 设备数量 */
int reg_fb(struct dev_message * reg)
{
int x;
struct dev_thing thing;
struct dev_thing *cur;
if (reg_num >= max)
exit;
……………………
return 0;
}
3.2LCD驱动实现代码分析
3.2.1设置fb_info
(1)申请和释放资源
在初始函数运行时,需要申请相应的资源;在程序运行结束时,要释放相应的资源,以免造成系统的资源浪费[3]。因此定义下面的函数:
Mod_init(Exyons_init); /* 申请资源 */
Mod_quit(Exyons_quit); /* 释放资源 */
定义fb_info结构体对象:
static struct fb_info*Exyons_lcd;
分配一个fb_info结构体,使用函数framebuffer_alloc实现:
Exyons_lcd = framebuffer_alloc(0,NULL);
(2)可变信息设置
Exyons_lcd -> var.xres = 800;
Exyons_lcd -> var.yres = 480;
Exyons_lcd -> var.xres_virtual = 800;
Exyons_lcd -> var.yres_virtual = 480;
然后进行红、绿、蓝三种颜色的设置和每一个像素用多少位的设置。
设置完上面的这些已经可以实现LCD的显示了。其他表示可变信息的设置根据需要进行。
(3)显存的分配
对显示屏的操作,是一个存储器的操作,可以直接访问应用程序的内存,它可以实现LCD的操作,通过应用数据到内存,然后LCD控制器从存储器中提取数据,并输出相应的LCD控制芯片,使实现LCD的控制[4]。
(4)设置其它信息
首先,设置LCD屏幕的大小,用字节来表示:
Exyons_lcd->screen_size = 800*480*32 / 8;
然后,调色板设置:
Static u32 colregs[16]; /* 代表了一个假的调色板 */
Exyons_lcd->pseudo_palette = colregs; /* 赋值操作完成设置 */
3.2.2设置LCD硬件
对LCD的硬件进行设置要参考芯片手册和LCD手册进行获得设置值。
(1)设置用于LCD的引脚
这个寄存器可以全部用来进行LCD颜色控制引脚。
控制LCD电源的引脚受GPGCON寄存器控制,手册中GPGCON寄存器的描述如表1所示:
表1 GPGCON寄存器
LCD电源控制引脚设置如表2所示:
表2 电源控制引脚描述
代码的具体实现如下:
int *gpccon;
int *gpdcon;
int *gpgcon; /*构建这三个寄存器的表示指针变量*/
*gpccon = 0xaaaaaaaa;
*gpdcon = 0xaaaaaaaa;
*gpgcon | = (3<<8); /*通过这三个寄存器,设置用于控制LCD的引脚*/
(2)LCD寄存器对象的构建
采用建立数组的方法对LCD的控制寄存器进行一次性映射成为虚拟地址,虽然在当下有些寄存器暂时还未被使用到,我们也把它们设置到这个数组中,这样做可以保证所有寄存器地址的连续性,使对寄存器的操作变得方便。完成这项工作后,就可以通过操纵该数组元素的指针来操纵相应的寄存器[5]。
(3)设置控制寄存器1(LCDCON1)
LINECNT:行计数器状态位,初始值为0000000000;
CLKVAL:设置VCLK,初始值为0000000000;
MMODE:决定VM信号的触发速率[6],初始值为0;PNRMODE:显示模式选择位,初始值为00;
BPPMODE:单个像素的位数选择,初始值为0000;
ENVID:视频输出和控制信号设置,初始值为0,在此置1,使信号有效。
(4)LCD垂直参数设置
参考芯片手册和LCD手册进行获得设置值:
VBPD=14;LINEVAL=239;VFPD=11;VSPW=2;
代码实现设置:
Exyons_lcd_regs->lcdcon2 = (14<<24)|(239<<14)|(11<<6)|(2<<0);
(5)LCD水平参数设置
HBPD=25;HOZVAL=213;HFPD=34;HSPW=18;
代码实现设置:
Exyons_lcd_regs->lcdcon3 = (37<<19)|(319<<8)|(19<<0);
Exyons_lcd_regs->lcdcon4 = 29;
(6)设置使能有效位
代码实现设置:
Exyons_lcd_regs->lcdcon5 = (1<<10)|(1<<9) | (1<<8) | (1<<5) |(0<<3);
(7)显存地址告诉LCD控制器
功能实现代码:
Exyons_reg -> lcdsdr1 = (Exyons_lcd -> fix_start >> 3);
Exyons_reg->lcdsdr2=((Exyons_lcd->fix_start+800*480*4)>>1)&0x1fffff;
Exyons_lcd_regs->lcdsaddr3 =800*480/2;
3.2.3 注册fb_info
(1)设置使能LCD
将寄存器LCDCON1的第0为设置为1:
Exyons_lcd_regs -> lcdcon1 | = (1 << 0);
(2)向上注册fb_info结构体对象
register_framebuffer(Exyons_lcd);
3.3添加驱动到内核
对于已有的驱动模块可以直接使用。实现fb_ops结构体时,有三个文件:cfbcopyarea.c、cfbfillrect.c和cfbimgblt.c已经存在但没有被编译安装,因此我们需要修改内核drivers/video下的Makefile,重新编译内核,就能让LCD正常工作[7]。操作如表1所示:
表3 Makefile文件修改内
再次编译内核,重新启动系统。效果如图1所示:
图1 加载LCD成功后的启动效果
在开发的过程中,通过对Tiny4412的硬件平台、LCD芯片手册及CPU芯片的寄存器的研究,分析LCD驱动内核层次,利用FrameBuffe实现了对驱动的管理和消息的分派;然后通过设置fb_ info对象和LCD硬件,进行fb_info注册;最后添加驱动到内核,成功实现了内核的启动信息在启动时通过LCD显示器打印出来。
[1]刘艺柱,郭素娜.ARM嵌入式系统基础[J].河南理工大学学报,2010,29(2):229-232.
[2]赖晓晨.嵌入式系统编程与设计[M].北京:清华大学出版社,2009.
[3]王华祥,张淑英.深入浅出:嵌入式底层软件开发[M].天津:天津大学出版社,2003.
[4]赵以强.嵌入式系统开发之道[M].北京:人民邮电出版,2009.
[5]武斌,张一哲.嵌入式工程师必知必会[M].北京:人民邮电出版,2008.
[6]甘瑟尔.嵌入式系统设计的艺术(第2版)[M].北京:北京人民邮电出版社,2011.
[7]林洪贵,林金表.21天学通ARM嵌入式开发[J].莆田学院学报,2007,14(5):63-65.