linux笔记(7):东山哪吒D1H使用framebuffer画直线(HDMI输出)


这部分linux笔记是记录我入门的过程,内容基本都是照着别人的文章,自己操作一遍,重走一次别人走过的路。
参考文章:
1.作者:闪耀大叔,文章《 嵌入式Linux入门-Framebuffer应用编程在Linux系统下画个点》。

1.测试流程和结果

1.1 使能HDMI

我前2天想把韦东山老师的《buildroot_dongshannezhastu》工程改成启动时有HDMI输出,结果没有成功。只能先利用上一篇文章的方法启动HDMI《linux笔记(6):东山哪吒D1H测试HDMI显示内置图片-命令行调试》。

1.2 framebuffer操作流程

1.打开设备节点:open(“/dev/fb0”, O_RDWR)

2.获取LCD参数:ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)

3.映射Framebuffer:mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0)

4.操作Framebuffer

5.取消映射 munmap (fb_base, screen_size)

6.关闭设备节点 close(fd_fb)

1.3 测试结果

在屏幕上描出不同颜色:
在这里插入图片描述

2.测试过程详述

2.1 编译源码

把源码fb001 – https://gitee.com/huangweide001/linux-d1-h-test/tree/master/fb001 下载下来,进入工程,直接使用 make 命令编译。

2.2上传可执行文件

我上传应用程序到开发板的步骤是不是太复杂?
在这里插入图片描述

2.3修改文件的权限,执行文件

> chmod 777 test
> ./test
1.open /dev/fb0
2.get V Screen INFO
width:800,hight:1280,bits_per_pixel:32
3.get framebuffer base address
fb_base:0xf1f6f000
4.flush screen in different colors
5.draw 30 lines in different colors

3.源码解释

3.1 HDMI使用的颜色格式是ARGB

可以参考这个文章《ARGB与RGB区别及透明度和RGB颜色对照表》。
ARGB从表面看比RGB多了个A,也是一种色彩模式,是在RGB的基础上添加了Alpha(透明度)通道。透明度也是以0到255表示的,所以也是总共有256级,透明是0,不透明是255。
用十六进制的格式来表示ARGB就是:0xAARRGGBB。
东山哪吒开发板的HDMI驱动使用的是ARGB,如果直接使用RGB格式,相当于ARGB的透明格式,显示出来是黑色的。
比如上面的参考文章使用的是RGB格式:
在这里插入图片描述
我画30条线使用的30种颜色数据:
在这里插入图片描述
举个例子,要正常显示红色(0x00FF0000),要使表示透明度的字节不为0.上面的A=0xFF和A=0x7F都可以正常显示。

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>
#include <unistd.h>
 
static int fd_fb;
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(int x, int y, unsigned int color)
//传入的 color 表示颜色,它的格式永远是 0x00RRGGBB,即 RGB888。
//当 LCD 是 16bpp 时,要把 color 变量中的 R、 G、 B 抽出来再合并成 RGB565 格式。
{
    unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
    //计算(x,y)坐标上像素对应的 Framebuffer 地址。
 
    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)
    {
      //对于 8bpp, color 就不再表示 RBG 三原色了,这涉及调色板的概念, color 是调色板的值。
        case 8:
            {
                *pen_8 = color;
                break;
            }
        case 16:
            {
                //  R5 G6 B5 
                //先从 color 变量中把 R、 G、 B 抽出来。
                red = (color >> 16) & 0xff;
                green = (color >> 8) & 0xff;
                blue = (color >> 0) & 0xff;
                //把 red、 green、 blue 这三种 8 位颜色值,根据 RGB565 的格式,
                //只保留 red 中的高 5 位、 green 中的高 6 位、 blue 中的高 5 位,
                //组合成一个新的 16 位颜色值。
                color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
                //把新的 16 位颜色值写入 Framebuffer
                *pen_16 = color;
                break;
            }
        case 32:
            {
                //对于 32bpp,颜色格式跟 color 参数一致,可以直接写入Framebuffer
                *pen_32 = color;
                break;
            }
        default:
            {
                printf("can't surport %dbpp\n",var.bits_per_pixel);
                break;
            }
     }
}

void    blushScreen2(unsigned int color)
{// 这里只考虑24色,也就是HDMI的情况
    unsigned int * p32=(unsigned int *)fb_base;
    unsigned int h,w;
    for(h=0;h<var.yres;h++)
        for(w=0;w<var.xres;w++){
            *p32= color;
            p32++;
        } 
}
int main(int argc,int **argv)
{	
	int i;
    
	printf("1.open /dev/fb0\n");
	fd_fb = open("/dev/fb0", O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open /dev/fb0\n");
		return -1;
	}	
	printf("2.get V Screen INFO\n");
	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;
    printf("width:%d,hight:%d,bits_per_pixel:%d\n",var.xres,var.yres,var.bits_per_pixel);
	
	printf("3.get framebuffer base address\n");
	fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}else{        
		printf("fb_base:0x%8x\n",fb_base);
    }
    unsigned char colorData[10]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xff};

    unsigned int cData[30] = {0xFFFF0000,0xFF00FF00,0xFF0000FF,
                            0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,
                            0xFF7F7F7F,0xFF007F7F,0xFF7F007F,0xFF7F7F00,//  0-9     FF开头
                            0x7FFF0000,0x7F00FF00,0x7F0000FF,
                            0x7FFFFF00,0x7FFF00FF,0x7F00FFFF,
                            0x7F7F7F7F,0x7F007F7F,0x7F7F007F,0x7F7F7F00,//  10-19   7F开头
                            0x00FF0000,0x0000FF00,0x000000FF,
                            0x00FFFF00,0x00FF00FF,0x0000FFFF,
                            0x007F7F7F,0x00007F7F,0x007F007F,0x007F7F00};//  20-29  00开头
          
	printf("4.flush screen in different colors\n");                      
    for(i = 0;i<10;i++)
    {
        memset(fb_base,colorData[i],screen_size );
        sleep(1);//usleep(100*1000);
    }
	printf("5.draw 30 lines in different colors\n"); 
    for (int j = 0; j < 30;j++){
	    for (i = 0; i < 100; i++)	{
            lcd_put_pixel(var.xres/3+i, var.yres/4+20*j+0, cData[j] );
            lcd_put_pixel(var.xres/3+i, var.yres/4+20*j+1, cData[j] );
            lcd_put_pixel(var.xres/3+i, var.yres/4+20*j+2, cData[j] );
            lcd_put_pixel(var.xres/3+i, var.yres/4+20*j+3, cData[j] );
        }
    }
    munmap (fb_base, screen_size);            
	close(fd_fb);
	return 0;
}

4.源码工程链接

源码工程fb001

可以控制显示后,下一步就是移植 lvgl ,请浏览下一篇文章《linux笔记(8):东山哪吒D1H移植lvgl(HDMI输出)》。

posted @ 2022-11-21 16:35  汉塘阿德  阅读(100)  评论(0编辑  收藏  举报  来源