本文转载自:http://blog.csdn.net/liuzijiang1123/article/details/46972723

如想想对lcd屏进行操作(例如在lcd屏幕上画线,或者显示视频数据),我们就必须得了framebuffer(帧缓冲),网上各种百度,大多都说的很官方,至少很难找到那些让人觉得很生动的描述,让我们这些出入门的菜鸟能好好了解一下。 下面就是我结合老师的指点和论坛上的解释再加上自己的理解写的一些东西。

************************************************************************************************************************************************************************************

很多人都会说操纵lcd显示就是操纵framebuffer,表面上来看是这样的。实际上是frambuffer就是Linux内核驱动申请的一片内存空间,然后lcd内有一片sram,cpu内部有个lcd控制器,它有个单独的dma用来将frambuffer中的数据拷贝到lcd的sram中去 拷贝到lcd的sram中的数据就会显示在lcd上,
LCD驱动和framebuffer驱动没有必然的联系,它只是驱动LCD正常工作的,比如有信号传过来,那么LCD驱动负责把信号转成显示屏上的内容,至于什么内容,怎么显示,它根本不关心也不知道。

*************************************************************************************************************************************************************************************
百度上framebuffer的解释:帧缓冲是Linux为显示设备提供的一个接口,它把一些显示设备描述成一个缓冲区,允许应用程序通过 FrameBuffer定义好的接口访问这些图形设备,从而不用去关心具体的硬件细节。
 
(经过我的解释,我们是不是可以好一点理解了呢?上面的显示设备就是lcd呀,framebuffer不就是一个临时存放数据的区域)其在文件系统中对应的设备名称为/dev/fb(0,1,2,3....31最大允许32个fb,主设备号是29)
*************************************************************************************************************************************************************************************
(下面插上一幅图来更形象的解释)
我们从上面这幅图看,帧缓冲设备在Linux中也可以看做是一个完整的子系统,大体由fbmem.c和xxxfb.c组成。向上给应用程序提供完善的设备文件操作接口(即对FrameBuffer设备进行read、write、ioctl等操作),接口在Linux提供的fbmem.c文件中实现;向下提供了硬件操作的接口,只是这些接口Linux并没有提供实现,因为这要根据具体的LCD控制器硬件进行设置,所以这就是我们要做的事情了(即xxxfb.c 部分的实现)。
说了这么多,我感觉应该要用一些实例在说说,到底如何在lcd上画线呢?(这个也是老师给我的任务)
****************************************************************************************************************************************************************************************
[cpp] view plaincopy print?
  1. #include <stdlib.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <fcntl.h>
  5. #include <linux/fb.h>
  6. #include <linux/kd.h>
  7. #include <sys/mman.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/time.h>
  10. #include <string.h>
  11. #include <errno.h>
  12. struct fb_var_screeninfo vinfo;
  13. struct fb_fix_screeninfo finfo;
  14. char *frameBuffer = 0;
  15. //打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。
  16. void printFixedInfo ()
  17. {
  18. printf ("Fixed screen info:\n"
  19. "\tid: %s\n"
  20. "\tsmem_start:0x%lx\n"
  21. "\tsmem_len:%d\n"
  22. "\ttype:%d\n"
  23. "\ttype_aux:%d\n"
  24. "\tvisual:%d\n"
  25. "\txpanstep:%d\n"
  26. "\typanstep:%d\n"
  27. "\tywrapstep:%d\n"
  28. "\tline_length: %d\n"
  29. "\tmmio_start:0x%lx\n"
  30. "\tmmio_len:%d\n"
  31. "\taccel:%d\n"
  32. "\n",
  33. finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
  34. finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
  35. finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
  36. finfo.mmio_len, finfo.accel);
  37. }
  38. //打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置
  39. void printVariableInfo ()
  40. {
  41. printf ("Variable screen info:\n"
  42. "\txres:%d\n"
  43. "\tyres:%d\n"
  44. "\txres_virtual:%d\n"
  45. "\tyres_virtual:%d\n"
  46. "\tyoffset:%d\n"
  47. "\txoffset:%d\n"
  48. "\tbits_per_pixel:%d\n"
  49. "\tgrayscale:%d\n"
  50. "\tred: offset:%2d, length: %2d, msb_right: %2d\n"
  51. "\tgreen: offset:%2d, length: %2d, msb_right: %2d\n"
  52. "\tblue: offset:%2d, length: %2d, msb_right: %2d\n"
  53. "\ttransp: offset:%2d, length: %2d, msb_right: %2d\n"
  54. "\tnonstd:%d\n"
  55. "\tactivate:%d\n"
  56. "\theight:%d\n"
  57. "\twidth:%d\n"
  58. "\taccel_flags:0x%x\n"
  59. "\tpixclock:%d\n"
  60. "\tleft_margin:%d\n"
  61. "\tright_margin: %d\n"
  62. "\tupper_margin:%d\n"
  63. "\tlower_margin:%d\n"
  64. "\thsync_len:%d\n"
  65. "\tvsync_len:%d\n"
  66. "\tsync:%d\n"
  67. "\tvmode:%d\n"
  68. "\n",
  69. vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,
  70. vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel,
  71. vinfo.grayscale, vinfo.red.offset, vinfo.red.length,
  72. vinfo.red.msb_right,vinfo.green.offset, vinfo.green.length,
  73. vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length,
  74. vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length,
  75. vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate,
  76. vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock,
  77. vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin,
  78. vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len,
  79. vinfo.sync, vinfo.vmode);
  80. }

下面才是我们的重点,这个代码是我自己参考别人画矩形的代码改过来的

[cpp] view plaincopy print?
  1. //画一条直线
  2. void drawline_rgb16 (int x0,int y0, int width,int height, int color,int flag0)
  3. {
  4. const int bytesPerPixel = 2;//因为是rgb16,用16位来描述色深,所以2个字节
  5. const int stride = finfo.line_length / bytesPerPixel;,一行有多少个点
  6. const int red = (color & 0xff0000) >> (16 + 3);//下面是颜色的操作,我目前还没弄明白
  7. const int green = (color & 0xff00) >> (8 + 2);
  8. const int blue = (color & 0xff) >> 3;
  9. const short color16 = blue | (green << 5) | (red << (5 +6));
  10. int flag=flag0;//这里我为了图个方便就用一个flag来区分是画横线还是竖线,0表示横线,1表示竖线。
  11. short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);//这个就是我们画点的起始位置,其+stride就是换行(这个是我个人通过代码测试得出来的结论)
  12. int x=0,y=0;
  13. if(flag==0)
  14. {
  15. for (x = 0; x < width; ++x)//width就是我们x方向的终点
  16. {
  17. dest[x] = color16;
  18. }
  19. }
  20. else if(flag==1)
  21. {
  22. for(y=0;y<height;y++)//height就是我们y方向的终点
  23. {
  24. dest[x]=color16;//这里x始终为0,和下面一句结合起来就是每一行就画一个点,一共画height行,不就是一条竖线了么,这里我还思考了很久。
  25. dest +=stride;
  26. }
  27. }
  28. }

解释:我的屏的lcd分辨率是480*272,分辨率的意思是一行有480个点,一共有272行,其实屏蔽上都是一个个点组成的,在上面画线的意思并不是真正意思上的拿一支笔画线。打个比方来说你你把一行中80-180个点都改成红色(我们屏蔽不是黑色么),改完你就可以看见一条红线了,感觉就是画了一条红色的直线对不对?
而且“上色”是从左到右一个点一个点,一行一行“上色”的,屏幕的坐标系如下图所示:
[cpp] view plaincopy print?
  1. short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);

上面这一行代码的具体意思就是定位到(x0,y0)这个坐标,也就是我们要画的其实位置

可以下面这个代码画一个矩形。
[cpp] view plaincopy print?
  1. //画大小为width*height的同色矩阵,5reds+6greens+5blues
  2. void drawRect_rgb16 (int x0, int y0, int width,int height, int color)
  3. {
  4. const int bytesPerPixel = 2;
  5. const int stride = finfo.line_length / bytesPerPixel;
  6. const int red = (color & 0xff0000) >> (16 + 3);
  7. const int green = (color & 0xff00) >> (8 + 2);
  8. const int blue = (color & 0xff) >> 3;
  9. const short color16 = blue | (green << 5) | (red << (5 +6));
  10. short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);
  11. int x, y;
  12. for (y = 0; y < height; ++y)
  13. {
  14. for (x = 0; x < width; ++x)
  15. {
  16. dest[x] = color16;
  17. }
  18. dest += stride;
  19. }
  20. }
下面是main函数:
[cpp] view plaincopy print?
  1. int main (int argc, char **argv)
  2. {
  3. const char *devfile = "/dev/fb0";
  4. long int screensize = 0;
  5. int fbFd = 0;
  6. /* Open the file for reading and writing */
  7. fbFd = open (devfile, O_RDWR);
  8. if (fbFd == -1)
  9. {
  10. perror ("Error: cannot open framebuffer device");
  11. exit (1);
  12. }
  13. //获取finfo信息并显示
  14. if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)
  15. {
  16. perror ("Error reading fixed information");
  17. exit (2);
  18. }
  19. printFixedInfo ();
  20. //获取vinfo信息并显示
  21. if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)
  22. {
  23. perror ("Error reading variable information");
  24. exit (3);
  25. }
  26. printVariableInfo ();
  27. /* Figure out the size of the screen in bytes */
  28. screensize = finfo.smem_len;//fb的缓存长度
  29. /* Map the device to memory */
  30. frameBuffer =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbFd, 0);
  31. if (frameBuffer == MAP_FAILED)
  32. {
  33. perror ("Error: Failed to map framebuffer device to memory");
  34. exit (4);
  35. }
  36. //drawRect_rgb16 (vinfo.xres *3 / 8, vinfo.yres * 3 / 8,vinfo.xres / 4, vinfo.yres / 4,0xff00ff00);//实现画矩形
  37. drawline_rgb16(50,80,260,0,0xffff0000,0);
  38. drawline_rgb16(160,10,0,180,0xff00ff00,1);//可以画出一个交叉的十字,坐标都是自己设的。
  39. sleep (2);
  40. printf (" Done.\n");
  41. munmap (frameBuffer, screensize);   //解除内存映射,与mmap对应
  42. close (fbFd);
  43. return 0;
  44. }

用一个流程图还说明一下mian函数吧

*****************************************************************************************************************************************************************************************
****************************************************************************************************************************************************************************************
这里最重要的就是mmap这个函数了
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。
len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
     prot参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问)。
    flags由以下几个常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
 如果指定为MAP_SHARED,则对映射的内存所做的修改同样影响到文件。如果是MAP_PRIVATE,则对映射的内存所做的修改仅对该进程可见,对文件没有影响。
     offset参数一般设为0,表示从文件头开始映射。
mmap使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
再来看看我们代码中的mmap的实例
frameBuffer =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbFd, 0);

前面我们不是说了frambuffer就是linux内核驱动申请的一片内存空间,lcd驱动将frambuffer的地址通过mmap()将这片内存映射到应用程序空间,这样我们写入到fb的数据就写入到内核驱动里的frambuffer中去了,而lcd 的dma就将这些数据写入到lcd的sram中,从而显示在lcd上.

*****************************************************************************************************************************************************************************************
下面是效果图:
 
这里只是简单的入门而已,对于具体的lcd和framebuffer的联系,还是要参考具体的驱动代码的,今天就分析到这里。
**********************************************************************************************************************************************************
而且对于linux中的子系统驱动这个还不是很清楚,我会在下去再自己总结一下,然后再写一篇文章来介绍一下。
这里我再小小的说明一下,最近再去了解一下内核的驱动框架,慢慢知道了原来有很多控制器,这些控制器再来控制设备。i2c就有i2c控制器,lcd也有lcd控制器....我开始也不明白,为啥驱动还有驱动控制器呢?
后来才知道因为cpu其实很小,上面根本没有那么多外设,就只有很数据线,地址线,和控制线,一些寄存器,还有DMA,在这些线上挂着一些外设的控制器,用此与外设来进行“通信”,进行数据交换,控制器也相当于一条总线,上面还挂着的设备,就这样一层套一层,“嵌套现象很严重啊”,控制器与外设之间又有一个核心层来进行交流....哇,好复杂!!!

framebuffer的入门介绍-实现程序分析【转】相关推荐

  1. 静态程序分析chapter3 - 数据流分析详述(Reaching Definitions、Live Variables、Available Expressions Analysis)

    文章目录 二. 数据流分析 introduction1 introduction2 输入和输出状态 转换函数 数据流分析应用 1,Reaching Definitions Analysis 概述 用途 ...

  2. 程序分析工具gprof介绍

    程序分析是以某种语言书写的程序为对象,对其内部的运作流程进行分析.程序分析的目的主要有三点:一是通过程序内部各个模块之间的调用关系,整体上把握程序的运行流程,从而更好地理解程序,从中汲取有价值的内容. ...

  3. 为什么要学习微信小程序直播开发?最新的小程序直播介绍和优势分析!

    小程序直播的介绍 "小程序直播"是微信提供给开发者的实时视频直播工具,包括直播管理端.主播端和观众端等模块,支持提供常用的用户互动和营销促销工具. 开发者只需在小程序中引入相关代码 ...

  4. 静态程序分析(一)—— 大纲思维导图与内容介绍

    本系列文章为,基于奥尔胡斯大学的Anders Møller 和 Michael I. Schwartzbach两位教授于2022年2月1日所出版的<static program analysis ...

  5. 01_美国医疗保健分析的入门介绍

    美国医疗保健分析的入门介绍 从这篇开始,我会慢慢来介绍美国的医疗健康领域,以及作为数据科学家我们可以在这个行业做什么.同时会慢慢教大家怎么在医疗保健领域做分析,模型.也会分享一些Case studie ...

  6. java 程序分析题_java程序入门50题分析:002

    [程序2]题目:判断101-200之间有多少个素数,并输出所有素数. 程序分析2:神马是素数,坑爹么,我都不知道素数,吃素我是知道了.那就百度下吧!!质数又称素数.指在一个大于1的自然数中,除了1和此 ...

  7. python的小程序分析_Python学习:JData入门小程序解析(续)

    接着上一篇文章: 第二个.py文件是explore_data.py 它实现的功能很简单,就是简单的处理NEW_USER_FILE,他的内容如下: user_id 用户ID 脱敏 age 年龄段 -1表 ...

  8. [Python爬虫] scrapy爬虫系列 一.安装及入门介绍

    前面介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分析网页DOM树结构进行爬取内容,同时可以结合Phantomjs模拟浏览器进行鼠标或键盘操作.但是,更 ...

  9. [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)

    最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的"原图"等,此时尝试学习Phantomjs和Caspe ...

最新文章

  1. 12-09关于几种排序方式
  2. .Net Petshop详解(二):petshop三层结构之DataTier
  3. 语义分割的时候,发的牢骚
  4. Android百度地图开发01之初体验
  5. java文件复制速度_【Java】Java代码拷贝文件的速度
  6. 微信公号“架构师之路”学习笔记(三)-MQ消息可达性_幂等性_延时性架构设计(应用场景、可靠投递、流量冲击)
  7. 一步一步学Repast 第二章(把界面显示出来2)
  8. linux tar压缩文件命令,tar打包压缩文件命令
  9. 从武汉远程医疗方案看,5G战“疫”是噱头还是福音?
  10. 离圆心最远的整数点(微软笔试题)
  11. 情迁机器人手机版1.6.9升级说明包含多个重要更新
  12. phpmyadmin linux 升级,phpMyAdmin 4.9.2发布下载,附主要更新内容介绍
  13. 华丽而实用的Java图表应用
  14. T细胞培养、分离方法大比拼
  15. EasyExcel 实现模板导出、模板导入分析功能
  16. 最短路:求最长最短路,求最短路的路径
  17. 长训终于完成了,深圳驾考,一把鼻涕一把泪
  18. 【数据库原理及应用】——数据库系统结构和组成(学习笔记)
  19. 一位高僧的告诫:人在惹祸前,往往有3个征兆,有一个就要警醒!
  20. 易语言写微信群AI人工智能机器人,自动对话、聊天、发消息

热门文章

  1. c++数据结构之广义表
  2. SharePonit Host WCF 注意事项
  3. 《精通Wireshark》—第2章2.6节总结
  4. android升级gradle到3.4.1
  5. HashMap之微代码解析-总结整理
  6. Rxlifecycle(一):使用
  7. NHibernate之映射文件配置说明(转载2)
  8. magento获取判断当前页或句柄handles
  9. linux 下 vi 块编辑
  10. 久坐 缺乏运动 消化能力 会减弱