嵌入式Linux驱动开发(LCD屏幕专题)(四)

news2024/11/17 3:16:26

单Buffer的缺点与改进方法

1. 单Buffer的缺点

  • 如果APP速度很慢,可以看到它在LCD上缓慢绘制图案

  • 即使APP速度很高,LCD控制器不断从Framebuffer中读取数据来显示,而APP不断把数据写入Framebuffer

    • 假设APP想把LCD显示为整屏幕的蓝色、红色

    • 很大几率出现这种情况:

      • LCD控制器读取Framebuffer数据,读到一半时,在LCD上显示了半屏幕的蓝色
      • 这是APP非常高效地把整个Framebuffer的数据都改为了红色
      • LCD控制器继续读取数据,于是LCD上就会显示半屏幕蓝色、半屏幕红色
      • 人眼就会感觉到屏幕闪烁、撕裂
        在这里插入图片描述

2. 使用多Buffer来改进

上述两个缺点的根源是一致的:Framebuffer中的数据还没准备好整帧数据,就被LCD控制器使用了。
使用双buffer甚至多buffer可以解决这个问题:

  • 假设有2个Framebuffer:FB0、FB1
  • LCD控制器正在读取FB0
  • APP写FB1
  • 写好FB1后,让LCD控制器切换到FB1
  • APP写FB0
  • 写好FB0后,让LCD控制器切换到FB0

3. 内核驱动程序、APP互相配合使用多buffer

流程如下:

在这里插入图片描述

  • 驱动:分配多个buffer

    fb_info->fix.smem_len = SZ_32M;
    fbi->screen_base = dma_alloc_writecombine(fbi->device,
    				fbi->fix.smem_len,
    				(dma_addr_t *)&fbi->fix.smem_start,
    				GFP_DMA | GFP_KERNEL);
    
  • 驱动:保存buffer信息

    fb_info->fix.smem_len  // 含有总buffer大小 
    fb_info->var           // 含有单个buffer信息
    
  • APP:读取buffer信息

    ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
    ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
    
    // 计算是否支持多buffer,有多少个buffer
    screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    nBuffers = fix.smem_len / screen_size;
    
  • APP:使能多buffer

    var.yres_virtual = nBuffers * var.yres;
    ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var);
    
  • APP:写buffer

    fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    
    /* get buffer */
    pNextBuffer =  fb_base + nNextBuffer * screen_size;
    
    /* set buffer */
    lcd_draw_screen(pNextBuffer, colors[i]);
    
  • APP:开始切换buffer

    /* switch buffer */
    var.yoffset = nNextBuffer * var.yres;
    ioctl(fd_fb, FBIOPAN_DISPLAY, &var);
    
  • 驱动:切换buffer

    // fbmem.c
    fb_ioctl
        do_fb_ioctl
        	fb_pan_display(info, &var);
    			err = info->fbops->fb_pan_display(var, info) // 调用硬件相关的函数            
    

    示例:
    在这里插入图片描述

  • APP:等待切换完成(在驱动程序中已经等待切换完成了,所以这个调用并无必要)

    ret = 0;
    ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret);
    

多buff代码

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>

static int fd_fb;
static struct fb_fix_screeninfo fix;	/* Current fix */
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;


void lcd_put_pixel(void *fb_base, int x, int y, unsigned int color)
{
	unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
	unsigned short *pen_16;	
	unsigned int *pen_32;	

	unsigned int red, green, blue;	

	pen_16 = (unsigned short *)pen_8;
	pen_32 = (unsigned int *)pen_8;

	switch (var.bits_per_pixel)
	{
		case 8:
		{
			*pen_8 = color;
			break;
		}
		case 16:
		{
			/* 565 */
			red   = (color >> 16) & 0xff;
			green = (color >> 8) & 0xff;
			blue  = (color >> 0) & 0xff;
			color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			*pen_16 = color;
			break;
		}
		case 32:
		{
			*pen_32 = color;
			break;
		}
		default:
		{
			printf("can't surport %dbpp\n", var.bits_per_pixel);
			break;
		}
	}
}

void lcd_draw_screen(void *fb_base, unsigned int color)
{
	int x, y;
	for (x = 0; x < var.xres; x++)
		for (y = 0; y < var.yres; y++)
			lcd_put_pixel(fb_base, x, y, color);
}


/* ./multi_framebuffer_test single
 * ./multi_framebuffer_test double
 */
int main(int argc, char **argv)
{
	int i;
	int ret;
	int nBuffers;
	int nNextBuffer = 1;
	char *pNextBuffer;
	unsigned int colors[] = {0x00FF0000, 0x0000FF00, 0x000000FF, 0, 0x00FFFFFF};  /* 0x00RRGGBB */
	struct timespec time;

	time.tv_sec  = 0;
	time.tv_nsec = 100000000;

	if (argc != 2)
	{
		printf("Usage : %s <single|double>\n", argv[0]);
		return -1;
	}
	
	fd_fb = open("/dev/fb0", O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open /dev/fb0\n");
		return -1;
	}

	if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
	{
		printf("can't get fix\n");
		return -1;
	}
	
	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var\n");
		return -1;
	}

	line_width  = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;

	nBuffers = fix.smem_len / screen_size;
	printf("nBuffers = %d\n", nBuffers);
	
	fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}

	if ((argv[1][0] == 's') || (nBuffers == 1))
	{
		while (1)
		{
			/* use single buffer */
			for (i = 0; i < sizeof(colors)/sizeof(colors[0]); i++)
			{
				lcd_draw_screen(fb_base, colors[i]);
				nanosleep(&time, NULL);
			}
		}
	}
	else
	{
		/* use double buffer */
		/* a. enable use multi buffers */
		var.yres_virtual = nBuffers * var.yres;
		ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var);

		while (1)
		{
			for (i = 0; i < sizeof(colors)/sizeof(colors[0]); i++)
			{
				/* get buffer */
				pNextBuffer =  fb_base + nNextBuffer * screen_size;

				/* set buffer */
				lcd_draw_screen(pNextBuffer, colors[i]);

				/* switch buffer */
				var.yoffset = nNextBuffer * var.yres;
				ioctl(fd_fb, FBIOPAN_DISPLAY, &var);

				ret = 0;
				ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret);
				
				nNextBuffer = !nNextBuffer;
				nanosleep(&time, NULL);
			}
		}
		
	}
	
	munmap(fb_base , screen_size);
	close(fd_fb);
	
	return 0;	
}



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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线程池的实现

目录 一、线程池的实现 1.什么是线程池 2.设计线程类 3.设计线程池类 4.运行 5.RAII加锁改造 二、利用单例模式改造线程池 1.复习 2.饿汉模式 3.懒汉模式 关于系统编程的知识我们已经学完了&#xff0c;最后我们需要利用之前写过的代码实现一个线程池&#xff0c;彻底…

如何理解张量、张量索引、切片、张量维度变换

Tensor 张量 Tensor&#xff0c;中文翻译“张量”&#xff0c;是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似。在 PyTorch 中&#xff0c;使用张量对模型的输入和输出以及模型的参数进行编码。 Tensor 是一个 Python Class。PyTorch 官方文档中定义“Tensor&#xff0…

Datawhale × 和鲸科技丨《2023 中国人工智能人才学习白皮书》发布!

2023 是一个历史性的年份&#xff0c;它标志着人工智能技术的崛起与普及&#xff0c;这一年里&#xff0c;AI 不仅在科技、经济、社会、文化等各个领域取得突破性的进展&#xff0c;也在人类日常生活中扮演愈加重要的角色。随着人工智能时代的加速到来&#xff0c;我国 AI 人才…

msvcp140.dll丢失的有哪些解决方法,丢失msvcp140.dll是什么意思

在我们的日常生活中&#xff0c;电脑问题是无处不在的&#xff0c;而msvcp140.dll丢失又是其中比较常见的一种。msvcp140.dll是Microsoft Visual C运行时库的一部分&#xff0c;它包含了一些重要的函数和资源。当这个文件丢失时&#xff0c;可能会导致电脑出现各种问题&#xf…

链路追踪Skywalking快速入门

目录 1 Skywalking概述1.1 微服务系统监控三要素1.2 什么是链路追踪1.2.1 链路追踪1.2.2 OpenTracing1、数据模型&#xff1a;2、核心接口语义 1.3 常见APM系统1.4 Skywalking介绍1、SkyWalking 核心功能&#xff1a;2、SkyWalking 特点&#xff1a;3、Skywalking架构图&#x…

mysql之DML的select分组排序

目录 一、创建表employee和department表 1.创建department表 2.创建employee表 3.给employee表格和department表格建立外键 4.给department插入数据 5.给employee表插入数据 6.删除名字为那个的数据 二、分组查询和排序查询&#xff0c;以及对数据的处理&#xff08;av…

ARM/X86工业级数据采集 (DAQ) 与控制产品解决方案

I/O设备&#xff0c;包括信号调理模块、嵌入式PCI/PCIE卡、便携式USB模块、DAQ嵌入式计算机、模块化DAQ系统&#xff0c;以及DAQNavi/SDK软件开发包和DAQNavi/MCM设备状态监测软件。 工业I/O产品适用于各种工业自动化应用&#xff0c;从机器自动化控制、测试测量到设备状态监测…

Java“牵手”京东商品详情数据,京东商品详情API接口,京东API接口申请指南

京东平台商品详情接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口&#xff0c;通过…

kuiper安装

1:使用docker方式安装 docker pull lfedge/ekuiper:latest docker run -p 9081:9081 -d --name kuiper -e MQTT_SOURCE__DEFAULT__SERVERtcp://127.0.0.1:1883 lfedge/ekuiper:latest这样就安装好了&#xff0c;但是操作只能通过命令完成&#xff0c;如果想要通过页面来操作&…

@DS注解方式springboot多数据源配置及失效场景解决

1.使用教程 导入依赖 <!--多数据源--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.0</version></dependency>配置数据源 datasource:…

MT36291 2.5A,高效型1.2MHz电流模式升压转换器芯片

MT36291 2.5A&#xff0c;高效型1.2MHz电流模式升压转换器芯片 特征 ●集成了80ms功率的MOSFET ●2.2V到16V的输入电压 ●1.2MHz固定开关频率 ●可调过电流保护&#xff1a; 0.5A ~2.5A ●内部2.5开关限流&#xff08;OC引脚浮动&#xff09; ●可调输出电压 ●内部补偿 ●过电…

PCL入门(三):矩阵变换实现平移和旋转

目录 1. pcl中的矩阵变换是什么2. 举例&#xff1a;如何做矩阵变换 1. pcl中的矩阵变换是什么 通过激光传感器等设备获得的3d点云在拼接成更大场景时&#xff0c;需要对点云数据进行旋转和平移操作。而旋转和平移操作&#xff0c;就可以通过矩阵变换来实现。 点的表示 对于点…

【每日一题】1523. 在区间范围内统计奇数数目,860. 柠檬水找零

1523. 在区间范围内统计奇数数目 - 力扣&#xff08;LeetCode&#xff09; 给你两个非负整数 low 和 high 。请你返回 low 和 high 之间&#xff08;包括二者&#xff09;奇数的数目。 示例 1&#xff1a; 输入&#xff1a;low 3, high 7 输出&#xff1a;3 解释&#xff1a;…

Excel文件损坏打不开怎么办?可用这三招解决!

当你的excel文件不可读&#xff0c;或者出现提示“文件已经被损坏&#xff0c;无法打开”&#xff0c;这种情况让人措手不及。而且还会给我们正常的工作带来很多麻烦&#xff0c;文件损坏打不开怎么办&#xff1f;来看看这3招&#xff0c;详细的图文教程&#xff0c;小白也能轻…

Notepad++ 的安装及配置

由于电脑重装了Win11系统&#xff0c;干脆重头开始&#xff0c;重新安装每一个软件~~~ 很多博客或者博主都会推荐notepad的官网&#xff1a;https://notepad-plus-plus.org/ 但大家亲自点开就会发现是无响应&#xff0c;如下图 同时&#xff0c;也会有很多博主直接给网盘地址…

【Flutter】Flutter 使用 table_calendar 实现自定义日历

【Flutter】Flutter 使用 table_calendar 实现自定义日历 文章目录 一、前言二、安装和基本使用三、日历的交互性四、日历事件五、自定义 UI 和 CalendarBuilders六、本地化和语言设置七、完整实际业务代码示例 一、前言 你好&#xff01;今天我要为你介绍一个非常实用的 Flut…

2023高教社杯数学建模国赛的工具箱准备

2023高教社杯数学建模国赛的工具箱准备 数学建模国赛工具箱&#xff08;私信领取&#xff09;&#xff01;&#xff01;&#xff01;小编仔细阅读了比赛官方网站上的规则和要求&#xff0c;以及比赛的题型和时间安排&#xff0c;现总结分享给大家。欢迎私信和评论&#xff0c;…

运维监控系统PIGOSS BSM 业务监控 大屏展现解析

“业务大屏”是 PIGOSS BSM&#xff08;IT运维监控工具&#xff09;的特色功能之一&#xff0c;旨在提供综合而直观的业务监控视图。该功能主要由三个组成部分构成&#xff1a;业务健康度雷达图、业务状态矩阵和多趋势对比图。 下面将对每个部分进行详细介绍&#xff1a; 业务健…

IDEA Java1.8通过sqljdbc4连接sqlserver插入语句

1. 下载sqljdbc4:https://mvnrepository.com/artifact/com.microsoft.sqlserver.jdbc/sqljdbc4/4.0 下载后在IDEA放入仓库内&#xff0c;可以放在resources下&#xff0c;右键“add as library”。 2. 在控制面板中开启Telnet客户端&#xff0c;默认是不开启的。 若报错“ ja…