Framebuffer programming summary, I hope everyone can learn

Posted by fxb9500 on Tue, 02 Nov 2021 20:40:48 +0100

🌹 Introduction of 0.FrameBuffer

Framebuffer is a driver interface that appears in the 2.2.xx kernel. In Linux system, LCD is controlled by framebuffer driver. Frame means frame and buffer means buffer, which means that framebuffer is a piece of memory that holds a frame of image. We can understand that each point is a pixel. The units of this pixel can be 24 bits, 16 bits and 32 bits. Assuming that the resolution of this LCD screen is 55100 and each pixel is represented by 32 bits, there are 55100 * 32 bytes in total.

☕ 1. Principle of LCD display

There is a special address bit framebuffer in the memory. We only need to write data to this address, so we need to obtain the basic address of this memory first. For example, a pixel has 5 bytes, so we only need to modify the value of these 5 bytes to write data to the LCD, The picture drawn by Mr. Wei Dongshan is clearer.

⌛ 2. How to modify the pixels specified by LCD

For example, to modify the value of the (x,y) th pixel, we have the following steps

  • Get the base address of framebuffer
  • Get the absolute address of this pixel.

♐ 3. Get framebuffer base address

The base address can be obtained by using the mmap disk mapping function,

fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

🚀 4. Calculation of pixel absolute address

Based on the base address, first calculate the number of lines and the number of deviation from the x-axis. bpp means pixels. A pixel can understand a bit and a point
Formula summary: (x, y) pixel start address = fb_base+(xres*bpp/8)y + xbpp/8

🌸 5. Color representation of pixels

Pixels are represented by RGB three primary colors (red, green and blue). In different BPP formats, different bits are used to represent R, G and B respectively,

  • For 32BPP, generally only the lower 24 bits are set, and the higher 8 bits represent transparency, which is not supported by general LCD
  • For 24BPP, in order to facilitate processing in hardware, it is also represented by 32 bits in Framebuffer, and the effect is the same as that of 32BPP.
  • For 16BPP, RGB565 is commonly used; RGB555 is rarely used, which can determine which format to use by ioctl reading the RGB bit offset in the driver.

💯 6. Acquisition of LCD parameters

LCD contains an LCD driver on each development board. We mainly code through the driver provided by others. There are two main types. Variable parameter fb_var_screeninfo, fixed parameter fb_fix_screeninfo. The main concern when writing applications is variable parameters.
We can call ioctl to get the parameters of lcd and put it into the structure you specify, as shown in the following code

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

👑 7. Opening of equipment

On linux system, there is a unique device node, which is responsible for writing framebuffer data. We need to call the open function to open the device node

  fd_fb = open("/dev/fb0", O_RDWR);
     if (fd_fb < 0)
     {
             printf("can't open /dev/fb0\n");
             return -1;
      }

🐟 8. Full code demonstration of framebuffer

Function: draw a red line in the middle of the LCD screen
There are a lot of notes in it. It should not be difficult to understand

#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>
//LCD driver provides APP with two types of parameters: variable parameter fb_var_screeninfo, fixed parameter fb_fix_screeninfo. 

static int fd_fb;
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;//Screen size
static unsigned char *fb_base;//And address of video memory
static unsigned int line_width;
static unsigned int pixel_width;//pixel

void lcd_put_pixel(int x, int y, unsigned int color)
{
    //Which point do you want to select
    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;	//The color consists of red, green and blue

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

    //In different BPP formats, R, G and B are represented by different bits, including 8 bits, 16 bits and 32 bits. Sixteen bits are selected here
    switch (var.bits_per_pixel)
	{
		case 8:
		{
		//8bpp, color no longer represents RBG three primary colors, which involves the concept of palette. Color is the value of palette.
			*pen_8 = color;
			break;
		}
		case 16:
		{
			/* RGB888 Turn to RGB565. According to the format of RGB565, the three 8-bit color values of red, green and blue are combined into a new 16 bit color value by retaining only the high 5 bits in red, the high 6 bits in green and the high 5 bits in blue.*/
			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;
		}
	}
}

int main()
{
    int i;
	fd_fb = open("/dev/fb0", O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open /dev/fb0\n");
		return -1;
	}
    //Get variable parameter FB_ var_ Value of screeninfo
       if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var\n");
		return -1;
	}
    //Calculation line, how many bytes per point
    line_width  = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;
    //The calculation formula of lcd size is x-axis * y-axis var.bits_ per_ Pixel stands for pixels, except 8 because pixels are in bits
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    //Get the video memory address through mmap
    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;
	}
    /* Clear screen: set all to white */
	memset(fb_base, 0xff, screen_size);

    
	/* Randomly set 100 to red */
	for (i = 0; i < 100; i++)
	lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);//Write pixel
    //Release disk mapping
    munmap(fb_base , screen_size);
	close(fd_fb);
	
	return 0;	
}





Topics: Linux Embedded system LCD