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.h。 62 63**表1** MIPI DSI API接口功能介绍 64 65| 功能分类 | 接口名 | 66| -------- | -------- | 67| DevHandle MipiDsiOpen(uint8_t id) | 获取MIPI DSI操作句柄 | 68| void MipiDsiClose(DevHandle handle) | 释放MIPI DSI操作句柄 | 69| int32_t MipiDsiSetCfg(DevHandle handle, struct MipiCfg \*cfg) | 设置MIPI DSI相关配置 | 70| int32_t MipiDsiGetCfg(DevHandle handle, struct MipiCfg \*cfg) | 获取当前MIPI DSI相关配置 | 71| void MipiDsiSetLpMode(DevHandle handle) | 设置MIPI DSI进入Low power模式 | 72| void MipiDsiSetHsMode(DevHandle handle) | 设置MIPI DSI进入High 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 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 DSI通道ID | 99| **返回值** | **返回值描述** | 100| NULL | 获取失败 | 101| 设备句柄 | 获取到指令通道的操作句柄, 类型为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 DSI相应配置buf 指针 | 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 DSI相应配置buf 指针 | 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 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