LISA Display Panel 移植适配指南

本文档说明如何为 LISA Display 驱动框架添加新的显示面板(Panel)驱动支持。

概述

LISA Display 采用分层架构,Panel 驱动层负责实现特定显示控制器(如 ST7789、AXS15231B 等)的初始化序列和专用命令。每个 Panel 驱动需要实现 lisa_display_panel_driver_t 接口。

目录结构

drivers/lisa_display/panels/
├── CMakeLists.txt          # 构建配置
├── Kconfig                 # Panel 选择配置
├── Kconfig.st7789p3        # ST7789P3 参数配置
├── Kconfig.axs15231b       # AXS15231B 参数配置
├── panel_st7789p3.c        # ST7789P3 驱动实现
├── panel_axs15231b.c       # AXS15231B 驱动实现
└── README.md               # 本文档

移植步骤

1. 创建 Panel 驱动源文件

panels/ 目录下创建 panel_<芯片型号>.c 文件:

/*
 * Copyright (c) 2025, LISTENAI
 * SPDX-License-Identifier: Apache-2.0
 */
#include <string.h>
#include "lisa_display_panel.h"
#include "lisa_mem.h"
#include "lisa_device.h"
#include "mipi_dcs.h"
#include "lisa_gpio.h"

#define LOG_TAG "panel.<芯片型号>"
#include "lisa_log.h"

/* ========================================================================
 * 1. 定义私有数据结构
 * ======================================================================== */
struct panel_<芯片型号>_priv {
    lisa_display_orientation_t orientation;
    // 其他芯片特定状态...
};

/* ========================================================================
 * 2. 定义初始化序列
 * ======================================================================== */
static const uint8_t init_sequence[] = {
    // 格式: cmd, len, data[0], data[1], ...
    // 示例:
    // 0x36, 1, 0x00,        // MADCTL
    // 0x3A, 1, 0x05,        // COLMOD: RGB565
    // ...
};

/* ========================================================================
 * 3. 实现 Panel 驱动接口
 * ======================================================================== */

static int <芯片型号>_init(lisa_display_panel_t *panel)
{
    // 1. 分配私有数据
    struct panel_<芯片型号>_priv *priv = lisa_mem_alloc(sizeof(*priv));
    if (!priv) {
        return LISA_DEVICE_ERR_NO_MEM;
    }
    panel->priv_data = priv;

    // 2. 设置显示能力
    panel->caps.width        = CONFIG_PANEL_<芯片型号>_WIDTH;
    panel->caps.height       = CONFIG_PANEL_<芯片型号>_HEIGHT;
    panel->caps.pixel_format = LISA_DISPLAY_PIXEL_FORMAT_RGB_565;
    panel->caps.orientation  = LISA_DISPLAY_ORIENTATION_0;
    panel->caps.supported_pixel_formats = (1U << LISA_DISPLAY_PIXEL_FORMAT_RGB_565);
    priv->orientation = LISA_DISPLAY_ORIENTATION_0;

    // 3. 硬件复位
    if (panel->rst_gpio) {
        lisa_gpio_write_pin(panel->rst_gpio, panel->rst_pin, 1);
        lisa_thread_mdelay(10);
        lisa_gpio_write_pin(panel->rst_gpio, panel->rst_pin, 0);
        lisa_thread_mdelay(10);
        lisa_gpio_write_pin(panel->rst_gpio, panel->rst_pin, 1);
        lisa_thread_mdelay(120);  // 根据芯片手册调整
    }

    // 4. 退出睡眠模式
    panel_write_cmd_data(panel, LCD_CMD_SLEEP_OUT, 8, NULL, 0);
    lisa_thread_mdelay(120);

    // 5. 发送初始化序列
    const uint8_t *p = init_sequence;
    while (p < init_sequence + sizeof(init_sequence)) {
        uint8_t cmd = *p++;
        uint8_t len = *p++;
        panel_write_cmd_data(panel, cmd, 8, p, len);
        p += len;
    }

    // 6. 颜色反转(可选)
#ifdef CONFIG_LISA_DISPLAY_COLOR_INVERT
    panel_write_cmd_data(panel, LCD_CMD_INVERT_ON, 8, NULL, 0);
#endif

    LISA_LOGI(LOG_TAG, "<芯片型号> initialized");
    return LISA_DEVICE_OK;
}

static int <芯片型号>_get_capabilities(lisa_display_panel_t *panel,
                                       lisa_display_capabilities_t *caps)
{
    if (!caps) {
        return LISA_DEVICE_ERR_INVALID;
    }
    memcpy(caps, &panel->caps, sizeof(*caps));
    return LISA_DEVICE_OK;
}

static int <芯片型号>_write(lisa_display_panel_t *panel, uint16_t x, uint16_t y,
                            const lisa_display_buffer_desc_t *desc, const void *buf)
{
    if (!desc || !buf) {
        return LISA_DEVICE_ERR_INVALID;
    }

    // 设置显示窗口
    lisa_mem_coord_t x_coord, y_coord;
    lisa_display_panel_mem_area_t area = {
        .panel_w = panel->caps.width,
        .panel_h = panel->caps.height,
        .x_offset = CONFIG_PANEL_<芯片型号>_X_OFFSET,
        .y_offset = CONFIG_PANEL_<芯片型号>_Y_OFFSET,
        .x = x, .y = y,
        .w = desc->width, .h = desc->height,
    };
    panel_set_mem_area(panel, &area, x_coord, y_coord);

    panel_write_cmd_data(panel, LCD_CMD_CASET, 8, x_coord, sizeof(x_coord));
    panel_write_cmd_data(panel, LCD_CMD_RASET, 8, y_coord, sizeof(y_coord));

    // 写入像素数据
    return panel_draw_pixels(panel, LCD_CMD_RAMWR, 8, x, y,
                             desc->width, desc->height, buf);
}

static int <芯片型号>_blanking_on(lisa_display_panel_t *panel)
{
    return panel_write_cmd_data(panel, LCD_CMD_DISPLAY_OFF, 8, NULL, 0);
}

static int <芯片型号>_blanking_off(lisa_display_panel_t *panel)
{
    return panel_write_cmd_data(panel, LCD_CMD_DISPLAY_ON, 8, NULL, 0);
}

static int <芯片型号>_set_brightness(lisa_display_panel_t *panel, uint8_t brightness)
{
    return panel_set_backlight_brightness(&panel->backlight, brightness);
}

static int <芯片型号>_set_orientation(lisa_display_panel_t *panel,
                                      lisa_display_orientation_t orientation)
{
    struct panel_<芯片型号>_priv *priv = panel->priv_data;

    panel->caps.orientation = orientation;
    priv->orientation = orientation;
    return LISA_DEVICE_OK;
}

/* ========================================================================
 * 4. 导出驱动接口
 * ======================================================================== */
const lisa_display_panel_driver_t lisa_display_<芯片型号>_driver = {
    .init             = <芯片型号>_init,
    .get_capabilities = <芯片型号>_get_capabilities,
    .write            = <芯片型号>_write,
    .blanking_on      = <芯片型号>_blanking_on,
    .blanking_off     = <芯片型号>_blanking_off,
    .set_brightness   = <芯片型号>_set_brightness,
    .set_orientation  = <芯片型号>_set_orientation,
};

/* ========================================================================
 * 5. 注册设备
 * ======================================================================== */
static int panel_<芯片型号>_device_init(void)
{
    LISA_LOGD(LOG_TAG, "<芯片型号> device registered");
    return LISA_DEVICE_OK;
}

/*
 * 重要: 第一个参数必须为 "lcd_panel"
 * Display 设备层通过 lisa_device_get("lcd_panel") 获取 Panel 驱动接口
 * 如果名称不匹配,将导致 Display 驱动无法正常工作
 */
LISA_DEVICE_REGISTER(lcd_panel, &lisa_display_<芯片型号>_driver, NULL, NULL,
                     &panel_<芯片型号>_device_init, LISA_DEVICE_PRIORITY_HIGH);

重要: LISA_DEVICE_REGISTER 的第一个参数必须为 lcd_panel,这是 Display 设备层获取 Panel 驱动接口的固定名称。

2. 添加 Kconfig 配置

创建 Kconfig.<芯片型号> 文件:

if LISA_DISPLAY_PANEL_<芯片型号>

config PANEL_<芯片型号>_WIDTH
    int "Panel width"
    default 240
    help
        Display panel width in pixels.

config PANEL_<芯片型号>_HEIGHT
    int "Panel height"
    default 320
    help
        Display panel height in pixels.

config PANEL_<芯片型号>_X_OFFSET
    int "X offset"
    default 0
    help
        X coordinate offset for the display area.

config PANEL_<芯片型号>_Y_OFFSET
    int "Y offset"
    default 0
    help
        Y coordinate offset for the display area.

endif # LISA_DISPLAY_PANEL_<芯片型号>

修改 Kconfig 文件,添加新面板选项:

config LISA_DISPLAY_PANEL_<芯片型号>
    bool "<芯片型号> Panel Driver"
    help
        Enable driver for <芯片型号> display panel.

并在文件末尾添加:

rsource "Kconfig.<芯片型号>"

3. 更新 CMakeLists.txt

CMakeLists.txt 中添加条件编译:

listenai_library_sources_ifdef(CONFIG_LISA_DISPLAY_PANEL_<芯片型号> panel_<芯片型号>.c)

Panel 驱动接口说明

接口

说明

必须实现

init

初始化面板,发送初始化序列

get_capabilities

获取显示能力(分辨率、像素格式等)

write

写入像素数据到指定区域

blanking_on

关闭显示(进入 blanking 模式)

blanking_off

开启显示(退出 blanking 模式)

set_brightness

设置背光亮度

set_orientation

设置显示方向

可选

公共辅助函数

Panel 抽象层提供以下辅助函数,可在驱动中直接使用:

函数

说明

panel_write_cmd_data()

发送命令和数据

panel_draw_pixels()

绘制像素数据

panel_set_backlight_brightness()

设置背光亮度

panel_reset_pin_set()

控制复位引脚

panel_set_mem_area()

计算显示区域坐标

常用 MIPI DCS 命令

mipi_dcs.h 中定义了标准 MIPI DCS 命令,常用命令包括:

宏定义

命令码

说明

LCD_CMD_SLEEP_OUT

0x11

退出睡眠模式

LCD_CMD_DISPLAY_ON

0x29

开启显示

LCD_CMD_DISPLAY_OFF

0x28

关闭显示

LCD_CMD_CASET

0x2A

设置列地址

LCD_CMD_RASET

0x2B

设置行地址

LCD_CMD_RAMWR

0x2C

写入显存

LCD_CMD_MADCTL

0x36

内存访问控制(方向)

LCD_CMD_COLMOD

0x3A

像素格式设置

LCD_CMD_INVERT_ON

0x21

开启颜色反转

LCD_CMD_INVERT_OFF

0x20

关闭颜色反转

移植注意事项

  1. 初始化序列: 从芯片手册或参考代码获取正确的初始化序列

  2. 时序要求: 注意复位和命令之间的延时要求

  3. 坐标偏移: 某些屏幕模组可能需要 X/Y 偏移配置

  4. 颜色格式: 确认屏幕支持的像素格式(RGB565/RGB888 等)

  5. 背光控制: 部分屏幕支持通过命令控制背光,部分需要 PWM

参考资料

  • 芯片数据手册(Datasheet)