
# 新增一个mipi屏幕

在本文档会演示如何新增一个 368(H) X 552(V) 的 `mipi` 屏幕。

## 使用屏幕调试助手

在 [CanMV-K230](https://github.com/kendryte/canmv_k230) 工程中的子仓库 [mpp](https://github.com/canmv-k230/mpp/) 里增加了一个屏幕调试助手，用户可将该功能使能后，通过修改存储在 `SDCard` 中的配置文件快速的调试屏幕时序以及初始化序列，不再需要频繁的修改代码编译固件。

### 使能 `DSI Debugger`

在工程根目录执行 `make menuconfig`，使能选项 `Enable DSI Debuger`。

![Enable DSI Debuger](https://www.kendryte.com/api/post/attachment?id=488)

保存配置后，编译生成新的固件，烧录固件。

### 生成 `display_debugger_config.txt`

在工程中有一个配置文件的模板，路径为 `src/rtsmart/mpp/userapps/src/connector/display_debugger_config.txt`。它的各项参数含义大概如下：

```shell
[config]
pclk_hz=33000000        # pclk in hz
fps=60                  # target fps
lane_num=2              # mipi dsi lane number, choice in 1, 2, 4

hactive=480
hsync=8
hbp=32
hfp=32

vactive=800
vsync=10
vbp=150
vfp=140

# !!! every line length should < 256

# cmd_type:
# 0x05  Command type: Single byte data (DCS Short Write, no parameters)
# 0x15  Command type: Two byte data (DCS Short Write, 1 parameter)
# 0x39  Command type: Multi byte data (DCS Long Write, n parameters n >= 2)

# format: cmd_type, delay_ms, cmd_data_length, cmd_data0 ... cmd_dataN

# 初始化序列的格式为：cmd_type, delay_ms, cmd_data_length, cmd_data0 ... cmd_dataN
#
# 现在支持3种Command type：
# 0x05 只写一个字节，不带参数
# 0x15 只写两个字节，带一个参数
# 0x39 可写多个字节，带大于两个参数
#
# 以 0x39,10,3,0xE8,0x00,0x0C 为例
# 0x39                  0x39命令，代表我们现在要写多个字节数据
# 十进制数，代表我们执行完这个命令之后要延时10个毫秒才会执行下一条命令
# 十进制数，代表我们这次的0x39命令会写3个字节的数据
# 0xE8,0x00,0x0C        3个字节的数据里面，0xE8是命令，0x00,0x0C是参数，即这是一个带两个参数的命令
#
# 注意，0x39 和 0xE8 都是命令，但是要区分开。前者是MIPI显示接口协议中的一种命令类型，后者是屏幕初始化序列里面的一个特定的命令字节，通常在屏幕初始化过程中用来指定某些设置，具体而言，这个命令可能是用来启用或禁用某些功能（如显示模式、对比度、颜色配置等）。

[init-sequence]
0x05,0,1,0x01
0x05,10,1,0x11
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x11
0x15,0,2,0xD1,0x11
0x15,0,2,0x55,0xB0
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x10
0x39,0,3,0xC0,0x63,0x00
0x39,0,3,0xC1,0x04,0x02
0x39,0,3,0xC2,0x37,0x08
0x15,0,2,0xC7,0x00
0x15,0,2,0xCC,0x38
0x39,0,17,0xB0,0x00,0x11,0x19,0x0C,0x10,0x06,0x07,0x0A,0x09,0x22,0x04,0x10,0x0E,0x28,0x30,0x1C
0x39,0,17,0xB1,0x00,0x12,0x19,0x0D,0x10,0x04,0x06,0x07,0x08,0x23,0x04,0x12,0x11,0x28,0x30,0x1C
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x11
0x15,0,2,0xB0,0x4D
0x15,0,2,0xB1,0x60
0x15,0,2,0xB2,0x07
0x15,0,2,0xB3,0x80
0x15,0,2,0xB5,0x47
0x15,0,2,0xB7,0x8A
0x15,0,2,0xB8,0x21
0x15,0,2,0xC1,0x78
0x15,0,2,0xC2,0x78
0x15,0,2,0xD0,0x88
0x39,0,4,0xE0,0x00,0x00,0x02
0x39,0,12,0xE1,0x01,0xA0,0x03,0xA0,0x02,0xA0,0x04,0xA0,0x00,0x44,0x44
0x39,0,12,0xE2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
0x39,0,5,0xE3,0x00,0x00,0x33,0x33
0x39,0,3,0xE4,0x44,0x44
0x39,0,17,0xE5,0x01,0x26,0xA0,0xA0,0x03,0x28,0xA0,0xA0,0x05,0x2A,0xA0,0xA0,0x07,0x2C,0xA0,0xA0
0x39,0,5,0xE6,0x00,0x00,0x33,0x33
0x39,0,3,0xE7,0x44,0x44
0x39,0,17,0xE8,0x02,0x26,0xA0,0xA0,0x04,0x28,0xA0,0xA0,0x06,0x2A,0xA0,0xA0,0x08,0x2C,0xA0,0xA0
0x39,0,8,0xEB,0x00,0x01,0xE4,0xE4,0x44,0x00,0x40
0x39,0,17,0xED,0xFF,0xF7,0x65,0x4F,0x0B,0xA1,0xCF,0xFF,0xFF,0xFC,0x1A,0xB0,0xF4,0x56,0x7F,0xFF
0x15,0,2,0xEE,0x42
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x00
0x15,0,2,0x36,0x00
0x15,0,2,0x3A,0x55
0x05,10,1,0x11
0x05,0,1,0x29

```

接下来，我们根据自己的屏幕修改对应的屏幕时序和初始化序列，然后生成自己屏幕的 `display_debugger_config.txt` ，以本文档所调试的屏幕为例子，最后会调整出一个这样的文件。（记住将配置文件中的注释删掉）

```shell
[config]
pclk_hz=27000000
fps=60
lane_num=2

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

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

[init-sequence]
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x13
0x15,0,2,0xEF,0x08
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x10
0x39,0,3,0xC0,0x44,0x00
0x39,0,3,0xC1,0x0B,0x02
0x39,0,3,0xC2,0x07,0x1F
0x15,0,2,0xCC,0x10
0x39,0,17,0xB0,0x0F,0x1E,0x25,0x0D,0x11,0x06,0x12,0x08,0x08,0x2A,0x05,0x12,0x10,0x2B,0x32,0x1F
0x39,0,17,0xB1,0x0F,0x1E,0x25,0x0D,0x11,0x05,0x12,0x08,0x08,0x2B,0x05,0x12,0x10,0x2B,0x32,0x1F
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x11
0x15,0,2,0xB0,0x35
0x15,0,2,0xB1,0x45
0x15,0,2,0xB2,0x87
0x15,0,2,0xB3,0x80
0x15,0,2,0xB5,0x49
0x15,0,2,0xB7,0x85
0x15,0,2,0xB8,0x11
0x15,0,2,0xBB,0x03
0x15,0,2,0xC0,0x07
0x15,0,2,0xC1,0x78
0x15,0,2,0xC2,0x78
0x15,100,2,0xD0,0x88
0x39,0,4,0xE0,0x00,0x00,0x02
0x39,0,12,0xE1,0x03,0x30,0x07,0x30,0x02,0x30,0x06,0x30,0x00,0x44,0x44
0x39,0,12,0xE2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
0x39,0,5,0xE3,0x00,0x00,0x22,0x00
0x39,0,3,0xE4,0x22,0x00
0x39,0,17,0xE5,0x0A,0x34,0x30,0xE0,0x08,0x32,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
0x39,0,5,0xE6,0x00,0x00,0x22,0x00
0x39,0,3,0xE7,0x22,0x00
0x39,0,17,0xE8,0x09,0x33,0x30,0xE0,0x07,0x31,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
0x39,0,8,0xEB,0x00,0x01,0x10,0x10,0x11,0x00,0x00
0x39,0,17,0xED,0xFF,0xFF,0xF0,0x45,0xBA,0x2F,0xFF,0xFF,0xFF,0xFF,0xF2,0xAB,0x54,0x0F,0xFF,0xFF
0x39,0,7,0xEF,0x08,0x08,0x08,0x45,0x3F,0x54
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x13
0x39,0,3,0xE8,0x00,0x0E
0x15,120,2,0x11,0x00
0x39,10,3,0xE8,0x00,0x0C
0x39,0,3,0xE8,0x00,0x00
0x39,0,6,0xFF,0x77,0x01,0x00,0x00,0x00
0x15,50,2,0x29,0x00
```

### 将配置文件放入`SDCard`

开机后，将配置文件放入`SDCard`根目录

![SDCard Path](https://www.kendryte.com/api/post/attachment?id=485)

### 验证并调整配置

#### 在 `CanMV IDE K230` 打开 `Display` 相关的Sample

![Open Display Sample](https://www.kendryte.com/api/post/attachment?id=483)

#### 修改Sample代码以使用 `DSI Debugger`

![Mod Sample Code](https://www.kendryte.com/api/post/attachment?id=484)

#### 运行Sample，查看结果

![Check Sample Result](https://www.kendryte.com/api/post/attachment?id=487)

因为本文档给的参数是适配对应屏幕后的，所以屏幕会正确输出图像，如果读者得不到预期结果，那么需要修改SDCard的配置文件调整参数，重复运行Sample，查看结果，最后调整到合适的参数。

![Check Panel Result](https://www.kendryte.com/api/post/attachment?id=499)

## 配置文件参数调整

SDCard中配置文件的参数基本分为两部分，前半部分是屏幕时序相关，后半部分是屏幕厂家提供的初始化序列，接下来我们分别了解一下这两部分的具体含义。

### 屏幕时序

```shell
[config]
pclk_hz=27000000        # 这个值是根据下面的参数，最后利用计算工具算出来的
fps=60                  # 假定我想要这个帧率，等会写进去计算工具
lane_num=2

# htotal = hactive + hsync + hbp + hfp

hactive=368             # 这个对应分辨率的宽
hsync=8                 # hsync,hbp,hfp，根据对应的屏幕估算，调整
hbp=16
hfp=16

# vtotal =  vactive + vsync + vbp +vfp
# 对于 vtotal 来说有个限制，主控只会在 2^N 行处发起中断，所以当 vtotal > 512 的时候，应该将 vtotal向上对齐到 1024，然后再给一点余量
# 给中断处理函数，所以预估 vtotal 应该为 1100，即 vactive + vsync + vbp +vfp 需要等于 1100，在这个限制下再去调整 vsync,vbp,vfp

vactive=552             # 这个对应分辨率的高
vsync=48                # vsync,vbp,vfp，根据对应的屏幕估算，调整
vbp=250
vfp=250
```

我们提供了一个协助计算时序的工具 [K230 MIPI DSI Connector Info Generator](https://kendryte-download.canaan-creative.com/developer/common/K230_MIPI_DSI_Connector_Info_Generator.html)，下面演示如何利用计算时序的工具来算出上面的值

![Calc Timing](https://www.kendryte.com/api/post/attachment?id=489)

### 初始化序列

本文档示例的屏幕厂家提供了如下的初始化序列，我们根据需要转换为符合格式的 `display_debugger_config.txt` 文件即可。

```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}},
{0xCC,1,{0x10}},
{0xB0,16,{0x0F,0x1E,0x25,0x0D,0x11,0x06,0x12,0x08,0x08,0x2A,0x05,0x12,0x10,0x2B,0x32,0x1F}},
{0xB1,16,{0x0F,0x1E,0x25,0x0D,0x11,0x05,0x12,0x08,0x08,0x2B,0x05,0x12,0x10,0x2B,0x32,0x1F}},
{0xFF,5,{0x77,0x01,0x00,0x00,0x11}},
{0xB0,1,{0x35}},
{0xB1,1,{0x45}},
{0xB2,1,{0x87}},
{0xB3,1,{0x80}},
{0xB5,1,{0x49}},
{0xB7,1,{0x85}},
{0xB8,1,{0x11}},
{0xBB,1,{0x03}},
{0xC0,1,{0x07}},
{0xC1,1,{0x78}},
{0xC2,1,{0x78}},
{0xD0,1,{0x88}},
{REGFLAG_DELAY,100,{}},
{0xE0,3,{0x00,0x00,0x02}},
{0xE1,11,{0x03,0x30,0x07,0x30,0x02,0x30,0x06,0x30,0x00,0x44,0x44}},
{0xE2,11,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{0xE3,4,{0x00,0x00,0x22,0x00}},
{0xE4,2,{0x22,0x00}},
{0xE5,16,{0x0A,0x34,0x30,0xE0,0x08,0x32,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{0xE6,4,{0x00,0x00,0x22,0x00}},
{0xE7,2,{0x22,0x00}},
{0xE8,16,{0x09,0x33,0x30,0xE0,0x07,0x31,0x30,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{0xEB,7,{0x00,0x01,0x10,0x10,0x11,0x00,0x00}},
{0xED,16,{0xFF,0xFF,0xF0,0x45,0xBA,0x2F,0xFF,0xFF,0xFF,0xFF,0xF2,0xAB,0x54,0x0F,0xFF,0xFF}},
{0xEF,6,{0x08,0x08,0x08,0x45,0x3F,0x54}},
{0xFF,5,{0x77,0x01,0x00,0x00,0x13}},
{0xE8,2,{0x00,0x0E}},
{0x11,0,{0x00}},
{REGFLAG_DELAY,120,{}},
{0xE8,2,{0x00,0x0C}},
{REGFLAG_DELAY,10,{}},
{0xE8,2,{0x00,0x00}},
{0xFF,5,{0x77,0x01,0x00,0x00,0x00}},
{0x29,0,{0x00}},
{REGFLAG_DELAY,50,{}},
```

我们举两个例子：

```shell

{0xB0,16,{0x0F,0x1E,0x25,0x0D,0x11,0x06,0x12,0x08,0x08,0x2A,0x05,0x12,0x10,0x2B,0x32,0x1F}},
# 将多余的{}去掉
# 0xB0 是命令，其余的都是16个字节是参数，所以我们选择 0x39 命令，长度应该是 16 + 1 = 17
# 不需要延时，所以转化结果如下：
0x39,0,17,0xB0,0x0F,0x1E,0x25,0x0D,0x11,0x06,0x12,0x08,0x08,0x2A,0x05,0x12,0x10,0x2B,0x32,0x1F


{0x11,0,{0x00}},
{REGFLAG_DELAY,120,{}},
# 将多余的{}去掉
# 0x11 是命令，其余的1个字节是参数，所以我们选择 0x15 命令，长度应该是 1 + 1 = 2
# 后面的REGFLAG_DELAY代表还有120毫秒的延时，所以转化结果为如下：

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

# Tips: 因为每个厂家提供的初始化序列格式可能大有不同，所以这种转化的事情可以丢给ChatGPT去干就好
# PS: 其实第二个例子转换为 0x05,120,1,0x11，也是正确的，我们会发现厂家提供的初始化序列，自己在长度和数据这方面就没统一好


```

## 在工程代码中添加屏幕

经过前面的调试，我们已经有了适配该款屏幕的参数了，可以在工程中添加一款屏幕了。

在 [CanMV-K230](https://github.com/kendryte/canmv_k230) 工程中的子仓库 [mpp](https://github.com/canmv-k230/mpp/) 里，仿造其他屏幕添加类似如下代码：（初始化序列来自屏幕厂家，屏幕时序是我们调整出来的，最后把计算工具生成的代码贴过去即可）

![User Timing](https://www.kendryte.com/api/post/attachment?id=490)
![Kernal Init](https://www.kendryte.com/api/post/attachment?id=491)

在 [CanMV-K230](https://github.com/kendryte/canmv_k230) 工程中的子仓库 [canmv](https://github.com/canmv-k230/canmv) 里，仿造其他屏幕添加类似如下代码：

![Canmv Add Panle](https://www.kendryte.com/api/post/attachment?id=492)
