10_9_fbbuffer整体框架流程

这个文章只是大概流程,很难讲的细
分为两部,第一部分是 整个框架怎么跑的
第二部分是 lcd手册的参数 和soc上lcd控制器的参数 和驱动中需要的参数 到底有什么映射关系
fbbuffer的思想是 应用空间有图像需要 拷贝到驱动空间 如果是cory_To_usr 效率就很低
如果驱动空间能直接映射一块内存(肯定是驱动分配的)到用户空间 mmap 映射到用户空间
应用程序直接写这个地址就会快很多了

当然了 上面驱动中分配的内存 并不是一个块普通内存 是一块DMA内存(外设和这个内存传输就不用cpu的参与)
比如 这块内存中数据达到一定的值 自动就刷入到外设中 比如串口 比如lcdbuffer
这样的话就不用 cpu进行 ldr等操作 直接就搬过去了 省出cpu的调度

达成的效果 如果想显示一张图片 只要用户空间 把这个图片丢入内存 就自动发送到外设了
一般把lcd设备叫帧缓冲设备 : 操作一块内存就是等于操作lcd屏 这块内存也就直接叫做显存 所以这一块在soc上的内存叫集显显存

第一部分

在linux驱动中只有两层
1:lcd控制器层 作用: 1初始化lcd控制器 2分配DMA的显存 (知道分配显存,但是不知道映射给谁)
2: 核心层fb 作用:与应用进行交互 2完成显存的映射 (知道映射不知道显存在哪里) ./drivers/video/fbdev/core/fbmem.c
其实我们这边要写的 只有应用程序 和 lcd_fb_win0里面的数据 但是要清楚流程
在这里插入图片描述

第一步

如果是老的内核,开机自启的时候会注册各种控制器的平台总线dev
新的内核就是用设备树 往平台总线上面注册pdev
那肯定是初始化lcd_control 也就是把这个lcd_control 抽象为一个pdev
这边用的是老的内核,所以开始开机会 跑arch/arm/mach-s5pv210/mach-smdkv210.c

static void __init smdkv210_machine_init(void) //总的初始化函数platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));//平台总线增加devicestatic struct platform_device *smdkv210_devices[] __initdata = {  //下面这个数组是各种soc上面的控制器&s3c_device_fb,//这里是lcd_contral&s3c_device_cfcon,&s3c_device_i2c2,}
arch/arm/plat-samsung/dev-fb.c  这个应该是soc的lcd_control寄存器资源 
struct platform_device s3c_device_fb = {  //lcd_contral上面的寄存器信息在这里,因为control资源一样所以都在plat-samsung中.name		  = "s3c-fb",.id		  = -1,.num_resources	  = ARRAY_SIZE(s3c_fb_resource),.resource	  = s3c_fb_resource,.dev.dma_mask	  = &s3c_device_fb.dev.coherent_dma_mask,.dev.coherent_dma_mask = 0xffffffffUL,
};
arch/arm/plat-samsung/dev-fb.c
static struct resource s3c_fb_resource[] = {[0] = {.start = S3C_PA_FB,.end   = S3C_PA_FB + SZ_16K - 1,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_LCD_VSYNC,.end   = IRQ_LCD_VSYNC,.flags = IORESOURCE_IRQ,},[2] = {.start = IRQ_LCD_FIFO,.end   = IRQ_LCD_FIFO,.flags = IORESOURCE_IRQ,},[3] = {.start = IRQ_LCD_SYSTEM,.end   = IRQ_LCD_SYSTEM,.flags = IORESOURCE_IRQ,},
};
第二步,把lcd硬件信息也放在pdev里面

上面的pdev里面只有当前的lcd_contral的数据
光有控制器的数据还不行,因为连接的lcd屏幕不一样,需要把屏幕的数据也放在pdev中
也是相同的在初始化函数增加 屏幕的信息

/下面这个是特定板子上面lcd的硬件资源
arch/arm/mach-s5pv210/mach-smdkv210.c
s3c_fb_set_platdata(&smdkv210_lcd0_pdata);  //初始化pdev,这里的data用来放屏幕的数据s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),&s3c_device_fb);//函数内部把s3c_fb_platdata也就是下面的lcd屏幕数据放到了//pdev中,这里lcd的pdev由lcd的屏幕数据和lcd的控制器数据合二为一static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {.win[0]		= &smdkv210_fb_win0,.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,.setup_gpio	= s5pv210_fb_gpio_setup_24bpp,};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,
};
第三步,进入核心层,注册fbmem

./drivers/video/fbdev/core/fbmem.c
核心层fb 作用:与应用进行交互 2完成显存的映射 (知道映射不知道显存在哪里)
a 申请主设备号 29+fops
b 创建类
c 注册了一个全局数组,register_fb 里面都是fbinfo结构体 下标也是次设备号
这个全局数组是为了存放 lcd控制器构造的显存
下面这个字符设备带的fops中 mmap已经写好了 会做一个物理地址的映射
如果app调用mmap 就会跑到这里

module_init(fbmem_init);
fbmem_init(void) !proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops)  //就是在/proc/下面有个fb的文件夹ret = register_chrdev(FB_MAJOR, "fb", &fb_fops);  //#define FB_MAJOR 29 主设备号29file_operations fb_fops.mmap =		fb_mmap,vm_iomap_memory(vma, start, len);io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot); //做一个物理地址的映射fb_class = class_create(THIS_MODULE, "graphics");//创建这个类 /sys/class
第四步,lcd控制器层,平台总线匹配

drivers/video/fbdev/s3c-fb.c
a pdrv->probe执行了probe函数
b 获取lcd控制器的数据
c 获取了平台自定义的数据(也就是这块lcd的数据)
d ioremap
e 获取中断数据等
f 申请中断
g 初始化lcd控制器

上面就是为了 构造fb_info对象
来记录显存的信息 构建创造fb_info对象 通过DMA分配显存也记录到fb_info
最后注册到 core层的regisiter_fb数组中
同时也把var这个可变参数进行记录fb_info 不止记录到lcd_contral中
记录在fb_info中为了让用户拿到lcd的分辨率

pdrv->probes3c_fb_probe(struct platform_device *pdev)pd = dev_get_platdata(&pdev->dev);  //就是获取pdev sfb = devm_kzalloc(dev, sizeof(*sfb), GFP_KERNEL);//分配全局对象platform_get_resource(pdev, IORESOURCE_MEM, 0);//获取dev资源sfb->regs = devm_ioremap_resource(dev, res);//ioremap的地址,就是映射lcd寄存器的地址,好操控寄存器,所以寄存器的地址映射在sfb->regspd->setup_gpio();//pd能猜到就是平台pdev,也就是自定义的数据,就是初始化gpio,获取到的pdev有个函数指针是setup_gpio()writel(pd->vidcon1, sfb->regs + VIDCON1);//也和ach-s5pvinit 要进去看看  视频14:05,意思是把pd->vidcon1(在pdev中的数据vidcon1)赋值给基地址偏移VIDCON1的地方,为了修改电频是否反转s3c_fb_probe_win(sfb, win, fbdrv->win[win],&sfb->windows[win]);//内部完成DMA显存分配,fb_info初始化和注册struct fb_info *fbinfo;fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +palette_size * sizeof(u32), sfb->dev);//分配fb_info对象s3c_fb_alloc_memory(sfb, win);//初始化,分配显存struct fb_info *fbi = win->fbinfo;fbi->screen_base = dma_alloc_wc(sfb->dev, size, &map_dma, GFP_KERNEL);//分配了一块dma内存,结果给了fbi->screen_basefbi->fix.smem_start = map_dma;//记录dma的显存起始位置到fb_info的固定参数区s3c_fb_set_par(fbinfo);//把各种值刷入lcd的寄存器中writel(data, regs + sfb->variant.buf_size + (win_no * 4));writel(data, regs + VIDOSD_B(win_no, sfb->variant));register_framebuffer(fbinfo);//注册这个fb对象drivers/video/fbdev/core/fbmem.cfor (i = 0 ; i < FB_MAX; i++)  //去数组registered_fb找到一个空的地方去注册registered_fb[i]fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);  //创建这个设备节点registered_fb[i] = fb_info;fb_videomode_to_var(&fbinfo->var, &initmode);//把fbinfo->var进行填充把平台自定义的数据,lcd的时序值刷入var中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;devm_request_irq(dev, sfb->irq_no, s3c_fb_irq,0, "s3c_fb", sfb);//申请中断platform_set_drvdata(pdev, sfb);//也就是在这个dev里面保存一下私有数据dev->driver_data = data;b 构造fb_info对象
用来记录显存的信息  构建创造fb_info对象  通过DMA分配显存也记录到fb_info
最后注册到 core层的regisiter_fb数组中
同时也把var这个可变参数进行记录fb_info 不止记录到lcd_contral中
记录在fb_info中为了让用户拿到lcd的分辨率
第五步应用程序,打开设备节点
1, 打开设备int fd = open("/dev/fb0", O_RDWR);2, 获取到lcd屏的信息xres, yres, bppstruct fb_var_screeninfo var;ioctl(fd, FBIOGET_VSCREENINFO, &var);//到内核空间,在core层|.unlocked_ioctl = fb_ioctl,|struct fb_info *info = file_fb_info(file);//|//从registered_fb数组中得到fb_info,获取到pdev的数据了struct fb_info *info = registered_fb[fbidx];do_fb_ioctl(info, cmd, arg);|void __user *argp = (void __user *)arg;switch (cmd) {case FBIOGET_VSCREENINFO:var = info->var; //把内核空间的var copy_to_user到 argp也就是应用空间的varcopy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;//回到用户空间,计算出一个frame的大小								size_t length = var.xres * var.yres * var.bits_per_pixel / 8				
3,映射显存到用户空间char *addr = mmap(NULL, size_t length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);可以理解为addr就是显存的地址framebuffer_ptr =(char *)mmap(  NULL,//如果此值为NULL,则表示用内核来自动给你分配一块虚拟空间screensize,		//空间大小PROT_READ|PROT_WRITE,//权限MAP_SHARED,		//是否可以共享framebuffer_fd,		//文件描述符0);			//从哪个地方开始		4, 得到图片数据,将数据写入到addr/*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); // buffer 存了bmp的图片数据, framebuffer_ptr映射之后的显存位置draw_bmp(buffer,(unsigned short *) framebuffer_ptr);|bmp_read_file(bmpfilename, &bmpdata);//跳过bmp文件头bmp2fb16_rgb565(bmpdata, fb);|//bmp2fb16_rgb565(unsigned char *bmpdata,unsigned short *fb16)fb16_buff = fb16; //  fb16_buff就是framebuffer_ptr,映射之后的显存位置for (y = ysize; y > 0 ; y--){for (x = 0 ; x < xsize; x++) /*copy one line to frame buffer*/{	/*copy one pixel to frame buffer*/b = *bmpdata;bmpdata++;b >>= 3;g = *bmpdata;bmpdata++;g >>= 2;r = *bmpdata;bmpdata++;r >>= 3;pixel16 = (unsigned short) ((r << 11) | (g << 5) | b);	*( fb16_buff +  (y* xsize + x)  ) = pixel16;//将一个像素填写到显存}}

第二部分

lcd手册的参数 和soc上lcd控制器的参数 和驱动中需要的参数 到底有什么映射关系
因为在pdev中的那个 fb_win的参数是要我们自己填写的 移植新的触摸屏 就需要知道这些参数

如果想象画图就是打点的话 会有时序要求
那么vsync 和hsync 就像时钟 比如拉高了 才能打点这种
Soc中vsync 和hsync就是时序控制的部分
对应soc的数据手册
在这里插入图片描述
这里看看我们需要的lcd的时序图 截取于soc
在这里插入图片描述

最上面的vsync 上下电频表示一帧 一个完整画面
Hsync的一个上下电频 就表示一行 所以一帧里面有很多行
图中把一行给放大
一行有很多个像素 那么vclk的 上下电频就是一个像素

理解电子枪打一行数据 从图上看 HSYNC为高电频的时候就是无效的周期
但是hsync放下来后还有个虚线 这里在下面的vden是表示数据使能
所以在vden里面的 hozval+1才是真正的稳定时间 这个时间里面要打800个像素
HFPD+1 电子枪跑到了开始的地方 表示打完第一行 打下一行 这个时间用来折返

理解电子枪打一帧数据
所以Vsunc中 开始的高电频也是无效周期 低电频才是稳定的时间
所以在VDEN 中LInval+1 才是真正的打点的时间 打了480行

上面的时序是soc给出来的样式 不是确定的具体时间
那么上面无效时间稳定时间 的决定 应该取决于LCD屏
所以现在打开lcd的屏幕手册

在这里插入图片描述
这里VS垂直同步信号 HS水平同步信号
DE像素使能
所以上面有个叫tvpw的时间其实就是 VS垂直同步信号中的无效时间

继续因为用的是 fb_buffer驱动,linux提供的 所以数据也要符合驱动的要求
在这里插入图片描述
到现在发现soc的手册 和lcd手册和驱动的叫法不一样但其实都描述一个东西
LINVAL 理解为行号一个frame中有480行
在这里插入图片描述

在这里插入图片描述

意思就是上面的数据 lcd知道自己的时序 soc把lcd需要的时序构造出来
时序有了 需要把时序给驱动 驱动里面需要的数值到底填多少 要根据驱动需要的数据
构造出来 比如下面就是驱动需要的数据

1,移植的时候主要是设定自定义数据
arch/arm/mach-s5pv210/mach-smdkv210.c
根据参数修改如下 所以下面这个pdev 就被构造出来了
这么想也是 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, // 和应用有关
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/264145.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能优化算法应用:基于蝴蝶算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝴蝶算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝴蝶算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝴蝶算法4.实验参数设定5.算法结果6.参考文献7.MA…

跟着我学Python基础篇:05.函数

往期文章 跟着我学Python基础篇&#xff1a;01.初露端倪 跟着我学Python基础篇&#xff1a;02.数字与字符串编程 跟着我学Python基础篇&#xff1a;03.选择结构 跟着我学Python基础篇&#xff1a;04.循环 目录 往期文章1. 函数如同黑盒子2. 实现和测试函数2.1 实现函数2.2 测试…

计算机毕业设计springboot+ssm停车场车位预约系统java

管理员不可以注册账号 停车位包括车位所在楼层、车位编号、车位类型(全时间开放/高峰期开放)、预定状态等 用户预约时要求支付预约时间段的停车费用 违规行为&#xff1a;1.停车超过预约时间段 2.预约未使用 于系统的基本要求 &#xff08;1&#xff09;功能要求&am…

时序数据库选型TimescaleDB

最近要做一个数字车间的物联网项目&#xff0c;数据存储成了首先要解决的问题&#xff0c;整个车间一共104台数控机床&#xff0c;1s钟采集1次数据&#xff0c;360024365*1043,279,744,000 &#xff0c;一年要产生32亿条记录&#xff0c;这个数据量用常见的关系型数据库肯定是不…

JavaScript基础知识整理(最全知识点, 精简版,0基础版)

文章目录 一、输入和输出内容 1.1 输出 1.1.1 在浏览器的控制台输出打印 1.1.2 直接在浏览器的页面上输出内容 1.1.3 页面弹出警告对话框 1.2 输入 二、变量 2.1 变量是什么 2.2 变量的声明和赋值 2.3 变量的命名规范和规范 三、变量扩展&#xff08;数组&#xff09; 3.1 数组…

实现跨VLAN通信、以及RIP路由协议的配置

一、如下图片&#xff1a; 1. 按照拓扑图所示&#xff0c;将8台计算机分别配置到相应的VLAN中。&#xff08;20分&#xff09; 2. 配置实现同一VLAN中的计算机可以通信。&#xff08;22分&#xff09; 3. 配置实现PC1,PC2,PC3,PC4可以互相通信&#xff0c;PC5,PC6,PC7,PC8可以互…

利用Microsoft Visual Studio Installer Projects打包安装包

利用Microsoft Visual Studio Installer Projects打包安装包 具体步骤步骤1&#xff1a;安装扩展步骤2&#xff1a;创建 Setup 项目步骤3&#xff1a;设置属性步骤4&#xff1a;添加输出步骤5&#xff1a;添加文件步骤6&#xff1a;添加桌面快捷方式步骤7&#xff1a;添加菜单快…

fl studio 21破解版注册机下载 水果音乐编曲软件 FL Studio v21.

FL studio21中文别名水果编曲软件&#xff0c;是一款全能的音乐制作软件&#xff0c;包括编曲、录音、剪辑和混音等诸多功能&#xff0c;让你的电脑编程一个全能的录音室&#xff0c;它为您提供了一个集成的开发环境&#xff0c;使用起来非常简单有效&#xff0c;您的工作会变得…

公式识别任务各个链条全部打通

目录 引言公式识别任务是什么&#xff1f;公式识别任务解决方案初探使用建议写在最后 引言 随着LaTeX-OCR模型转换问题的解决&#xff0c;公式识别任务中各个链条已经全部打通。小伙伴们可以放开膀子干了。 解决业界问题的方案&#xff0c;并不是单独训练一个模型就完事了&am…

接触刚性环境任务下的机器人力控(阻抗)性能测试

内涵 接触刚性环境任务下的机器人力控&#xff08;阻抗&#xff09;性能测试旨在评估机器人在与刚性物体交互时的性能表现。这种测试通过调整机器人的控制参数&#xff0c;如期望刚度和期望阻尼等&#xff0c;并分析记录的数据&#xff0c;旨在确保机器人能够在执行任务时保持…

Redis 持久化 —— 超详细操作演示!

四、Redis 持久化 四、Redis 持久化4.1 持久化基本原理4.2 RDB持久化4.3 AOF持久化4.4 RDB与AOF对比4.5 持久化技术转型 五、Redis 主从集群六、Redis 分布式系统七、Redis 缓存八、Lua脚本详解九、分布式锁 数据库系列文章&#xff1a; 关系型数据库: MySQL —— 基础语法大全…

【实战教程】PHP与七牛云的完美对接,你值得拥有!

前言&#xff1a; 随着互联网的迅速发展&#xff0c;越来越多的网站和应用程序需要处理大量的图片、视频和其他文件。为了有效地存储和管理这些文件&#xff0c;并提供快速的内容分发服务&#xff0c;开发者们常常依赖于云存储和CDN服务提供商。 七牛云是一家领先的云存储和C…