# How to Add a Display Driver

This document describes the recommended workflow for adding a new display panel under the current display driver framework. The new framework has removed the old `DSI Debugger` debug path. When adding a new panel, you should first complete the display driver, pin, and panel selection in `make menuconfig`, and then add the code following the current connector/panel framework.

This document uses a `368(H) x 552(V)` `MIPI DSI` panel as an example to walk through the complete process from menuconfig to code integration.

## Overall Workflow

The recommended steps for adding a new panel are:

1. Enable the corresponding display driver in `make menuconfig` and configure the pins.
1. Select an existing panel in `Display Panel Drivers Configuration`, or add a new panel driver for a new panel.
1. Build and run a display sample, then use `list_connector` and existing samples to verify the configuration.
1. If the panel is not yet in the SDK, add the `connector_type`, `panel_desc`, initialization sequence, and CanMV mapping following the current framework.

## Configure Display Settings in menuconfig First

Run the following from the project root directory:

```bash
make menuconfig
```

Navigate to:

```text
MPP Configuration -> Display Configuration
```

![display](https://www.kendryte.com/api/post/attachment?id=866)

### Select the Display Driver Type

Based on your hardware connection, enable the correct display driver first:

- `Enable HDMI Display Driver`
- `Enable LCD Display Driver`
- `Enable SPI LCD Display Driver`
- `Enable QSPI LCD Display Driver`
- `Enable OSPI LCD Display Driver`

For a `MIPI DSI LCD` panel, you typically need to enable `Enable LCD Display Driver`.

### Configure Display-Related Pins

Configure the pins used by your board in the same menu.

For a `MIPI DSI LCD`, at minimum confirm:

- `DSI-LCD Reset GPIO`
- `DSI-LCD BackLight GPIO`

For `HDMI`, confirm:

- `DSI-HDMI Reset GPIO`
- `DSI-HDMI I2c Bus`

For `SPI/QSPI/OSPI LCD`, in addition to reset/backlight, also confirm bus and FPIOA-related settings such as:

- `Data/Command GPIO`
- `Chip Select GPIO`
- `Reset GPIO`
- `Backlight GPIO`
- `Clock Pin`
- `Data0/MOSI Pin`
- `QSPI Bus`

![display](https://www.kendryte.com/api/post/attachment?id=865)

### Select the Panel Driver

After completing the driver type and pin configuration, select the panel driver in:

```text
Display Panel Drivers Configuration
```

Currently available panel/bridge chip drivers that can be selected directly in the SDK include:

- `Enable HDMI Display Panel Driver LT9611`
- `Enable LCD Display Panel Driver HX8399`
- `Enable LCD Display Panel Driver ST7701`
- `Enable LCD Display Panel Driver ili9806`
- `Enable LCD Display Panel Driver ili9881`
- `Enable LCD Display Panel Driver nt35516`
- `Enable LCD Display Panel Driver nt35532`
- `Enable LCD Display Panel Driver gc9503`
- `Enable LCD Display Panel Driver st7102`
- `Enable LCD Display Panel Driver aml020t`
- `Enable LCD Display Panel Driver JD9852`
- `Enable SPI LCD Panel Driver ST7789`

If your panel model is already listed here, enable it first and verify the pin and display link. If your model is not listed, continue with the "Adding the Panel in Project Code" section below.

![display](https://www.kendryte.com/api/post/attachment?id=866)

Save the configuration and rebuild the firmware.

## Verify the Current Configuration

It is recommended to verify that the menuconfig settings are correct before writing any new code.

### Enable and Build Display Samples

In `RT-Smart UserSpace Examples Configuration`, enable at least:

- `Enable MPP examples`
- One or more VO/display-related samples, such as `sample_vo_video` or `sample_vo_osd`

After rebuilding the image, locate the samples on the board.

### Check the Connectors Supported by the Current Firmware

After entering the board shell, run:

```shell
list_connector
```

This command lists the connector types and enumeration values compiled into the current firmware. It helps you confirm:

- Whether the panel driver selected in menuconfig has taken effect
- Whether a newly added panel driver has made it into the final image
- Which `connector_type` to pass when running a sample

### Run a Display Sample

For example:

```shell
./mpp/sample_vo_video.elf <connector_type>
```

If the sample can light up the enabled panel, the display link, pins, and basic timing are working. You can then add new panel code with a clearer baseline.

## Information to Gather Before Adding a New Panel

Before writing a panel driver, you typically need two categories of information:

1. Panel timing parameters
1. The initialization sequence provided by the panel vendor

Both will go into the panel driver source code, rather than a configuration file on the SD card as in the old workflow.

### Panel Timing

Using the example panel in this document, timing information typically includes:

```shell
pclk_hz=27000000
fps=60
lane_num=2

hactive=368
hsync=8
hbp=16
hfp=16

vactive=552
vsync=48
vbp=250
vfp=250
```

These values map to the `timing` field in `panel_desc`, for example:

- `pclk_hz` / `pclk_khz`
- `hactive`
- `hsync_len`
- `hback_porch`
- `hfront_porch`
- `vactive`
- `vsync_len`
- `vback_porch`
- `vfront_porch`

You can still use the timing calculation tool to assist:

[K230 MIPI DSI Connector Info Generator](https://kendryte-download.canaan-creative.com/developer/common/K230_MIPI_DSI_Connector_Info_Generator.html)

> This tool only validates whether timing parameters can be generated.

### Initialization Sequence

Vendors typically provide a register initialization table, for example:

```shell
{0xFF,5,{0x77,0x01,0x00,0x00,0x13}},
{0xEF,1,{0x08}},
{0xFF,5,{0x77,0x01,0x00,0x00,0x10}},
{0xC0,2,{0x44,0x00}},
{0xC1,2,{0x0B,0x02}},
{0xC2,2,{0x07,0x1F}},
```

In the current framework these are converted into a command sequence array in the panel source file, such as the `init_sequence` in `mipi_st7701.c`:

```c
const k_u8 init_sequence[] = {
    0x39, 0, 6, 0xFF, 0x77, 0x01, 0x00, 0x00, 0x13,
    0x15, 0, 2, 0xEF, 0x08,
    0x39, 0, 3, 0xC0, 0x44, 0x00,
};
```

The command format is:

```text
cmd_type, delay_ms, cmd_data_length, cmd_data0 ... cmd_dataN
```

Common `cmd_type` values:

- `0x05`: single-byte command, no parameters
- `0x15`: single-byte command with one parameter
- `0x39`: long command with multiple parameters

Two conversion examples:

```shell
{0xB0,16,{0x0F,0x1E,0x25,0x0D,0x11,0x06,0x12,0x08,0x08,0x2A,0x05,0x12,0x10,0x2B,0x32,0x1F}},

# Remove outer braces
# 0xB0 is the command, followed by 16 parameter bytes, so use 0x39
# Length = 1 command byte + 16 parameter bytes = 17

0x39,0,17,0xB0,0x0F,0x1E,0x25,0x0D,0x11,0x06,0x12,0x08,0x08,0x2A,0x05,0x12,0x10,0x2B,0x32,0x1F
```

```shell
{0x11,0,{0x00}},
{REGFLAG_DELAY,120,{}},

# This group can also be placed in the init_sequence array
# Treating it as "1 command + 1 parameter":

0x15,120,2,0x11,0x00
```

## Adding the Panel in Project Code

The current framework does not simply copy an old panel file and rename it. It is organized around `connector_type`, `panel_desc`, `panel_ops`, and `panel_drv`.

### Define or Confirm the `connector_type`

Panel type definitions are located in:

- `src/rtsmart/mpp/include/comm/k_connector_comm.h`

The project uses `K_CONN_TYPE(chip, bus, w, h, ver)` to generate `k_connector_type`. When adding a new panel, first add a new type constant for the new model, following the naming style of existing definitions:

- `ST7701_480_800_DSI_V1`
- `ST7701_480_854_DSI_V1`
- `ST7701_480_640_DSI_V1`
- `ST7701_368_544_DSI_V1`

If you are adding a new resolution variant of an existing chip, prefer the existing chip naming convention rather than inventing a new one.

### Add the Initialization and Descriptor in the Panel Source File

DSI panel implementations are usually located in:

- `src/rtsmart/mpp/kernel/connector/src/panels/`

For example, the ST7701 implementation is in:

- `src/rtsmart/mpp/kernel/connector/src/panels/mipi_st7701.c`

A new panel typically needs at minimum:

1. An initialization function corresponding to `init_sequence`
1. A `panel_ops`
1. A `panel_desc`
1. A `panel_drv` or a new variant attached to an existing `panel_drv`

Key fields in `panel_desc` include:

- `name`
- `connector_type`
- `bus_type`
- `timing`
- `gpio`
- `bus`
- `bus_ops`
- `ops`

For a DSI panel, `gpio` typically references the pins configured in menuconfig:

```c
.gpio = {
    .reset_pin = CONFIG_MPP_DSI_LCD_RESET_PIN,
    .backlight_pin = CONFIG_MPP_DSI_LCD_BACKLIGHT_PIN,
    .reset_delay_ms = 10,
    .backlight_delay_ms = 0,
    .reset_active_low = K_TRUE,
    .backlight_active_low = K_FALSE,
},
```

This is why you should configure the pins in `Display Configuration` before adding panel code.

### Register the New Panel in the Driver Framework

The connector core looks up available panels from `connector_drv_list[]`. The relevant logic is in:

- `src/rtsmart/mpp/kernel/connector/src/connector_dev.c`

The lookup flow is:

1. Iterate over `connector_drv_list[]`
1. Iterate over each driver's `panel_variants`
1. Match the target panel by `connector_type`

When adding a new panel, ensure it is included in a `panel_drv`'s `panel_variants`, and that the driver itself is compiled into the image.

### Wire the New Panel into Kconfig and Makefile

After writing the panel source code, connect it to the build system.

Relevant files:

- `src/rtsmart/mpp/Kconfig`
- `src/rtsmart/mpp/kernel/connector/Makefile`

Kconfig exposes the new panel under:

```text
MPP Configuration -> Display Configuration -> Display Panel Drivers Configuration
```

The Makefile decides whether to compile the source file based on the Kconfig option. For example, existing DSI panels are wired in as:

```make
src-$(CONFIG_MPP_DSI_ENABLE_LCD_ST7701) += src/panels/mipi_st7701.c
```

Add a corresponding entry for the new panel and add the matching `config` entry in `Kconfig`.

### Add CanMV Python Interface Mapping (If Needed)

If the panel should also be selectable via the CanMV Python interface—not just in C samples—also update:

- `src/canmv/port/modules/modmedia.display.c`

Two parts need updating:

1. The `PY_PANEL_TYPE_*` enum
1. The `py_display_panel_map[]` mapping table

Only after the new `connector_type` is mapped into `py_display_panel_map[]` can the CanMV Python layer select it by panel type and resolution.

## Minimum Checklist for Adding a New Panel

Before submitting code, verify at least the following:

1. The new panel option is visible in `make menuconfig`.
1. The reset/backlight/bus pins in `Display Configuration` match the actual hardware.
1. The `Makefile` compiles the corresponding panel source file based on the new Kconfig option.
1. The `connector_type` is defined in `k_connector_comm.h`.
1. The `panel_desc` has timing, lane count, GPIO, and initialization sequence filled in.
1. The `connector_drv_list[]` lookup path can reach the new panel.
1. The new panel appears in `list_connector` on the board.
1. `sample_vo_video` or another display sample can light up the panel.
1. If Python support is needed, `py_display_panel_map[]` has been updated.

## Troubleshooting

### A panel option is not visible in menuconfig

Check:

1. Whether the corresponding display driver is enabled first, e.g. `Enable LCD Display Driver` or `Enable SPI LCD Display Driver`.
1. Whether the Kconfig entry `depends on` an upstream driver switch.
1. Whether the new panel's Kconfig configuration has been connected.

### Build succeeds but `list_connector` does not show the new panel

Check:

1. Whether the `Makefile` compiles the panel source file.
1. Whether the driver list in `connector_dev.c` includes the `panel_drv` for this panel.
1. Whether the new `panel_desc` is actually attached to `panel_variants`.

> `list_connector` is only compiled in the RTOS SDK.

### Panel powers on but shows no image

Check:

1. Whether the reset/backlight GPIO configuration is correct.
1. Whether the DSI lane count, pixel clock, porch, and sync parameters are correct.
1. Whether the vendor initialization sequence is complete and delays are preserved.
1. Whether the `connector_type` passed to the sample matches the new panel.
1. Check the serial log. If the issue persists, post on the forum for help.

## References

- Current display driver switches and panel list: [`../userguide/display_list.md`](../userguide/display_list.md)
- Display sample usage: [`../app_develop_guide/media/display.md`](../app_develop_guide/media/display.md)
- VO/Display API reference: [`../api_reference/mpp/display.md`](../api_reference/mpp/display.md)
