RGB LCD 驱动
概述
lisa_rgb 是针对 RGB (并口) LCD 显示屏的设备驱动模型,封装了对 HAL 层 Driver_RGB 和 Driver_GPDMA 的调用,提供统一的设备接口。
功能特性
✅ 支持 RGB565/RGB888 输入格式
✅ 支持 RGB565/RGB666/RGB888 输出格式
✅ 支持 8/16/24 位并口输出
✅ 支持 SYNC+DE / SYNC-ONLY 同步模式
✅ 支持单次传输 / 连续刷新模式
✅ 使用 GPDMA 高效传输帧缓冲数据
✅ 提供互斥锁保护多线程访问
✅ 信号量同步传输完成事件
架构设计
┌────────────────────────────────────────────────────────────┐
│ 应用层 (LVGL / Panel 驱动) │
├────────────────────────────────────────────────────────────┤
│ Display Bus API (lisa_display_bus_write_pixels) │
├────────────────────────────────────────────────────────────┤
│ RGB 总线层 (lisa_display_bus_rgb.c) │
│ - rgb_bus_write_pixels() 转发像素数据 │
│ - 持有 RGB 控制器设备引用 (priv->rgb_dev) │
├────────────────────────────────────────────────────────────┤
│ RGB 控制器层 (lisa_rgb_arcs.c) │
│ - arcs_rgb_update_framebuffer() 管理双缓冲 │
│ - bounce_buffer_fill() 分块传输 │
│ - gpdma_event_callback() 自动切换缓冲区 │
├────────────────────────────────────────────────────────────┤
│ HAL Driver_RGB + Driver_GPDMA │
├────────────────────────────────────────────────────────────┤
│ 硬件 RGB 控制器 + GPDMA │
└────────────────────────────────────────────────────────────┘
关键设计:
双层架构:总线层(bus)作为抽象接口,控制器层(controller)负责硬件实现
设备引用传递:总线层在
rgb_bus_attach()时保存控制器设备引用priv->rgb_devAPI 调用链:
rgb_bus_write_pixels()→lisa_rgb_update_framebuffer(priv->rgb_dev)→arcs_rgb_update_framebuffer()独立命令通道:Panel 初始化命令通过独立的软件 SPI/I2C 通道发送,不经过 RGB 数据总线
快速开始
典型使用流程
#include "lisa_device.h"
#include "lisa_rgb.h"
#include "lisa_display.h"
// 1. 获取设备(由设备框架自动注册)
lisa_device_t *rgb = lisa_device_get("rgb0");
lisa_device_t *display = lisa_device_get("display");
// 2. 通过 Display Bus API 配置 RGB(推荐方式)
lisa_display_config_t config = {
.bus_type = LISA_DISPLAY_BUS_RGB,
.bus_config.rgb = {
.rgb_dev = rgb,
.bounce_buffer_size = 480 * 10, // 10 行像素
.input_format = LISA_RGB_INPUT_FORMAT_RGB565,
.output_format = LISA_RGB_OUTPUT_FORMAT_RGB565,
.timings = {
.h_res = 480, .v_res = 480,
.h_pulse_width = 10, .h_front_blanking = 20,
.h_back_blanking = 10, .v_pulse_width = 10,
.v_front_blanking = 10, .v_back_blanking = 1,
},
.pclk_hz = 6000000,
.cmd_bus_dev = cmd_bus, // 独立命令通道
},
};
lisa_display_attach_bus(display, &config);
// 3. RGB 传输已自动启动,直接更新帧缓冲即可
uint16_t *framebuffer = allocate_framebuffer();
memset(framebuffer, 0xFFFF, 480 * 480 * 2); // 填充白色
// 4. 更新显示内容(通过 Display Bus 层)
lisa_display_write(display, 0, 0, &desc, framebuffer);
// 或者直接调用 RGB API(高级用法)
lisa_rgb_update_framebuffer(rgb, framebuffer, 480 * 480 * 2);
重要提示:
✅ 推荐:通过
lisa_display_attach_bus()使用 RGB,由框架自动管理⚠️ 高级:直接调用
lisa_rgb_*()API 需要理解双层架构❌ 错误:不要混用 Display Bus 层和 RGB 控制器层的 API
配置选项
在 menuconfig 中配置驱动参数:
Device Drivers
└─ LISA Device Drivers
└─ [*] Enable LISA RGB LCD driver
├─ (1) GPDMA channel for RGB data transfer
├─ (6000000) RGB pixel clock frequency (Hz)
├─ (480) Horizontal resolution (pixels)
├─ (480) Vertical resolution (pixels)
├─ RGB output bus width (24-bit RGB)
├─ RGB input data format (RGB565)
├─ [*] Enable continuous DE signal output
└─ [*] Enable continuous frame mode
使用示例
1. 获取设备实例
#include "lisa_device.h"
#include "lisa_rgb.h"
lisa_device_t *rgb = lisa_device_get(LISA_RGB0_NAME);
if (!rgb) {
// 设备未注册或初始化失败
return;
}
2. 启动 RGB 传输
// RGB 传输由 Display Bus 层在 attach 时自动启动
// 如果直接使用 RGB API,只需调用:
int ret = lisa_rgb_start(rgb);
if (ret != LISA_DEVICE_OK) {
// 启动失败
}
// 注意:
// - RGB 控制器启动后会持续运行,自动循环显示当前帧缓冲
// - 使用 Bounce Buffer 模式,无需手动管理帧缓冲切换
// - 推荐通过 Display Bus 层使用,由框架自动管理启动
3. 等待传输完成(单次模式)
// 等待传输完成(最长 1000ms)
ret = lisa_rgb_wait_done(rgb, 1000);
if (ret == LISA_DEVICE_ERR_TIMEOUT) {
// 传输超时
}
4. 停止传输
ret = lisa_rgb_stop(rgb);
if (ret != LISA_DEVICE_OK) {
// 停止失败
}
5. 更新帧缓冲区(Bounce Buffer 模式)
uint16_t *framebuffer = get_current_framebuffer();
// ... LVGL 或应用层绘制新内容到 framebuffer ...
// 更新显示内容(拷贝到非显示缓冲区并标记待切换)
int ret = lisa_rgb_update_framebuffer(rgb, framebuffer, 480 * 480 * 2);
if (ret != LISA_DEVICE_OK) {
// 更新失败(可能是信号量超时)
}
// DMA 中断会在下一帧完成时自动切换显示缓冲区
6. 完整示例流程
#include "lisa_device.h"
#include "lisa_display.h"
// 1. 通过 Display Bus 层配置(推荐)
lisa_device_t *display = lisa_device_get("display");
lisa_display_config_t config = {
.bus_type = LISA_DISPLAY_BUS_RGB,
.bus_config.rgb = {
.rgb_dev = lisa_device_get("rgb0"),
.bounce_buffer_size = 480 * 10,
.input_format = LISA_RGB_INPUT_FORMAT_RGB565,
// ... 其他配置 ...
},
};
lisa_display_attach_bus(display, &config); // 自动调用 setup 和 start
// 2. 更新显示内容
uint16_t *fb = allocate_framebuffer();
draw_content(fb); // 绘制内容
lisa_display_write(display, 0, 0, &desc, fb); // 通过 Display Bus 更新
7. Bounce Buffer 模式
Bounce Buffer 模式通过小的内部 RAM 缓冲区分块传输大的 PSRAM 帧缓冲,实现高效的显示刷新。这是唯一支持的工作模式。
7.1 配置
lisa_display_bus_rgb_config_t config = {
// ... 其他配置 ...
.bounce_buffer_size = 480 * 10, // 10 行像素数(驱动会根据 bpp 自动计算字节数)
.input_format = LISA_RGB_INPUT_FORMAT_RGB565, // RGB565 格式,bpp=16
};
// 实际 bounce buffer 内存分配大小 = bounce_buffer_size * bpp / 8
// 例如:480 * 10 * 16 / 8 = 9600 字节
7.2 使用示例
lisa_device_t *rgb = lisa_device_get(LISA_RGB0_NAME);
// 启动 RGB 传输(Bounce Buffer 模式会自动初始化)
lisa_rgb_start(rgb);
// 更新图像数据
uint16_t *new_frame = get_new_frame_data();
lisa_rgb_update_framebuffer(rgb, new_frame, 480 * 480 * 2);
// DMA 会自动:
// 1. 等待上一帧显示完成
// 2. 拷贝新帧数据到非显示缓冲区
// 3. 在下一帧传输完成时切换缓冲区
// 说明:
// - lisa_rgb_start() 会自动初始化 Bounce Buffer 和 Ping-Pong DMA
// - 双帧缓冲已在 lisa_rgb_setup() 中分配(PSRAM)
// - Bounce Buffer 已在 lisa_rgb_setup() 中分配(内部 SRAM)
7.3 工作原理
┌─────────────────────────────────────────────────────┐
│ PSRAM 帧缓冲 (480x480x2 = 460KB) │
│ [显示缓冲 fb_buf[0]] [写入缓冲 fb_buf[1]] │
└──────────────┬──────────────────────────────────────┘
│ 分块拷贝
▼
┌─────────────────────────────────────────────────────┐
│ 内部 RAM Bounce Buffer (480x10x2 = 9.6KB) │
│ [Ping Buffer] ⇄ [Pong Buffer] │
└──────────────┬──────────────────────────────────────┘
│ GPDMA Ping-Pong 传输
▼
┌─────────────────────────────────────────────────────┐
│ RGB 控制器 FIFO │
└─────────────────────────────────────────────────────┘
7.4 优势
内存效率:Bounce Buffer 只需几KB内部RAM,帧缓冲使用PSRAM
无闪烁:双缓冲机制确保显示和写入分离
自动管理:DMA 中断自动填充和切换,应用层无需手动干预
高性能:内部 RAM 作为 DMA 源,传输速度快
API 参考
数据结构
lisa_display_bus_rgb_config_t
RGB 总线配置结构体,用于配置 RGB 控制器和 Bounce Buffer 模式。
关键字段:
typedef struct {
lisa_device_t *rgb_dev; // RGB 控制器设备(必需)
lisa_device_t *cmd_bus_dev; // 独立命令总线设备(可选,用于 Panel 初始化)
uint32_t bounce_buffer_size; // Bounce Buffer 大小(像素数,非字节数)
lisa_rgb_input_format_t input_format; // 输入格式(RGB565/RGB888)
lisa_rgb_output_format_t output_format; // 输出格式
lisa_rgb_timings_t timings; // 时序参数
uint32_t pclk_hz; // 像素时钟频率
lisa_rgb_polarity_t hsync_polarity; // 水平同步极性
lisa_rgb_polarity_t vsync_polarity; // 垂直同步极性
lisa_rgb_polarity_t de_polarity; // 数据使能极性
lisa_rgb_polarity_t pclk_polarity; // 像素时钟极性
bool output_lsb_first; // 是否 LSB 优先输出
} lisa_display_bus_rgb_config_t;
lisa_rgb_timings_t
RGB 时序参数结构体。
字段说明:
typedef struct {
uint16_t h_res; // 水平分辨率(像素)
uint16_t v_res; // 垂直分辨率(像素)
uint16_t h_pulse_width; // 水平同步脉冲宽度(PCLK)
uint16_t h_front_blanking; // 水平前肩消隐(PCLK)
uint16_t h_back_blanking; // 水平后肩消隐(PCLK)
uint16_t v_pulse_width; // 垂直同步脉冲宽度(行)
uint16_t v_front_blanking; // 垂直前肩消隐(行)
uint16_t v_back_blanking; // 垂直后肩消隐(行)
} lisa_rgb_timings_t;
函数接口
lisa_rgb_setup()
配置 RGB 控制器和 Bounce Buffer 模式。
函数签名:
int lisa_rgb_setup(lisa_device_t *dev, const lisa_display_bus_rgb_config_t *config);
功能:
初始化 RGB 控制器硬件参数(时序、格式、极性等)
启用 RGB 像素时钟输出
初始化 GPDMA 通道配置
分配双帧缓冲区(PSRAM,每个
fb_size字节)分配 Bounce Buffer(内部 SRAM,每个
bb_size字节)初始化信号量和互斥锁
参数:
config->bounce_buffer_size: Bounce Buffer 大小(单位:像素数)config->input_format: 输入格式(RGB565/RGB888)config->output_format: 输出格式config->timings: 时序参数(分辨率、消隐期等)config->pclk_hz: 像素时钟频率
注意:
此函数通常由 Display Bus 层在
attach时自动调用应用层一般不需要直接调用此函数
bounce_buffer_size必须使得fb_size % (bounce_buffer_size * bpp / 8) == 0
lisa_rgb_start()
启动 RGB 传输,初始化 Bounce Buffer 并启动 GPDMA Ping-Pong 传输。
函数签名:
int lisa_rgb_start(lisa_device_t *dev);
功能:
预填充两个 Bounce Buffer(Ping 和 Pong)
启动 GPDMA Ping-Pong DMA 传输
启动 RGB 控制器连续输出
注意:
此函数只需在初始化时调用一次
调用前必须已通过
lisa_rgb_setup()完成配置启动后 RGB 控制器会持续输出,自动循环显示当前帧缓冲内容
lisa_rgb_stop()
停止 RGB 传输。
函数签名:
int lisa_rgb_stop(lisa_device_t *dev);
功能:
停止 RGB 控制器输出
不会停止 GPDMA(GPDMA 会自动在缓冲区耗尽后停止)
注意:正常使用时通常不需要停止 RGB 传输
lisa_rgb_wait_done()
等待传输完成(仅在单次传输模式下需要)。
注意:Bounce Buffer 模式下通常不需要调用此函数,因为双缓冲机制会自动管理同步。
lisa_rgb_enable_clock()
启用/禁用像素时钟输出。
lisa_rgb_update_framebuffer()
更新帧缓冲区数据,将新帧数据拷贝到非显示缓冲区并标记待切换。这是 Bounce Buffer 模式下更新显示内容的主要接口。
函数签名:
int lisa_rgb_update_framebuffer(lisa_device_t *dev, const void *buf, uint32_t size);
参数:
dev: RGB 控制器设备(注意:必须是rgb0设备,而非panel_bus_rgb总线设备)buf: 新的帧缓冲区数据指针size: 数据大小(字节),建议为完整帧大小(width * height * bpp / 8)
工作流程:
等待写入信号量(确保上一帧已完成切换)
拷贝新数据到非显示缓冲区(
fb_buf[1 - display_idx])设置
swap_pending = 1,标记有新帧待显示DMA 中断会在下一帧传输完成时自动切换
display_idx
注意:
此函数在 Bounce Buffer 模式下自动管理双缓冲,应用层无需关心缓冲区切换逻辑
如果传入的
size超过帧缓冲大小,会被截断并输出警告函数内部会阻塞等待信号量(最长 1000ms),确保不与上一次写入冲突
注意事项
GPDMA 通道冲突:确保配置的 GPDMA 通道不与其他外设冲突
帧缓冲区对齐:帧缓冲区地址建议 32 字节对齐以获得最佳性能
时钟频率:像素时钟频率需要根据 LCD 面板规格配置
连续模式:在连续刷新模式下,无需调用
wait_done(),RGB 控制器会自动循环发送数据D-Cache:如果启用 D-Cache,需要在更新帧缓冲区后刷新 Cache
Bounce Buffer 模式(必需):
bounce_buffer_size配置必须设置为 > 0(单位:像素数)实际分配大小 =
bounce_buffer_size * bpp / 8字节Bounce buffer 字节大小必须是帧缓冲字节大小的整数因子
推荐配置:10-20 行像素(如
480 * 10,RGB565 下占 9600 字节)使用
lisa_rgb_update_framebuffer()更新帧数据自动双缓冲机制,无需手动管理缓冲区切换
帧缓冲分配在 PSRAM,Bounce buffer 分配在内部 SRAM
内部自动使用 Ping-Pong DMA 进行高效传输
RGB 总线层会自动路由到正确的 RGB 控制器设备
硬件接口
RGB 信号引脚
信号 |
描述 |
方向 |
|---|---|---|
PCLK |
像素时钟 |
输出 |
HSYNC |
水平同步 |
输出 |
VSYNC |
垂直同步 |
输出 |
DE |
数据使能 |
输出 |
R[7:0] |
红色数据 |
输出 |
G[7:0] |
绿色数据 |
输出 |
B[7:0] |
蓝色数据 |
输出 |
时序参数示例
以 480x480 LCD 为例:
水平时序:
h_res = 480
h_pulse_width = 10
h_front_blanking = 20
h_back_blanking = 10
总水平周期 = 480 + 10 + 20 + 10 = 520 PCLK
垂直时序:
v_res = 480
v_pulse_width = 10
v_front_blanking = 10
v_back_blanking = 1
总垂直周期 = 480 + 10 + 10 + 1 = 501 行
帧率计算:
PCLK = 6MHz
帧率 = 6,000,000 / (520 * 501) ≈ 23 fps
故障排查
屏幕无显示
检查 PCLK 频率是否正确
检查时序参数是否匹配 LCD 规格
检查信号极性配置
确认帧缓冲区数据正确
屏幕闪烁
检查帧率是否太低
检查 GPDMA 传输是否及时
确认时序参数稳定
验证 Bounce Buffer 大小是否为帧缓冲大小的整数因子
颜色错误
检查输入/输出格式配置
检查 RGB 数据线接线
确认 LSB/MSB 配置正确
验证
bpp计算与实际格式匹配(RGB565=16, RGB888=24)