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输出)》。