LCD加入双缓冲

来源:互联网 发布:台州椒江区网络诈骗 编辑:程序博客网 时间:2024/05/29 19:23

LCD加入双缓冲
为了提高LCD的显示效果,如果只是使用单缓冲,即一帧数据作为缓冲区的话,就会出现写数据的时候有闪屏现象,为了解决这个问题,
我们为LCD缓冲区设置了两个帧的大小,这样如果此时LCD控制器帧缓冲区地址指向的是第一帧的数据的话我们可以写第二帧数据,
写完以后把第二帧的首址赋给LCD控制器,S3C2410A中有专门的LCDDMA,所有我们只要在内存把帧缓冲区内存设为DMA格式的内存,LCD
控制器就会自动发送,当然我们要写寄存器控制显示的频率。在使用时我们要和用户程序结合起来,用户程序映射缓冲区的时候也要映射两个帧的
大小

下面是修改LCD驱动的过程。
我们使用的是linux2.6.35.13中内核中原有的LCD驱动,
首先在fb.h修改fb_info结构体
这个结构体包含了framebuffer以后LCD的所有信息
我们加入 unsigned long smem_start_buffer;//开始缓冲区物理地址
这个元素的作用后面会提到。
然后设置yres_virtual
在static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
          struct fb_info *info)
函数中修改为var->yres_virtual = display->yres*2;//modiby bu xiaohe
这个是提供给framebuffer驱动说明使用了虚拟y坐标,如果不设置我们没法通过后来的程序修改LCD控制器帧缓冲区的地址

之后修改static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
      enum s3c_drv_type drv_type)
函数中的fbinfo->fix.ypanstep     = 1;//modify bu xiaohe

在函数static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)中
给info->smem_start_buffer=map_dma;赋值,这个值的作用就是存储要赋给LCD帧缓冲区地址的地址

在函数static void s3c2410fb_set_lcdaddr(struct fb_info *info)
中修改要赋给LCD帧缓冲区地址的地址,修改info->fix.smem_start为 info->smem_start_buffer
如:
saddr1  = info->smem_start_buffer >> 1;
saddr2  = info->smem_start_buffer;
这里说明一下:
fix结构体的smem_start和fb_info结构体的screen_base,以后表示分配的DMA缓冲区的物理地址和虚拟地址,两个地址
都在framebuffer驱动中映射给了用户空间,所以我们不能使用它们作为LCD帧缓冲区地址(默认的使用smem_start),
所以我另加了一个fb_info结构体元素smem_start_buffer,也就是在处理双缓冲的函数中只改变这个值就OK了。

再之后在static struct fb_ops s3c2410fb_ops 结构体中加入双缓冲的处理函数
.fb_pan_display =mvfb_pan_display,
函数内容如下:
//fb->screen_base_start//虚拟起始地址
//info->smem_start_star;//存储内存分配的DMA起始地址
//int yoffset_origin;//存储上一次的y偏移地址
static int mvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
{
 //printk("fb->smem_start_buffer %x\n",fb->smem_start_buffer);
 if(var->yoffset==var->yres)//第二帧地址
 {
  fb->smem_start_buffer=fb->fix.smem_start+var->yres*var->xres*2;
 }
 else//第一帧地址
 {
  if(var->yoffset>=0&&var->yoffset<var->yres)
  {
   fb->smem_start_buffer=fb->fix.smem_start+var->xres*2*var->yoffset;
  }
 } 
 s3c2410fb_lcd_enable(fb->par, 0);//关闭LCD
 s3c2410fb_set_lcdaddr(fb);//设置帧缓冲区起始地址
 s3c2410fb_lcd_enable(fb->par, 1);//启动LCD
 //printk("fb->smem_start_buffer %x\n",fb->smem_start_buffer);
 return 0;
}
这时候就可以通过
if (ioctl(fd,FBIOPAN_DISPLAY, &fb_vinfo)) {////返回framebuffer可变信息
  perror(__func__);
  return (-1);
}
来传递var结构体参数,它里面包含我们要设置的yoffset,我们写屏之后通过这个函数来改变帧缓冲区起址。
这样就实现了我们在用户程序映射两个帧空间后先写入想要写入的区域,然后在改变yoffset,消除闪屏的现象。
我们页可以不使用双缓冲,只要写入的位置与yoffset相同,就会和使用单缓冲效果一样。

不足:
s3c2410中的LCD控制器已经实现了硬件上的虚拟显示,而我这个并没有使用,只是软件上的双缓冲,同时没有使用xoffset,由于时间的原因就先不加了。

原创粉丝点击