1. 初始化Framebuffer设备

初始化Framebuffer设备 学习卡片

任务目标

本案例实现Linux下LCD Framebuffer设备的最小初始化流程:打开设备文件、获取屏幕固定与可变参数、计算缓冲区大小并完成内存映射。初始化成功后,向映射内存写入一个像素值,用于验证写入路径可用。

环境与依赖

  • Linux系统,内核已启用CONFIG_FB_DEVICE(标准内核默认开启)
  • LCD设备节点:/dev/fb0(若为其他编号,修改代码中的设备路径)
  • 当前用户需有设备读写权限(可加入video组或使用sudo运行)
  • 编译依赖:仅需标准C库与Linux内核头文件(linux/fb.h、sys/mman.h)

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>

int main(void) {
    const char *fb_path = "/dev/fb0";
    int fd = open(fb_path, O_RDWR);
    if (fd < 0) {
        perror("open /dev/fb0");
        return 1;
    }

    struct fb_fix_screeninfo finfo;
    struct fb_var_screeninfo vinfo;

    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
        perror("ioctl FBIOGET_FSCREENINFO");
        close(fd);
        return 1;
    }
    if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
        perror("ioctl FBIOGET_VSCREENINFO");
        close(fd);
        return 1;
    }

    printf("分辨率: %ux%u\n", vinfo.xres, vinfo.yres);
    printf("色深: %u bpp\n", vinfo.bits_per_pixel);
    printf("行字节数: %u\n", finfo.line_length);
    printf("屏幕总字节数: %u\n", finfo.smem_len);

    /* 计算一帧所需字节数(行字节数 × 行数) */
    size_t frame_size = finfo.line_length * vinfo.yres;
    if (frame_size > finfo.smem_len) {
        fprintf(stderr, "错误: 计算帧大小超过显存大小\n");
        close(fd);
        return 1;
    }

    /* 映射显存到用户空间 */
    void *fbp = mmap(NULL, frame_size, PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0);
    if (fbp == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }

    /* 写入一个像素(假设32bpp,ARGB8888格式,坐标(0,0)为红色) */
    if (vinfo.bits_per_pixel == 32) {
        unsigned int *pixel = (unsigned int *)fbp;
        *pixel = 0x00FF0000;  /* 不透明红色 */
        printf("已向(0,0)写入红色像素\n");
    } else {
        printf("当前色深非32bpp,跳过像素写入(仅完成初始化)\n");
    }

    /* 清理:解除映射并关闭设备 */
    munmap(fbp, frame_size);
    close(fd);
    printf("Framebuffer初始化完成并已清理\n");
    return 0;
}

编译与运行

# 编译
gcc -o fb_init fb_init.c

# 运行(若权限不足,加sudo)
./fb_init

验证方法

  1. 正常输出:程序依次打印分辨率、色深、行字节数、屏幕总字节数,最后显示“Framebuffer初始化完成并已清理”。
  2. 像素写入验证:若色深为32bpp,程序会向(0,0)写入红色像素。可在运行后观察屏幕左上角是否出现红色点(若LCD当前显示该Framebuffer内容)。
  3. 错误排查:若打开设备失败,检查/dev/fb0是否存在及权限;若ioctl失败,确认内核Framebuffer驱动已加载(ls /dev/fb*应有节点)。
  4. 内存映射检查:程序正常结束且无mmap错误,说明映射成功;munmap后无崩溃即清理正确。

关键说明

  • 代码使用finfo.line_length * vinfo.yres计算映射大小,而非直接使用finfo.smem_len,因为显存可能大于单帧所需空间(如支持双缓冲)。
  • 像素写入仅针对32bpp格式做了演示;若实际屏幕为16bpp或24bpp,需按对应格式构造像素值,本案例聚焦初始化流程,不展开各色深写入。
  • 本程序为一次性初始化验证,未实现持续显示或绘制功能;如需在屏幕上绘制图形,应在munmap前操作fbp指向的内存。