高及驱动——四、framebuffer子系统(帧缓冲):lcd屏

=============================================

一、framebuffer子系统(帧缓冲):lcd屏

1,了解lcd屏的基础知识
2,framebuffer子系统框架
3,lcd驱动移植
4,linux启动logo的制作
5,framebuffer框架代码跟读
6,应用程序如何向lcd上显示数据

==================================================

一,了解lcd屏的基础知识

//参考:E:\peter\2010\高级驱动\5day\framebuffer研究.xls

二,framebuffer子系统框架

---------------------------------------------------------
fb通用层--------//drivers/video/fbmem.c
作用:
	1,与用户交互
	2,实现fops中的接口---mmap	

--------------------------------------------
lcd控制器层 ------//drivers/video/s3c-fb.c
作用: 
	1,初始化lcd控制器
	2,分配显存空间---dma

三,lcd驱动移植

1,lcd硬件连接

//参考:E:\peter\2010\高级驱动\5day\5day_photo\3_lcd硬件连接.tif

2,lcd时序分析 ---------Documentation/fb/framebuffer.txt

			soc:			lcd屏							驱动:
垂直方向:	
			VSPW 			tvpw   	1 < y < 20  y = 10		vsync_len
			VBPD 			tvb -tvpw  23 -y = 13			upper_margin
			LNEVAL 			tvd   		 480				yres
			VFPD			tvfp   		 22 				lower_margin
水平方向:
			HSPW			thpw	1 < x < 40 x = 20		hsync_len
			HBPD 			thb -thpw  46 -x = 26			left_margin
			HOZVAL			thd			 800				xres
			HFPD			thfp  		 210				right_margin

3,lcd参数设置 ------- //硬件差异化数据:pdev

arch/arm/mach-s5pv210/mach-smdkv210.c
			|
	static void __init smdkv210_machine_init(void)
						|
			s3c_fb_set_platdata(&smdkv210_lcd0_pdata);  //设置fb的自定义数据
									|
						static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
							.win[0]		= &smdkv210_fb_win0,	//lcd参数
												|
										static struct s3c_fb_pd_win smdkv210_fb_win0 = {
											.win_mode = {
												.left_margin	= 13,
												.right_margin	= 8,
												.upper_margin	= 7,
												.lower_margin	= 5,
												.hsync_len	= 3,
												.vsync_len	= 1,
												.xres		= 800,
												.yres		= 480,
											},
											.max_bpp	= 32,		//像素最大的颜色空间
											.default_bpp	= 24,	//缺省颜色空间值
										};
							.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
							.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,	//电平翻转
							.setup_gpio	= s5pv210_fb_gpio_setup_24bpp,
						};	

4,移植lcd驱动-----//修改自定义数据

arch/arm/mach-s5pv210/mach-smdkv210.c
			|
	static void __init smdkv210_machine_init(void)
						|
			s3c_fb_set_platdata(&smdkv210_lcd0_pdata);  //设置fb的自定义数据
									|
						static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
							.win[0]		= &smdkv210_fb_win0,	//lcd参数
													|
										static struct s3c_fb_pd_win smdkv210_fb_win0 = {
											.win_mode = {
												.left_margin	= 26,
												.right_margin	= 210,
												.upper_margin	= 13,
												.lower_margin	= 22,
												.hsync_len	= 20,
												.vsync_len	= 10,
												.xres		= 800,
												.yres		= 480,
											},
											.max_bpp	= 32,		//像素最大的颜色空间
											.default_bpp	= 16,	//缺省颜色空间值
										};

5,确保fb子系统两层相关代码被编译进内核镜像

make menuconfig
	Device Drivers  ---> 
		Graphics support  ---> 
			<*> Support for frame buffer devices  ---> 
				 <*>   Samsung S3C framebuffer support 
			Console display driver support  --->
				 <*> Framebuffer Console support
			[*] Bootup logo  ---> 
				[*]   Standard 224-color Linux logo (NEW) 

6,打开lcd的背光

背光:gpd0_0
arch/arm/mach-s5pv210/mach-smdkv210.c
|
static void __init smdkv210_machine_init(void)
//打开lcd的背光
gpio_request(S5PV210_GPD0(0), “lcd_gpd0_0”);
gpio_direction_output(S5PV210_GPD0(0), 1);
gpio_free(S5PV210_GPD0(0));

7,编译内核,并更新

make -j2 zImage
cp arch/arm/boot/zImage /tftpboot/

8,重启开发板,观察结果:

在lcd屏的左上角可以看到一个小企鹅的图标,说明驱动移植OK

四,linux启动logo的制作

1,准备一张需要做成logo的图片,并将图片转换为ppm格式

1》在Windows中安装格式转换工具gimp 
	1)安装:
		gtk+-2.10.13-setup.exe
		
	2)安装: 
		gimp-2.2.17-i586-setup.exe

2》打开gimp工具,在gimp中打开要制作的图片,然后修改格式
	
	1)修改图片的大小
		--->图像
			---->缩放图像
				---->图像大小: 800 * 480 
				
	2)修改颜色空间
		--->图像
			---->模式
				----->索引
					---->最大颜色数量:224
	3)图片另存为,同时修改格式
		--->文件
			---->另存为
				----->选择文件类型: ppm  ,点击保存
					------->数据格式:ascii

2,将图片编译进内核中

1》将制作好的图片拷贝到:drivers/video/logo/ 并修改图片的名称,如下:
	logo_fegnj_clut224.ppm
	
2》修改drivers/video/logo/中的Makefile文件,
	添加一行: 
		 7 obj-$(CONFIG_LOGO_FENGJ_CLUT224)    += logo_fengj_clut224.o

3》修改drivers/video/logo/中Kconfig文件
	添加下面几行: 
		 30 config LOGO_FENGJ_CLUT224
		 31     bool "test Linux logo for fs210"
		 32     help
		 33         test lcd logo
4》执行make menuconfig 
		
	make menuconfig 
		Device Drivers  --->
			Graphics support  ---> 
				[*] Bootup logo  --->
					[*]   test Linux logo for fs210
5》编译内核: 
	farsight@ubuntu:~/fs210/linux-3.0.8$ make -j2 zImage
	scripts/kconfig/conf --silentoldconfig Kconfig
	  CHK     include/linux/version.h
	  CHK     include/generated/utsrelease.h
	make[1]: `include/generated/mach-types.h' is up to date.
	  CALL    scripts/checksyscalls.sh
	  CHK     include/generated/compile.h
	  LOGO    drivers/video/logo/logo_fengj_clut224.c	//生成图片对应的.c文件
	  CC      drivers/video/logo/logo_fengj_clut224.o	//编译.c文件生成.o
	  LD      drivers/video/logo/built-in.o
				
//logo_fengj_clut224.c中会创建一个图片对应的结构体:
const struct linux_logo logo_fengj_clut224 __initconst = {
	.type       = LINUX_LOGO_CLUT224,
	.width      = 800,
	.height     = 480,
	.clutsize   = 224,
	.clut       = logo_fengj_clut224_clut,
	.data       = logo_fengj_clut224_data
};

3,在内核中指定启动时,加载哪个图片作为logo

1》修改 drivers/video/logo/logo.c 

	增加下面几行:
		 70 #ifdef CONFIG_LOGO_FENGJ_CLUT224
		 71         /* test  logo */
		 72         logo = &logo_fengj_clut224;
		 73 #endif
		 
2》修改 include/linux/linux_logo.h
	增加下面一行: 
		38 extern const struct linux_logo logo_fengj_clut224;
		
3》重新编译内核,并更新
	make -j2 zImage
	cp arch/arm/boot/zImage /tftpboot/
	
4》重启开发板,观察结果:
	lcd屏整个屏幕上会显示出新的图片

五,framebuffer框架代码跟读

fb通用层:drivers/video/fbmem.c

	module_init(fbmem_init);
					|
		static int __init fbmem_init(void)
		{
			1,在/proc目录中创建驱动相关的文件
				proc_create("fb", 0, NULL, &fb_proc_fops);
				
			2,申请设备号,主:29
				if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
														|
								static const struct file_operations fb_fops = {
									.mmap =		fb_mmap,
													|
										static int fb_mmap(struct file *file, struct vm_area_struct * vma)
										{
											
											unsigned long start;
											//1,获取显存的物理地址
											start = info->fix.smem_start;   
											
											//2,初始化vma
											vma->vm_pgoff = off >> PAGE_SHIFT;
											/* This is an IO map - tell maydump to skip this VMA */
											vma->vm_flags |= VM_IO | VM_RESERVED;
											vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
											fb_pgprotect(file, vma, off);
											
											//3,将显存空间映射到用户的虚拟空间
											if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
														 vma->vm_end - vma->vm_start, vma->vm_page_prot))
										}
								}
					
			3,创建类
				fb_class = class_create(THIS_MODULE, "graphics");
		}
----------------------------------------------------------------------------
lcd控制器层 : drivers/video/s3c-fb.c

module_init(s3c_fb_init);
				|
	static int __init s3c_fb_init(void)
						|
			return platform_driver_register(&s3c_fb_driver);
												|
					static struct platform_driver s3c_fb_driver = {
						.probe		= s3c_fb_probe,
										|
						static int __devinit s3c_fb_probe(struct platform_device *pdev)
						{
							// 1,获取平台数据
							pd = pdev->dev.platform_data;
							
							// 2,分配struct s3c_fb对象空间
							struct s3c_fb *sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
							
							// 3,时钟使能
							sfb->bus_clk = clk_get(dev, "lcd");
							clk_enable(sfb->bus_clk);
							
							// 4,获取平台地址资源,并映射地址
							res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
							sfb->regs = ioremap(res->start, resource_size(res));
							
							// 5,获取中断资源,申请中断
							res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
							sfb->irq_no = res->start;
							ret = request_irq(sfb->irq_no, s3c_fb_irq, 0, "s3c_fb", sfb);
							
							// 6,设置lcd相关的gpio 
							pd->setup_gpio();
							
							// 7,翻转电平
							writel(pd->vidcon1, sfb->regs + VIDCON1);
							
							// 8,初始化lcd控制器
							ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],&sfb->windows[win]);
										|
									1,初始化等待队列头
									init_waitqueue_head(&sfb->vsync_info.wait);
									
									2,实例化struct fb_info对象
									struct fb_info *fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +palette_size * sizeof(u32), sfb->dev);
									struct fb_info {
										struct fb_var_screeninfo var;	/* Current var ----可变参数,与lcd屏相关 */
										struct fb_fix_screeninfo fix;	/* Current fix ----固定参数,与soc相关*/
									}
									
									3,分配显存空间,并初始化dma
									ret = s3c_fb_alloc_memory(sfb, win);
												|
										// 1,计算显存大小
										size = (real_size > virt_size) ? real_size : virt_size;
										size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
										size /= 8;

										fbi->fix.smem_len = size;
										size = PAGE_ALIGN(size);
										
										// 2,分配显存空间:返回显存映射到内核中的虚拟地址,同时返回显存的物理地址给map_dma
										fbi->screen_base = dma_alloc_writecombine(sfb->dev, size, &map_dma, GFP_KERNEL);
										
										// 3,初始化显存空间
										memset(fbi->screen_base, 0x0, size);
										
										// 4, 将显存的物理地址给:fbi->fix.smem_start
										fbi->fix.smem_start = map_dma;
										
									4,设置可变参数和固定参数
									fb_videomode_to_var(&fbinfo->var, initmode);
												|
										var->xres = mode->xres;
										var->yres = mode->yres;
										var->xres_virtual = mode->xres;
										var->yres_virtual = mode->yres;
										var->xoffset = 0;
										var->yoffset = 0;
										var->pixclock = mode->pixclock;
										var->left_margin = mode->left_margin;
										var->right_margin = mode->right_margin;
										var->upper_margin = mode->upper_margin;
										var->lower_margin = mode->lower_margin;
										var->hsync_len = mode->hsync_len;
										var->vsync_len = mode->vsync_len;
										var->sync = mode->sync;
										var->vmode = mode->vmode & FB_VMODE_MASK;
									fbinfo->fix.type	= FB_TYPE_PACKED_PIXELS;
									fbinfo->fix.accel	= FB_ACCEL_NONE;
									fbinfo->var.activate	= FB_ACTIVATE_NOW;
									fbinfo->var.vmode	= FB_VMODE_NONINTERLACED;
									fbinfo->var.bits_per_pixel = windata->default_bpp;
									fbinfo->fbops		= &s3c_fb_ops;
									fbinfo->flags		= FBINFO_FLAG_DEFAULT;
									fbinfo->pseudo_palette  = &win->pseudo_palette;
									
									5,初始化lcd控制器
									s3c_fb_set_par(fbinfo);
											|
										data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
										writel(data, regs + VIDCON0);

										data = VIDTCON0_VBPD(var->upper_margin - 1) |
											   VIDTCON0_VFPD(var->lower_margin - 1) |
											   VIDTCON0_VSPW(var->vsync_len - 1);

										writel(data, regs + sfb->variant.vidtcon);

										data = VIDTCON1_HBPD(var->left_margin - 1) |
											   VIDTCON1_HFPD(var->right_margin - 1) |
											   VIDTCON1_HSPW(var->hsync_len - 1);

										/* VIDTCON1 */
										writel(data, regs + sfb->variant.vidtcon + 4);

										data = VIDTCON2_LINEVAL(var->yres - 1) |
											   VIDTCON2_HOZVAL(var->xres - 1);
										writel(data, regs + sfb->variant.vidtcon + 8);
									6,注册struct fb_info对象
									ret = register_framebuffer(fbinfo);
												|
											ret = do_register_framebuffer(fb_info);
											{
												// 1,在数组registered_fb找到一个空的位置
												for (i = 0 ; i < FB_MAX; i++)
													if (!registered_fb[i])
														break;
												// 2,创建设备节点
												fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
												
												// 3,将fbinfo对象保存到数组:registered_fb
												registered_fb[i] = fb_info;
											}
												
						}
						
					};		

六,应用程序如何向lcd上显示数据

/*1.打开一副图片*/
pic_fd =open(argv[2],O_RDWR);
printf("pic_fd=%d\n",pic_fd);

/*2.获取图片大小*/
len =lseek(pic_fd, 0, SEEK_END);
printf("len =%ld\n",len);

/*分配空间保存图片的数据*/
buffer =(char *)malloc(len);

lseek(pic_fd, 0, SEEK_SET);
/*3.读取图片数据*/
read(pic_fd,buffer,len); 

/*4.打开帧缓冲设备*/
framebuffer_fd =open(dev_name,O_RDWR);


/*5.获取固定参数*/
if(ioctl(framebuffer_fd,FBIOGET_FSCREENINFO,&finfo))
{
	printf("Error:failed get the framebuffer device`s fix informations!\n");
	return -1;
}

/*6.获取可变参数*/
if(ioctl(framebuffer_fd,FBIOGET_VSCREENINFO,&vinfo))
{
	printf("Error:failed get the framebuffer device`s var informations!\n");
	return -1;
}


printf("xres =%ld\n",vinfo.xres);
printf("yres =%ld\n",vinfo.yres);
/*7,计算一帧数据的长度(byte)*/
screensize =(vinfo.xres *vinfo.yres*vinfo.bits_per_pixel/8);
printf("screensize =%ld\n",screensize);

/*8.映射*/
framebuffer_ptr =(char *)mmap(  NULL,//如果此值为NULL,则表示用内核来自动给你分配一块虚拟空间
						     screensize,		//空间大小
						     PROT_READ|PROT_WRITE,//权限
						     MAP_SHARED,		//是否可以共享
						     framebuffer_fd,		//文件描述符
						     0);			//从哪个地方开始
/*9.清空映射的空间*/
memset(framebuffer_ptr,0,screensize);

/*10.向lcd屏上显示图片或者文字*/
while(1)
{
	printf("选择要显示图片还是文字:1-图片,2-文字");
	scanf("%d",&key);
	switch(key)
	{
		case 1:
			/*2.7 显示图片*/
			printf("test picture!\n");
			
			printf("loadjpeg00000!!!!\n");
			draw_bmp(buffer,(unsigned short *) framebuffer_ptr);
			break;
		case 2:
			/*2.8 显示字符*/
			
			length1 =sizeof(string1);
			length2 =sizeof(string2);
			printf("length1 =%d\n",length1);
			Display_character(140,100,length1,string1);
			Display_character(140,120,length2,string2);	
			break;
		default:
			break;
	}	
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值