Introduction and Usage of Linux LCD Framebuffer

Today, let’s talk about the LCD Framebuffer in Linux, which is a powerful tool in embedded systems. Despite its fancy name, it’s actually very simple to use; it’s just a large array in memory that stores the color information of each pixel on the screen.

What is a Framebuffer?

In simple terms, a Framebuffer is a region in memory that holds the color values of each pixel on the screen. For example, if you have a 320×240 LCD screen, the Framebuffer is an array of 76800 elements, with each element representing the color of a pixel.

Here’s a simple example:

// Assume we have a 16-bit color 320x240 screen
unsigned short *fb = (unsigned short *)malloc(320 * 240 * sizeof(unsigned short));

// Fill the entire screen with red
for (int i = 0; i < 320 * 240; i++) {
    fb[i] = 0xF800;  // Red color in 16-bit color
}

Tip: Don’t forget to free the memory allocated by malloc after use, or you may end up with memory leaks.

How to Use Framebuffer in Linux

The Linux system is quite powerful; it abstracts the Framebuffer as a device file, usually located at /dev/fb0. We just need to operate on it like a regular file.

#include <fcntl.h>
#include <sys/mman.h>

int fd = open("/dev/fb0", O_RDWR);
if (fd < 0) {
    perror("Cannot open Framebuffer device");
    return -1;
}

// Assuming screen resolution is 320x240, 16-bit color
int screensize = 320 * 240 * 2;
unsigned char *fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (fbp == MAP_FAILED) {
    perror("mmap failed");
    close(fd);
    return -1;
}

// Now fbp points to the Framebuffer and can be directly manipulated

Let’s Draw a Pixel

Since we can manipulate the Framebuffer, let’s draw a pixel.

// Draw a red dot at (x, y)
void draw_pixel(int x, int y, unsigned short color) {
    unsigned short *pixel = (unsigned short *)(fbp + (y * 320 + x) * 2);
    *pixel = color;
}

// Usage
draw_pixel(100, 100, 0xF800);  // Draw a red dot at (100, 100)

Let’s Do Something Fancy

Just drawing pixels is boring; how about creating a gradient rainbow?

void draw_rainbow() {
    for (int y = 0; y < 240; y++) {
        unsigned short color = ((y * 31 / 240) << 11) | ((y * 63 / 240) << 5) | (y * 31 / 240);
        for (int x = 0; x < 320; x++) {
            draw_pixel(x, y, color);
        }
    }
}

This code will draw a rainbow effect that fades from black to white on the screen.

Tip: In actual projects, it’s best to encapsulate Framebuffer operations into a library for easier use and cleaner code.

Double Buffering Technique

Speaking of Framebuffers, we must mention the double buffering technique. This technique works like a magician’s trick, making the display smoother.

The principle is simple: we prepare two Framebuffers in memory, one for display and one for drawing. After the drawing is complete, we swap the two buffers, and the new image appears without a blink.

unsigned short *front_buffer, *back_buffer;

// Initialize double buffering
void init_double_buffer() {
    front_buffer = (unsigned short *)fbp;
    back_buffer = (unsigned short *)malloc(320 * 240 * sizeof(unsigned short));
}

// Swap buffers
void swap_buffers() {
    memcpy(front_buffer, back_buffer, 320 * 240 * sizeof(unsigned short));
}

When using double buffering, we draw on the back_buffer, and after finishing, calling swap_buffers() will show the new image.

Although the Framebuffer is simple, it’s a powerful tool. It allows us to directly manipulate the display and draw whatever we want. However, writing complex graphical interfaces with the Framebuffer can be quite tedious, so in actual development, we usually use more advanced graphics libraries. Nonetheless, understanding how the Framebuffer works is very helpful for grasping the entire graphics system.

That’s all for today. The Framebuffer may seem simple and easy to use, but mastering it requires a lot of skills. Practice more, and who knows, you might even create a simple graphics library yourself!

Leave a Comment