• 嵌入式快速入门学习笔记-Framebuffer


    介绍

    在应用层与内核之间传递少量数据时,采用copy_from_usr,copy_to_usr。但是如果是传输图片这种大量数据时需使用mmap方法(在内核空间中申请一段内存作为显存,然后将这段内存的物理地址与应用层的地址进行映射)。

    使用流程

    1)打开设备文件/dev/fb0
    2)获取设备信息——需要包含头文件#include
    3)mmap做映射
    4)向framebuffer填充数据

    #include 
    
    void *mmap (void *addr, size_t length, 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则不推荐使用。
    @fd 即将映射到进程空间的文件描述字,一般为open()返回值,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)。
    @offset 一般设为0,表示从文件头开始映射, 代表偏移量。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    应用层例程

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    //设备名宏定义
    #define FBDEVICE	"/dev/fb0"
    
    // 旧开发板
    //#define WIDTH		800	
    //#define HEIGHT		480
    // 新开发板
    #define WIDTH		1024	
    #define HEIGHT		600
    
    //颜色宏定义
    #define WHITE		0xffffffff			// test ok
    #define BLACK		0x00000000
    #define RED			0xffff0000
    #define GREEN		0xff00ff00			// test ok
    #define BLUE		0xff0000ff			
    #define GREENP		0x0000ff00			// 一样,说明前2个ff透明位不起作用
    
    //全局变量 指向mmap映射空间
    unsigned int *pfb = NULL;
    
    //背景填充函数
    void draw_back(unsigned int width, unsigned int height, unsigned int color)
    {
    	unsigned int x, y;
    	
    	for (y=0; y<height; y++)
    	{
    		for (x=0; x<width; x++)
    		{
    			*(pfb + y * WIDTH + x) = color;//从左到右,从上到下
    		}
    	}
    }
    
    //划线函数
    void draw_line(unsigned int color)
    {
    	unsigned int x, y;
    	
    	for (x=50; x<600; x++)
    	{
    		*(pfb + 200 * WIDTH + x) = color;
    	}
    }
    
    int main(void)
    {
    	int fd = -1, ret = -1;
    	
    	struct fb_fix_screeninfo finfo = {0};
    	struct fb_var_screeninfo vinfo = {0};
    	
    	// 第1步:打开设备
    	fd = open(FBDEVICE, O_RDWR);
    	if (fd < 0)
    	{
    		perror("open");
    		return -1;
    	}
    	printf("open %s success.\n", FBDEVICE);
    	
    	// 第2步:获取设备的硬件信息
    	ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);//FBIOGET_FSCREENINFO 获取不可变的硬件信息
    	if (ret < 0)
    	{
    		perror("ioctl");
    		return -1;
    	}
    	printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len);
    	
    	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);//FBIOGET_VSCREENINFO 获取可变的硬件信息
    	if (ret < 0)
    	{
    		perror("ioctl");
    		return -1;
    	}
    	printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
    	printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
    	printf("bpp = %u.\n", vinfo.bits_per_pixel);
    	
    	// 修改驱动中屏幕的分辨率
    	vinfo.xres = 1024;
    	vinfo.yres = 600;
    	//虚拟空间大小=1024*1200 ——> 双缓冲区
    	vinfo.xres_virtual = 1024;
    	vinfo.yres_virtual = 1200;
    	ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo);//FBIOPUT_VSCREENINFO 设定可变的硬件信息
    	if (ret < 0)
    	{
    		perror("ioctl");
    		return -1;
    	}
    	
    	// 再次读出来检验一下
    	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);//FBIOGET_VSCREENINFO 获取可变的硬件信息
    	if (ret < 0)
    	{
    		perror("ioctl");
    		return -1;
    	}
    	printf("修改过之后的参数:\n");
    	printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
    	printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
    	printf("bpp = %u.\n", vinfo.bits_per_pixel);
    	
    	// 第3步:进行mmap
    	unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;//映射字节数=长*宽(实际长宽的两倍)*像素bit数/8
    	printf("len = %ld\n", len);
    	pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    	if (NULL == pfb)
    	{
    		perror("mmap");
    		return -1;
    	}
    	printf("pfb = %p.\n", pfb);
    	
    	draw_back(WIDTH, HEIGHT, WHITE);//背景填充
    	draw_line(RED);//划线
    
    	close(fd);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131

    gcc编译,烧录测试

    修改内核显示logo

    1、logo的png格式图片(图片分辨率不得大于屏幕分辨率),并将其命令为logo.png(目的在于方便pngtopnm指令)

    2、在终端下执行以下命令

    pngtopnm logo.png | ppmquant -fs 224 | pnmtoplainpnm > logo_x210_clut224.ppm
    
    • 1

    3、生成的ppm文件拷贝到/kernel/drivers/video/logo/目录下进行替换。

    4、编译内核 make -j4

    补充:

    (1)修改fbmem.c的471行可以修改Logo显示在屏幕中间:

    image.dx = (info->var.xres - logo->width)/2;
    image.dy = (info->var.yres - logo->height)/2;
    
    • 1
    • 2

    (2)如果图片显示不出来可能有以下原因:
     
    a、内核里framebuffer的分辨率不对,可以在mach-x210.c的225行修改(1024 * 600);

    b、只能在左上角显示,CONFIG_FRAMEBUFFER_CONSOLE宏可能被选中(该宏不需要勾选,可以现在.config里面查看,确定后,make menuconfig 去除Device Drivers -> Graphics support -> Console display driver support -> Framebuffer Console Support)

    修改Boot开机logo

    1、Boot显示开机logo的代码定位 uboot\drivers\video\logo.c
    2、更改变量xboot_logo的赋值。

    自制开机logo

    1、下载GIMP(linux平台)
    2、将准备的图片(分辨率不要太高)通过GMIP导出C文件
    3、将导出的C文件代码替换xboot_logo的值。
    补:目前还没有测试过GIMP生成C数组

  • 相关阅读:
    对城乡居民消费结构数据AIDS模型进行参数估计时用SPSS软件的操作视频或操作流程图片
    如果你想了解远程工作,这篇文章不容错过
    【MySQL】_JDBC
    在Bash中如何提取子字符串
    Go 代码包与引入:如何有效组织您的项目
    AOP切面实现增删改防止重放攻击
    Java类和对象(1)
    【pen200-lab】10.11.1.21(实际获得22权限)
    开源软件安全与应对策略探讨 - Java 机密计算技术应用实践
    fmp4打包H265视频流
  • 原文地址:https://blog.csdn.net/wuli_Thames/article/details/126307292