一、什么是 Framebuffer
Framebuffer(帧缓存/显存)是一个用于存储一帧 LCD 图像数据的内存区域。在嵌入式系统中,Framebuffer 通常通过内存模拟实现,其大小由 LCD 的分辨率和每个像素的字节大小决定。
1、Framebuffer 的大小计算
以 480x320 的屏幕为例,在不同像素模式下,Framebuffer 的大小如下:
-
ARGB888 (32bpp):
- 计算公式:480 x 320 x 4 (bytes)
- 大小:614,400 字节
-
RGB565 (16bpp):
- 计算公式:480 x 320 x 2 (bytes)
- 大小:307,200 字节
二、Framebuffer的显示原理
Framebuffer 的显示原理可以概括为:LCD 控制器(LCDC)从 Framebuffer 中读取像素数据,并通过并行数据接口将数据传输到 LCD 面板进行显示。
1、显示流程图
以下是 Framebuffer 的显示流程:
- Framebuffer:存储像素数据。
- LCDC:从 Framebuffer 中读取像素数据,并将其传输到 LCD 面板。
- LCD Panel:接收数据并显示图像。
2、数据传输接口
LCDC 通过以下信号将数据传输到 LCD 面板:
- Clock:时钟信号,用于同步数据传输。
- Data:像素数据,包括 R(红)、G(绿)、B(蓝)三种颜色通道。
- Control:控制信号,用于管理数据传输的时序和状态。
三、openvela Framebuffer 接口
openvela 的 Framebuffer 接口分为上层用户接口和下层驱动接口,分别为用户和设备驱动程序提供了灵活的操作能力。以下是接口的详细说明。
1、上层用户接口
openvela 的 Framebuffer 用户接口类似于 Linux 系统,通过 VFS(虚拟文件系统)提供标准操作接口,包括 open、close、read、write 和 ioctl 等。用户可以通过操作 /dev/fbx 设备文件,完成以下功能:
-
映射 Framebuffer 到用户态:
使用 mmap 将 Framebuffer 映射到用户空间,便于直接对 Framebuffer 进行读写操作。
-
切换 Framebuffer:
用户可以通过 ioctl 接口切换不同的 Framebuffer 配置或模式。
2、下层驱动接口
openvela 的 Framebuffer 驱动接口用于管理 LCD 设备,设计相对简单。开发者可以参考 video/fb.h 和 /drivers/video/fb.c 文件中的实现。以下是 fb_register() 函数的源码,展示了与 Framebuffer 设备驱动相关的重要部分:
int fb_register(int display, int plane)
{
FAR struct fb_chardev_s *fb;
...
/* Initialize the frame buffer device. */
ret = up_fbinitialize(display);
if (ret < 0)
{
gerr("ERROR: up_fbinitialize() failed for display %d: %d\n",
display, ret);
goto errout_with_fb;
}
DEBUGASSERT((unsigned)plane <= UINT8_MAX);
fb->plane = plane;
fb->vtable = up_fbgetvplane(display, plane);
if (fb->vtable == NULL)
{
gerr("ERROR: up_fbgetvplane() failed, vplane=%d\n", plane);
goto errout_with_fb;
}
/* Initialize the frame buffer instance. */
...
ret = register_driver(devname, &fb_fops, 0666, (FAR void *)fb);
if (ret < 0)
{
gerr("ERROR: register_driver() failed: %d\n", ret);
goto errout_with_fb;
}
return OK;
errout_with_fb:
kmm_free(fb);
return ret;
}
从代码中可以看出,Framebuffer 针对 LCD 设备驱动程序提供了以下 3 个接口,驱动程序需要自行实现:
-
void up_fbinitialize(int display)
- 用于初始化硬件 LCD 控制器。
- 例如,在 STM32 平台上,up_fbinitialize 函数需要初始化 LTDC(LCD-TFT 控制器)或 MIPI 接口,并完成 DSI 外设和 LCD IC 的初始化。
-
FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
- 获取 LCD 的 fb_vtable_s 结构体信息。
- fb_vtable_s 是 Framebuffer 的核心结构,包含了 Framebuffer 的所有接口。通过实现该函数,LCD 控制器可以将自身信息注册到 Framebuffer 框架中。
-
驱动程序可以参考以下示例实现:
- drivers/video/vnc/vnc_fbdev.c
- boards/arm/stm32f7/stm32f746g-disco/stm32_lcd.c
-
void up_fbuninitialize(int display)
- 执行与 up_fbinitialize 相反的操作,用于释放资源。通常可以实现为空,不执行任何操作。
3、struct fb_vtable_s 结构
fb_vtable_s 是 Framebuffer 的核心结构,定义了与视频硬件交互的接口。以下是其主要功能模块:
-
核心功能。
- getvideoinfo:获取视频控制器配置和颜色平面信息。
- getplaneinfo:获取指定颜色平面的信息。
-
可选功能(根据配置启用)。
- 颜色映射(CONFIG_FB_CMAP):
- getcmap:获取当前颜色映射表。
- putcmap:更新颜色映射表。
- 硬件光标(CONFIG_FB_HWCURSOR):
- getcursor:获取光标属性。
- setcursor:设置光标配置。
- 显示更新(CONFIG_FB_UPDATE):
- updatearea:通知硬件更新指定显示区域。
- 垂直同步(CONFIG_FB_SYNC):
- waitforvsync:等待垂直同步信号,避免屏幕撕裂。
- 叠加管理(CONFIG_FB_OVERLAY):
- getoverlayinfo:获取叠加层的配置信息。
- settransp:设置叠加层的透明度。
- setchromakey:设置叠加层的色键。
- setcolor:用指定颜色填充叠加层。
- setblank:启用或禁用叠加层。
- setarea:设置叠加操作的活动区域。
- 叠加层的 Blit 和 Blend 操作(CONFIG_FB_OVERLAY_BLIT):
- blit:在叠加层之间执行 Blit 操作。
- blend:在叠加层之间执行 Blend 操作。
- 颜色映射(CONFIG_FB_CMAP):
-
其他控制功能。
- 显示平移:
- pandisplay:为多缓冲区显示执行平移操作。
- 帧率控制:
- setframerate:设置 Framebuffer 的刷新率。
- getframerate:获取当前刷新率。
- 电源管理:
- getpower:获取面板的电源状态。
- setpower:启用或禁用面板电源。
- 显示平移:
示例代码
以下是 struct fb_vtable_s 的部分定义示例:
struct fb_vtable_s
{
/* Get information about the video controller configuration and the
* configuration of each color plane.
*/
int (*getvideoinfo)(FAR struct fb_vtable_s *vtable,
FAR struct fb_videoinfo_s *vinfo);
int (*getplaneinfo)(FAR struct fb_vtable_s *vtable, int planeno,
FAR struct fb_planeinfo_s *pinfo);
#ifdef CONFIG_FB_CMAP
/* The following are provided only if the video hardware supports RGB
* color mapping
*/
int (*getcmap)(FAR struct fb_vtable_s *vtable,
FAR struct fb_cmap_s *cmap);
int (*putcmap)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_cmap_s *cmap);
#endif
#ifdef CONFIG_FB_HWCURSOR
/* The following are provided only if the video hardware supports a
* hardware cursor.
*/
int (*getcursor)(FAR struct fb_vtable_s *vtable,
FAR struct fb_cursorattrib_s *attrib);
int (*setcursor)(FAR struct fb_vtable_s *vtable,
FAR struct fb_setcursor_s *settings);
#endif
#ifdef CONFIG_FB_UPDATE
/* The following are provided only if the video hardware need extera
* notification to update display content.
*/
int (*updatearea)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_area_s *area);
#endif
#ifdef CONFIG_FB_SYNC
/* The following are provided only if the video hardware signals
* vertical sync.
*/
int (*waitforvsync)(FAR struct fb_vtable_s *vtable);
#endif
#ifdef CONFIG_FB_OVERLAY
/* Get information about the video controller configuration and the
* configuration of each overlay.
*/
int (*getoverlayinfo)(FAR struct fb_vtable_s *vtable, int overlayno,
FAR struct fb_overlayinfo_s *oinfo);
/* The following are provided only if the video hardware supports
* transparency
*/
int (*settransp)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayinfo_s *oinfo);
/* The following are provided only if the video hardware supports
* chromakey
*/
int (*setchromakey)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayinfo_s *oinfo);
/* The following are provided only if the video hardware supports
* filling the overlay with a color.
*/
int (*setcolor)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayinfo_s *oinfo);
/* The following allows to switch the overlay on or off */
int (*setblank)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayinfo_s *oinfo);
/* The following allows to set the active area for subsequently overlay
* operations.
*/
int (*setarea)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayinfo_s *oinfo);
# ifdef CONFIG_FB_OVERLAY_BLIT
/* The following are provided only if the video hardware supports
* blit operation between overlays.
*/
int (*blit)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayblit_s *blit);
/* The following are provided only if the video hardware supports
* blend operation between overlays.
*/
int (*blend)(FAR struct fb_vtable_s *vtable,
FAR const struct fb_overlayblend_s *blend);
#endif
/* Pan display for multiple buffers. */
int (*pandisplay)(FAR struct fb_vtable_s *vtable,
FAR struct fb_planeinfo_s *pinfo);
/* Specific Controls ******************************************************/
/* Set the frequency of the Framebuffer update panel (0: disable refresh) */
int (*setframerate)(FAR struct fb_vtable_s *vtable, int rate);
/* Get the frequency of the Framebuffer update panel (0: disable refresh) */
int (*getframerate)(FAR struct fb_vtable_s *vtable);
/* Get the panel power status (0: full off). */
int (*getpower)(FAR struct fb_vtable_s *vtable);
/* Enable/disable panel power (0: full off). */
int (*setpower)(FAR struct fb_vtable_s *vtable, int power);
};
开发者可以根据具体硬件需求实现这些接口,以满足 Framebuffer 的功能需求。
四、启用 Framebuffer
启用 Framebuffer 需要完成以下步骤:
1、开启 Framebuffer 编译选项
在配置文件中启用以下选项:
CONFIG_VIDEO_FB
2、注册 Framebuffer
在系统启动的初始化阶段,调用 fb_register 函数注册 Framebuffer。以下是示例代码:
#include <nuttx/video/fb.h>
#ifdef CONFIG_VIDEO_FB
ret = fb_register(0, 0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR fb_register() failed: %d\n", ret);
}
#endif
3、处理 VSync
为了避免屏幕撕裂并提高渲染性能,建议在实现中处理 VSync(垂直同步)。VSync 的具体实现和优化方法,请参考 VSync。
五、相关仓
以下是与 Framebuffer 驱动相关的代码仓库链接: