RGB LCD 驱动

概述

lisa_rgb 是针对 RGB (并口) LCD 显示屏的设备驱动模型,封装了对 HAL 层 Driver_RGBDriver_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_dev

  • API 调用链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

工作流程

  1. 等待写入信号量(确保上一帧已完成切换)

  2. 拷贝新数据到非显示缓冲区(fb_buf[1 - display_idx]

  3. 设置 swap_pending = 1,标记有新帧待显示

  4. DMA 中断会在下一帧传输完成时自动切换 display_idx

注意

  • 此函数在 Bounce Buffer 模式下自动管理双缓冲,应用层无需关心缓冲区切换逻辑

  • 如果传入的 size 超过帧缓冲大小,会被截断并输出警告

  • 函数内部会阻塞等待信号量(最长 1000ms),确保不与上一次写入冲突

注意事项

  1. GPDMA 通道冲突:确保配置的 GPDMA 通道不与其他外设冲突

  2. 帧缓冲区对齐:帧缓冲区地址建议 32 字节对齐以获得最佳性能

  3. 时钟频率:像素时钟频率需要根据 LCD 面板规格配置

  4. 连续模式:在连续刷新模式下,无需调用 wait_done(),RGB 控制器会自动循环发送数据

  5. D-Cache:如果启用 D-Cache,需要在更新帧缓冲区后刷新 Cache

  6. 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

故障排查

屏幕无显示

  1. 检查 PCLK 频率是否正确

  2. 检查时序参数是否匹配 LCD 规格

  3. 检查信号极性配置

  4. 确认帧缓冲区数据正确

屏幕闪烁

  1. 检查帧率是否太低

  2. 检查 GPDMA 传输是否及时

  3. 确认时序参数稳定

  4. 验证 Bounce Buffer 大小是否为帧缓冲大小的整数因子

颜色错误

  1. 检查输入/输出格式配置

  2. 检查 RGB 数据线接线

  3. 确认 LSB/MSB 配置正确

  4. 验证 bpp 计算与实际格式匹配(RGB565=16, RGB888=24)