• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# MIPI DSI
2
3## 概述
4
5### 功能简介
6
7DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface (MIPI) Alliance)制定的规范,旨在降低移动设备中显示控制器的成本。它以串行的方式发送像素数据或指令给外设(通常是LCD或者类似的显示设备),或从外设中读取状态信息或像素信息;它定义了主机、图像数据源和目标设备之间的串行总线和通信协议。
8
9MIPI DSI具备高速模式和低速模式两种工作模式,全部数据通道都可以用于单向的高速传输,但只有第一个数据通道才可用于低速双向传输,从属端的状态信息、像素等是通过该数据通道返回。时钟通道专用于在高速传输数据的过程中传输同步时钟信号。
10
11图1显示了简化的DSI接口。从概念上看,符合DSI的接口与基于DBI-2和DPI-2标准的接口具有相同的功能。它向外围设备传输像素或命令数据,并且可以从外围设备读取状态或像素信息。主要区别在于,DSI对所有像素数据、命令和事件进行序列化,而在传统接口中,这些像素数据、命令和事件通常需要附加控制信号才能在并行数据总线上传输。
12
13**图1** DSI发送、接收接口
14
15![image](figures/DSI发送-接收接口.png "DSI发送-接收接口")
16
17DSI标准对应D-PHY、DSI、DCS规范,可分为四层:
18
19- PHY Layer
20
21  定义了传输媒介,输入/输出电路和和时钟和信号机制。PHY层指定传输介质(电导体)、输入/输出电路和从串行比特流中捕获“1”和“0”的时钟机制。这一部分的规范记录了传输介质的特性、信号的电气参数以及时钟与数据通道之间的时序关系。在DSI链路的发送端,并行数据、信号事件和命令按照包组织在协议层转换为包。协议层附加包协议信息和报头,然后通过Lane Management层向PHY发送完整的字节。数据由PHY进行序列化,并通过串行链路发送。DSI链路的接收端执行与发送端相反的操作,将数据包分解为并行的数据、信号事件和命令。如果有多个Lane, Lane管理层将字节分配给单独的物理层,每个Lane一个PHY。
22
23- Lane Management层
24
25  负责发送和收集数据流到每条Lane。数据Lane的三种操作模式 :espace mode,High-Speed(Burst) mode,Control mode。
26
27- Low Level Protocol层
28
29  定义了如何组帧和解析以及错误检测等。
30
31- Application层
32
33  描述高层编码和解析数据流。这一层描述了数据流中包含的数据的更高级的编码和解释。根据显示子系统架构的不同,它可能由具有指定格式的像素或编码的位流组成,或者由显示模块内的显示控制器解释的命令组成。DSI规范描述了像素值、位流、命令和命令参数到包集合中的字节的映射。
34
35### 运作机制
36
37MIPI DSI软件模块各分层的作用为:
38
39- 接口层:提供打开设备、写入数据和关闭设备的接口。
40- 核心层:主要提供绑定设备、初始化设备以及释放设备的能力。
41- 适配层:实现其它具体的功能。
42
43![](../public_sys-resources/icon-note.gif) **说明:**<br>核心层可以调用接口层的函数,核心层通过钩子函数调用适配层函数,从而适配层可以间接的调用接口层函数,但是不可逆转接口层调用适配层函数。
44
45**图2** DSI无服务模式结构图
46
47![image](figures/无服务模式结构图.png "DSI无服务模式结构图")
48
49### 约束与限制
50
51由于使用无服务模式,MIPI_DSI接口暂不支持用户态使用。
52
53## 使用指导
54
55### 场景介绍
56
57MIPI DSI主要用于连接显示屏。
58
59### 接口说明
60
61MIPI DSI模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/mipi_dsi_if.h62
63**表1** MIPI DSI API接口功能介绍
64
65| 功能分类 |  接口名  |
66| -------- | -------- |
67| DevHandle MipiDsiOpen(uint8_t id) | 获取MIPI&nbsp;DSI操作句柄 |
68| void MipiDsiClose(DevHandle handle) | 释放MIPI&nbsp;DSI操作句柄 |
69| int32_t MipiDsiSetCfg(DevHandle handle, struct MipiCfg \*cfg) | 设置MIPI&nbsp;DSI相关配置 |
70| int32_t MipiDsiGetCfg(DevHandle handle, struct MipiCfg \*cfg) | 获取当前MIPI&nbsp;DSI相关配置 |
71| void MipiDsiSetLpMode(DevHandle handle) | 设置MIPI&nbsp;DSI进入Low&nbsp;power模式 |
72| void MipiDsiSetHsMode(DevHandle handle) | 设置MIPI&nbsp;DSI进入High&nbsp;speed模式 |
73| int32_t MipiDsiTx(DevHandle handle, struct DsiCmdDesc \*cmd) | DSI发送指令 |
74| int32_t MipiDsiRx(DevHandle handle, struct DsiCmdDesc \*cmd, int32_t readLen, uint8_t \*out) | MIPI&nbsp;DSI按期望长度回读数据 |
75
76### 开发步骤
77
78使用MIPI DSI的一般流程如下图所示。
79
80**图3** MIPI DSI使用流程图
81
82![image](figures/MIPI-DSI使用流程图.png "MIPI-DSI使用流程图")
83
84
85#### 获取MIPI DSI操作句柄
86
87在进行MIPI DSI进行通信前,首先要调用MipiDsiOpen获取操作句柄,该函数会返回指定通道ID的操作句柄。
88
89
90```c
91DevHandle MipiDsiOpen(uint8_t id);
92```
93
94  **表2** MipiDsiOpen的参数和返回值描述
95
96| **参数** | **参数描述** |
97| -------- | -------- |
98| id | MIPI&nbsp;DSI通道ID |
99| **返回值** | **返回值描述** |
100| NULL | 获取失败 |
101| 设备句柄 | 获取到指令通道的操作句柄,&nbsp;类型为DevHandle |
102
103假设系统中的MIPI DSI通道为0,获取该通道操作句柄的示例如下:
104
105
106```c
107DevHandle mipiDsiHandle = NULL;  /* 设备句柄 */
108chnId = 0;      /* MIPI DSI通道ID */
109
110/* 获取操作句柄 */
111mipiDsiHandle = MipiDsiOpen(chnId);
112if (mipiDsiHandle == NULL) {
113    HDF_LOGE("MipiDsiOpen: failed\n");
114    return;
115}
116```
117
118
119#### MIPI DSI相应配置
120
121- 写入MIPI DSI配置
122
123  ```c
124  int32_t MipiDsiSetCfg(DevHandle handle, struct MipiCfg *cfg);
125  ```
126
127    **表3** MipiDsiSetCfg的参数和返回值描述
128
129  | **参数** | **参数描述** |
130  | -------- | -------- |
131  | handle | 操作句柄 |
132  | cfg | MIPI&nbsp;DSI相应配置buf&nbsp;指针 |
133  | **返回值** | **返回值描述** |
134  | 0 | 设置成功 |
135  | 负数 | 设置失败 |
136
137
138  ```c
139  int32_t ret;
140  struct MipiCfg cfg = {0};
141
142  /* 当前对接的屏幕配置如下 */
143  cfg.lane = DSI_4_LANES;
144  cfg.mode = DSI_CMD_MODE;
145  cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS;
146  cfg.format = FORMAT_RGB_24_BIT;
147  cfg.pixelClk = 174;
148  cfg.phyDataRate = 384;
149  cfg.timingInfo.hsaPixels = 50;
150  cfg.timingInfo.hbpPixels = 55;
151  cfg.timingInfo.hlinePixels = 1200;
152  cfg.timingInfo.yResLines = 1800;
153  cfg.timingInfo.vbpLines = 33;
154  cfg.timingInfo.vsaLines = 76;
155  cfg.timingInfo.vfpLines = 120;
156  cfg.timingInfo.xResPixels = 1342;
157  /* 写入配置数据 */
158  ret = MipiDsiSetCfg(mipiDsiHandle, &cfg);
159  if (ret != 0) {
160      HDF_LOGE("%s: SetMipiCfg fail! ret=%d\n", __func__, ret);
161      return -1;
162  }
163  ```
164
165- 获取当前MIPI DSI的配置
166
167  ```c
168  int32_t MipiDsiGetCfg(DevHandle handle, struct MipiCfg *cfg);
169  ```
170
171    **表4** MipiDsiGetCfg的参数和返回值描述
172
173  | **参数** | **参数描述** |
174  | -------- | -------- |
175  | handle | 操作句柄 |
176  | cfg | MIPI&nbsp;DSI相应配置buf&nbsp;指针 |
177  | **返回值** | **返回值描述** |
178  | 0 | 获取成功 |
179  | 负数 | 获取失败 |
180
181
182  ```c
183  int32_t ret;
184  struct MipiCfg cfg;
185  memset(&cfg, 0, sizeof(struct MipiCfg));
186  ret = MipiDsiGetCfg(mipiDsiHandle, &cfg);
187  if (ret != HDF_SUCCESS) {
188      HDF_LOGE("%s: GetMipiCfg fail!\n", __func__);
189      return HDF_FAILURE;
190  }
191  ```
192
193
194#### 发送/回读控制指令
195
196- 发送指令
197
198  ```c
199  int32_t MipiDsiTx(PalHandle handle, struct DsiCmdDesc *cmd);
200  ```
201
202    **表5** MipiDsiTx的参数和返回值描述
203
204  | **参数** | **参数描述** |
205  | -------- | -------- |
206  | handle | 操作句柄 |
207  | cmd | 需要发送的指令数据指针 |
208  | **返回值** | **返回值描述** |
209  | 0 | 发送成功 |
210  | 负数 | 发送失败 |
211
212
213  ```c
214  int32_t ret;
215  struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc));
216  if (cmd == NULL) {
217      return HDF_FAILURE;
218  }
219  cmd->dtype = DTYPE_DCS_WRITE;
220  cmd->dlen = 1;
221  cmd->payload = OsalMemCalloc(sizeof(uint8_t));
222  if (cmd->payload == NULL) {
223      HdfFree(cmd);
224      return HDF_FAILURE;
225  }
226  *(cmd->payload) = DTYPE_GEN_LWRITE;
227  MipiDsiSetLpMode(mipiHandle);
228  ret = MipiDsiTx(mipiHandle, cmd);
229  MipiDsiSetHsMode(mipiHandle);
230  if (ret != HDF_SUCCESS) {
231      HDF_LOGE("%s: PalMipiDsiTx fail! ret=%d\n", __func__, ret);
232      HdfFree(cmd->payload);
233      HdfFree(cmd);
234      return HDF_FAILURE;
235  }
236  HdfFree(cmd->payload);
237  HdfFree(cmd);
238  ```
239
240- 回读指令
241
242  ```c
243  int32_t MipiDsiRx(DevHandle handle, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out);
244  ```
245
246    **表6** MipiDsiRx的参数和返回值描述
247
248  | **参数** | **参数描述** |
249  | -------- | -------- |
250  | handle | 操作句柄 |
251  | cmd | 需要回读的指令数据指针 |
252  | readLen | 期望回读的数据长度 |
253  | out | 回读的数据buf指针 |
254  | **返回值** | **返回值描述** |
255  | 0 | 获取成功 |
256  | 负数 | 获取失败 |
257
258
259  ```c
260  int32_t ret;
261  uint8_t readVal = 0;
262
263  struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc));
264  if (cmdRead == NULL) {
265      return HDF_FAILURE;
266  }
267  cmdRead->dtype = DTYPE_DCS_READ;
268  cmdRead->dlen = 1;
269  cmdRead->payload = OsalMemCalloc(sizeof(uint8_t));
270  if (cmdRead->payload == NULL) {
271      HdfFree(cmdRead);
272      return HDF_FAILURE;
273  }
274  *(cmdRead->payload) = DDIC_REG_STATUS;
275  MipiDsiSetLpMode(mipiDsiHandle);
276  ret = MipiDsiRx(mipiDsiHandle, cmdRead, sizeof(readVal), &readVal);
277  MipiDsiSetHsMode(mipiDsiHandle);
278  if (ret != HDF_SUCCESS) {
279      HDF_LOGE("%s: MipiDsiRx fail! ret=%d\n", __func__, ret);
280      HdfFree(cmdRead->payload);
281      HdfFree(cmdRead);
282      return HDF_FAILURE;
283  }
284  HdfFree(cmdRead->payload);
285  HdfFree(cmdRead);
286  ```
287
288
289#### 释放MIPI DSI操作句柄
290
291MIPI DSI使用完成之后,需要释放操作句柄,释放句柄的函数如下所示:
292
293```c
294void MipiDsiClose(DevHandle handle);
295```
296
297该函数会释放掉由MipiDsiOpen申请的资源。
298
299  **表7** MipiDsiClose的参数和返回值描述
300
301| 参数 | 参数描述 |
302| -------- | -------- |
303| handle | MIPI&nbsp;DSI操作句柄 |
304
305```c
306MipiDsiClose(mipiHandle); /* 释放掉MIPI DSI操作句柄 */
307```
308
309
310## 使用实例
311
312本例拟对Hi3516DV300开发板上MIPI DSI设备进行操作。
313
314MIPI DSI完整的使用示例如下所示:
315
316```c
317#include "hdf.h"
318#include "mipi_dsi_if.h"
319
320void PalMipiDsiTestSample(void)
321{
322    uint8_t chnId;
323    int32_t ret;
324    DevHandle mipiDsiHandle = NULL;
325
326    /* 设备通道编号 */
327    chnId = 0;
328    /* 获取操作句柄 */
329    mipiDsiHandle = MipiDsiOpen(chnId);
330    if (mipiDsiHandle == NULL) {
331        HDF_LOGE("MipiDsiOpen: failed!\n");
332        return;
333    }
334    /* 配置相应参数 */
335    struct MipiCfg cfg = {0};
336    cfg.lane = DSI_4_LANES;
337    cfg.mode = DSI_CMD_MODE;
338    cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS;
339    cfg.format = FORMAT_RGB_24_BIT;
340    cfg.pixelClk = 174;
341    cfg.phyDataRate = 384;
342    cfg.timingInfo.hsaPixels = 50;
343    cfg.timingInfo.hbpPixels = 55;
344    cfg.timingInfo.hlinePixels = 1200;
345    cfg.timingInfo.yResLines = 1800;
346    cfg.timingInfo.vbpLines = 33;
347    cfg.timingInfo.vsaLines = 76;
348    cfg.timingInfo.vfpLines = 120;
349    cfg.timingInfo.xResPixels = 1342;
350    /* 写入配置数据 */
351    ret = MipiDsiSetCfg(mipiDsiHandle, &cfg);
352    if (ret != 0) {
353        HDF_LOGE("%s: SetMipiCfg fail! ret=%d\n", __func__, ret);
354        return;
355    }
356    /* 发送PANEL初始化指令 */
357    struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc));
358    if (cmd == NULL) {
359        return;
360    }
361    cmd->dtype = DTYPE_DCS_WRITE;
362    cmd->dlen = 1;
363    cmd->payload = OsalMemCalloc(sizeof(uint8_t));
364    if (cmd->payload == NULL) {
365        HdfFree(cmd);
366        return;
367    }
368    *(cmd->payload) = DTYPE_GEN_LWRITE;
369    MipiDsiSetLpMode(mipiHandle);
370    ret = MipiDsiTx(mipiHandle, cmd);
371    MipiDsiSetHsMode(mipiHandle);
372    if (ret != HDF_SUCCESS) {
373        HDF_LOGE("%s: MipiDsiTx fail! ret=%d\n", __func__, ret);
374        HdfFree(cmd->payload);
375        HdfFree(cmd);
376        return;
377    }
378    HdfFree(cmd->payload);
379    HdfFree(cmd);
380    /* 回读panel状态寄存器 */
381    uint8_t readVal = 0;
382    struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc));
383    if (cmdRead == NULL) {
384        return;
385    }
386    cmdRead->dtype = DTYPE_DCS_READ;
387    cmdRead->dlen = 1;
388    cmdRead->payload = OsalMemCalloc(sizeof(uint8_t));
389    if (cmdRead->payload == NULL) {
390        HdfFree(cmdRead);
391        return;
392    }
393    *(cmdRead->payload) = DDIC_REG_STATUS;
394    MipiDsiSetLpMode(mipiDsiHandle);
395    ret = MipiDsiRx(mipiDsiHandle, cmdRead, sizeof(readVal), &readVal);
396    MipiDsiSetHsMode(mipiDsiHandle);
397    if (ret != HDF_SUCCESS) {
398        HDF_LOGE("%s: MipiDsiRx fail! ret=%d\n", __func__, ret);
399        HdfFree(cmdRead->payload);
400        HdfFree(cmdRead);
401        return;
402    }
403    HdfFree(cmdRead->payload);
404    HdfFree(cmdRead);
405    /* 释放MIPI DSI设备句柄 */
406    MipiDsiClose(handle);
407}
408```
409