1# MIPI CSI
2
3## 概述
4
5### 功能简介
6
7CSI(Camera Serial Interface)是由MIPI联盟下Camera工作组指定的接口标准。CSI-2是MIPI CSI第二版,主要由应用层、协议层、物理层组成,最大支持4通道数据传输、单线传输速度高达1Gb/s。
8
9物理层支持HS(High Speed)和LP(Low Speed)两种工作模式。HS模式下采用低压差分信号,功耗较大,但数据传输速率可以很高(数据速率为80M~1Gbps);LP模式下采用单端信号,数据速率很低(<10Mbps),但是相应的功耗也很低。两种模式的结合保证了MIPI总线在需要传输大量数据(如图像)时可以高速传输,而在不需要传输大数据量时又能够减少功耗。
10
11图1显示了简化的CSI接口。D-PHY采用1对源同步的差分时钟和1~4对差分数据线来进行数据传输。数据传输采用DDR方式,即在时钟的上下边沿都有数据传输。
12
13**图 1** CSI发送、接收接口<a name="fig1_MIPI_CSIDes"></a>
14
15![CSI发送、接收接口](figures/CSI发送-接收接口.png)
16
17MIPI CSI标准分为应用层、协议层与物理层,协议层又细分为像素字节转换层、低级协议层、Lane管理层。
18
19- 物理层(PHY Layer)
20
21    PHY层指定了传输媒介,在电气层面从串行bit流中捕捉“0”与“1”,同时生成SoT与EoT等信号。
22
23- 协议层(Protocol Layer)
24
25    协议层由三个子层组成,每个子层有不同的职责。CSI-2协议能够在host侧处理器上用一个单独的接口处理多条数据流。协议层规定了多条数据流该如何标记和交织起来,以便每条数据流能够被正确地恢复出来。
26
27    - 像素字节转换层(Pixel/Byte Packing/Unpacking Layer)
28
29        CSI-2规范支持多种不同像素格式的图像应用。在发送方中,本层在发送数据到Low Level Protocol层之前,将来自应用层的像素封包为字节数据。在接收方中,本层在发送数据到应用层之前,将来自Low Level Protocol层的字节数据解包为像素。8位的像素数据在本层中传输时保持不变。
30
31    - 低级协议层(Low Level Protocol)
32        LLP主要包含了在SoT和EoT事件之间的bit和byte级别的同步方法,以及和下一层传递数据的方法。LLP最小数据粒度是1个字节。LLP也包含了一个字节内的bit值解析,即Endian(大小端里的Endian的意思)的处理。
33
34    - Lane管理层(Lane Management)
35
36        CSI-2的Lane是可扩展的。具体的数据Lane的数量规范并没有给出限制,具体根据应用的带宽需求而定。发送侧分发(distributor功能)来自出口方向数据流的字节到1条或多条Lane上。接收侧则从一条或多条Lane中收集字节并合并(merge功能)到一个数据流上,复原出原始流的字节顺序。对于C-PHY物理层来说,本层专门分发字节对(16 bits)到数据Lane或从数据Lane中收集字节对。基于每Lane的扰码功能是可选特性。
37
38        协议层的数据组织形式是包(packet)。接口的发送侧会增加包头(header)和错误校验(error-checking)信息到即将被LLP发送的数据上。接收侧在LLP将包头剥掉,包头会被接收器中对应的逻辑所解析。错误校验信息可以用来做入口数据的完整性检查。
39
40- 应用层(Application Layer)
41
42    本层描述了更高层级的应用对于数据中的数据的处理,规范并不涵盖应用层。CSI-2规范只给出了像素值和字节的映射关系。
43
44### 运作机制
45
46MIPI CSI模块各分层的作用为:接口层提供打开设备、写入数据和关闭设备的接口。核心层主要提供绑定设备、初始化设备以及释放设备的能力。适配层实现其它具体的功能。
47
48![](../public_sys-resources/icon-note.gif) **说明:**<br>核心层可以调用接口层的函数,核心层通过钩子函数调用适配层函数,从而适配层可以间接的调用接口层函数,但是不可逆转接口层调用适配层函数。
49
50**图 2** CSI无服务模式结构图
51
52![CSI无服务模式结构图](figures/无服务模式结构图.png)
53
54### 约束与限制
55
56由于使用无服务模式,MIPI_CSI接口暂不支持用户态使用。
57
58## 使用指导
59
60### 场景介绍
61
62MIPI CSI主要用于连接摄像头组件。
63
64### 接口说明
65
66MIPI CSI模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/mipi_csi_if.h67
68**表 1** ComboDevAttr结构体介绍
69
70<a name="table1_MIPI_CSIDes"></a>
71
72| 名称 | 描述 |
73| --------- | ----------------------------------------------------- |
74| devno | 设备号 |
75| inputMode | 输入模式:MIPI/LVDS/SUBSLVDS/HISPI/DC |
76| dataRate | Mipi Rx,SLVS输入速率 |
77| imgRect | MIPI Rx设备裁剪区域(与原始传感器输入图像大小相对应) |
78| MIPIAttr | Mipi设备属性 |
79| lvdsAttr | LVDS/SubLVDS/HiSPi设备属性 |
80
81**表 2** ExtDataType结构体介绍
82
83<a name="table2_MIPI_CSIDes"></a>
84
85| 名称 | 描述 |
86| --------------- | ------------------------------- |
87| devno | 设备号 |
88| num | Sensor号 |
89| extDataBitWidth | 图片的位深 |
90| extDataType | 定义YUV和原始数据格式以及位深度 |
91
92**表 3** MIPI CSI API接口功能介绍
93
94<a name="table3_MIPI_CSIDes"></a>
95
96| 接口名 | 接口描述 |
97| -------- | -------- |
98| DevHandle MipiCsiOpen(uint8_t id) | 获取MIPI_CSI控制器操作句柄 |
99| void MipiCsiClose(DevHandle handle) | 释放MIPI_CSI控制器操作句柄 |
100| int32_t MipiCsiSetComboDevAttr(DevHandle handle, ComboDevAttr \*pAttr) | 设置MIPI,CMOS或者LVDS相机的参数给控制器,参数包括工作模式,图像区域,图像深度,数据速率和物理通道等 |
101| int32_t MipiCsiSetExtDataType(DevHandle handle, ExtDataType \*dataType) | 设置YUV和RAW数据格式和位深(可选) |
102| int32_t MipiCsiSetHsMode(DevHandle handle, LaneDivideMode laneDivideMode) | 设置MIPI&nbsp;RX的Lane分布。根据硬件连接的形式选择具体的mode |
103| int32_t MipiCsiSetPhyCmvmode(DevHandle handle, uint8_t devno, PhyCmvMode cmvMode) | 设置共模电压模式 |
104| int32_t MipiCsiResetSensor(DevHandle handle, uint8_t snsResetSource) | 复位Sensor |
105| int32_t MipiCsiUnresetSensor(DevHandle handle, uint8_t snsResetSource) | 撤销复位Sensor |
106| int32_t MipiCsiResetRx(DevHandle handle, uint8_t comboDev) | 复位MIPI&nbsp;RX。不同的s32WorkingViNum有不同的enSnsType |
107| int32_t MipiCsiUnresetRx(DevHandle handle, uint8_t comboDev) | 撤销复位MIPI&nbsp;RX |
108| int32_t MipiCsiEnableClock(DevHandle handle, uint8_t comboDev) | 使能MIPI的时钟。根据上层函数电泳传递的enSnsType参数决定是用MIPI还是LVDS |
109| int32_t MipiCsiDisableClock(DevHandle handle, uint8_t comboDev) | 关闭MIPI设备的时钟 |
110| int32_t MipiCsiEnableSensorClock(DevHandle handle, uint8_t snsClkSource) | 使能MIPI上的Sensor时钟 |
111| int32_t MipiCsiDisableSensorClock(DevHandle handle, uint8_t snsClkSource) | 关闭Sensor的时钟 |
112
113## 开发步骤
114
115#### 使用流程
116
117使用MIPI CSI的一般流程如图3所示。
118
119**图 3** MIPI CSI使用流程图
120
121![MIPI CSI使用流程图](figures/MIPI-CSI使用流程图.png)
122
123#### 获取MIPI CSI控制器操作句柄
124
125在进行MIPI CSI进行通信前,首先要调用MipiCsiOpen获取控制器操作句柄,该函数会返回指定通道ID的控制器操作句柄。
126
127```c
128DevHandle MipiCsiOpen(uint8_t id);
129```
130
131**表 4** MipiCsiOpen的参数和返回值描述
132
133| 参数 | 参数描述 |
134| ---------- | ----------------------------------------------- |
135| id | uint8_t类型,MIPI CSI通道ID |
136| **返回值** | **返回值描述** |
137| NULL | 获取失败 |
138| 设备句柄 | 获取到指令通道的控制器操作句柄,类型为DevHandle |
139
140假设系统中的MIPI CSI通道为0,获取该通道控制器操作句柄的示例如下:
141
142```c
143DevHandle MipiCsiHandle = NULL;  // 设备句柄
144id = 0;                          // MIPI CSI通道ID
145
146// 获取控制器操作句柄
147MipiCsiHandle = MipiCsiOpen(id);
148if (MipiCsiHandle == NULL) {
149    HDF_LOGE("MipiCsiOpen: mipi csi open fail.\n");
150    return NULL;
151}
152```
153
154#### 进行MIPI CSI相应配置
155
156- 写入MIPI CSI配置
157
158    ```c
159    int32_t MipiCsiSetComboDevAttr(DevHandle handle, ComboDevAttr *pAttr);
160    ```
161
162    **表 5** MipiCsiSetComboDevAttr的参数和返回值描述
163
164    <a name="table5_MIPI_CSIDes"></a>
165
166    | 参数 | 参数描述 |
167    | ---------- | -------------------------- |
168    | handle | DevHandle类型,控制器操作句柄 |
169    | pAttr | 结构体指针,MIPI CSI相应配置 |
170    | **返回值** | **返回值描述** |
171    | HDF_SUCCESS | 设置成功 |
172    | 负数 | 设置失败 |
173
174    ```c
175    int32_t ret;
176    struct ComboDevAttr attr;
177
178    // 当前配置如下
179    (void)memset_s(&attr, sizeof(ComboDevAttr), 0, sizeof(ComboDevAttr));
180    attr.devno = 0;                    // 设备0
181    attr.inputMode = INPUT_MODE_MIPI;  // 输入模式为MIPI
182    attr.dataRate = MIPI_DATA_RATE_X1; // 每时钟输出1像素
183    attr.imgRect.x = 0;                // 0: 图像传感器左上位置
184    attr.imgRect.y = 0;                // 0: 图像传感器右上位置
185    attr.imgRect.width = 2592;         // 2592: 图像传感器宽度大小
186    attr.imgRect.height = 1944;        // 1944: 图像传感器高度尺寸
187    // 写入配置数据
188    ret = MipiCsiSetComboDevAttr(MipiCsiHandle, &attr);
189    if (ret != HDF_SUCCESS) {
190        HDF_LOGE("MipiCsiSetComboDevAttr: mipi csi set combo dev attr fail, ret=%d\n", ret);
191        return ret;
192    }
193    ```
194
195- 设置YUV和RAW数据格式和位深
196
197    ```c
198    int32_t MipiCsiSetExtDataType(DevHandle handle, ExtDataType* dataType);
199    ```
200
201    **表 6** MipiCsiSetExtDataType的参数和返回值描述
202
203    <a name="table6_MIPI_CSIDes"></a>
204
205    | 参数 | 参数描述 |
206    | ---------- | ------------------------------- |
207    | handle | DevHandle类型,控制器操作句柄 |
208    | dataType | 结构体指针,定义YUV和原始数据格式以及位深度 |
209    | **返回值** | **返回值描述** |
210    | HDF_SUCCESS | 设置成功 |
211    | 负数 | 设置失败 |
212
213    ```c
214    int32_t ret;
215    struct ExtDataType dataType;
216
217    // 配置YUV和RAW数据格式和位深参数
218    dataType.devno = 0;               // 设备0
219    dataType.num = 0;                 // Sensor 0
220    dataType.extDataBitWidth[0] = 12; // 位深数组元素0
221    dataType.extDataBitWidth[1] = 12; // 位深数组元素1
222    dataType.extDataBitWidth[2] = 12; // 位深数组元素2
223
224    dataType.extDataType[0] = 0x39;   // 定义YUV和原始数据格式以及位深度元素0
225    dataType.extDataType[1] = 0x39;   // 定义YUV和原始数据格式以及位深度元素1
226    dataType.extDataType[2] = 0x39;   // 定义YUV和原始数据格式以及位深度元素2
227    // 设置YUV和RAW数据格式和位深
228    ret = MipiCsiSetExtDataType(MipiCsiHandle, &dataType);
229    if (ret != HDF_SUCCESS) {
230        HDF_LOGE("MipiCsiSetExtDataType: mipi csi set ext data type fail, ret=%d\n", ret);
231        return ret;
232    }
233    ```
234
235- 设置MIPI RX的Lane分布
236
237    ```c
238    int32_t MipiCsiSetHsMode(DevHandle handle, LaneDivideMode laneDivideMode);
239    ```
240
241    **表 7** MipiCsiSetHsMode的参数和返回值描述
242
243    | 参数 | 参数描述 |
244    | -------------- | -------------- |
245    | handle | DevHandle类型,控制器操作句柄 |
246    | laneDivideMode | 结构体类型,Lane模式参数 |
247    | **返回值** | **返回值描述** |
248    | HDF_SUCCESS | 设置成功 |
249    | 负数 | 设置失败 |
250
251    ```c
252    int32_t ret;
253    enum LaneDivideMode mode;
254
255    // Lane模式参数为0
256    mode = LANE_DIVIDE_MODE_0;
257    // 设置MIPI RX的 Lane分布
258    ret = MipiCsiSetHsMode(MipiCsiHandle, mode);
259    if (ret != HDF_SUCCESS) {
260        HDF_LOGE("MipiCsiSetHsMode: mipi csi set hs mode fail, ret=%d\n", ret);
261        return ret;
262    }
263    ```
264
265- 设置共模电压模式
266
267    ```c
268    int32_t MipiCsiSetPhyCmvmode(DevHandle handle, uint8_t devno, PhyCmvMode cmvMode);
269    ```
270
271    **表 8** MipiCsiSetPhyCmvmode的参数和返回值描述
272
273    | 参数 | 参数描述 |
274    | ---------- | ---------------- |
275    | handle |  DevHandle类型,控制器操作句柄 |
276    | cmvMode | 结构体类型,共模电压模式参数 |
277    | devno | uint8_t类型,设备编号 |
278    | **返回值** | **返回值描述** |
279    | HDF_SUCCESS | 设置成功 |
280    | 负数 | 设置失败 |
281
282    ```c
283    int32_t ret;
284    enum PhyCmvMode mode;
285    uint8_t devno;
286
287    // 共模电压模式参数为0
288    mode = PHY_CMV_GE1200MV;
289    // 设备编号为0
290    devno = 0;
291    // 设置共模电压模式
292    ret = MipiCsiSetPhyCmvmode(MipiCsiHandle, devno, mode);
293    if (ret != HDF_SUCCESS) {
294        HDF_LOGE("MipiCsiSetPhyCmvmode: mipi csi set phy cmv mode fail, ret=%d\n", ret);
295        return ret;
296    }
297    ```
298
299#### 复位/撤销复位Sensor
300
301- 复位Sensor
302
303    ```c
304    int32_t MipiCsiResetSensor(DevHandle handle, uint8_t snsResetSource);
305    ```
306
307    **表 9** MipiCsiResetSensor的参数和返回值描述
308
309    | 参数 | 参数描述 |
310    | -------------- | ------------------------------------------------ |
311    | handle | DevHandle类型,控制器操作句柄 |
312    | snsResetSource | uint8_t类型,传感器的复位信号线号,在软件中称为传感器的复位源 |
313    | **返回值** | **返回值描述** |
314    | HDF_SUCCESS | 复位成功 |
315    | 负数 | 复位失败 |
316
317    ```c
318    int32_t ret;
319    uint8_t snsResetSource;
320
321    // 传感器复位信号线号为0
322    snsResetSource = 0;
323    // 复位Sensor
324    ret = MipiCsiResetSensor(MipiCsiHandle, snsResetSource);
325    if (ret != HDF_SUCCESS) {
326        HDF_LOGE("MipiCsiResetSensor: mipi csi reset sensor fail, ret=%d\n", ret);
327        return ret;
328    }
329    ```
330
331- 撤销复位Sensor
332
333    ```c
334    int32_t MipiCsiUnresetSensor(DevHandle handle, uint8_t snsResetSource);
335    ```
336
337    **表 10** MipiCsiUnresetSensor的参数和返回值描述
338
339    | 参数 | 参数描述 |
340    | -------------- | ------------------------------------------------ |
341    | handle | DevHandle类型,控制器操作句柄 |
342    | snsResetSource | uint8_t类型,传感器的复位信号线号,在软件中称为传感器的复位源 |
343    | **返回值** | **返回值描述** |
344    | HDF_SUCCESS | 撤销复位成功 |
345    | 负数 | 撤销复位失败 |
346
347    ```c
348    int32_t ret;
349    uint8_t snsResetSource;
350
351    // 传感器撤销复位信号线号为0
352    snsResetSource = 0;
353    // 撤销复位Sensor
354    ret = MipiCsiUnresetSensor(MipiCsiHandle, snsResetSource);
355    if (ret != HDF_SUCCESS) {
356        HDF_LOGE("MipiCsiUnresetSensor: mipi csi unreset sensor fail, ret=%d\n", ret);
357        return ret;
358    }
359    ```
360
361#### 复位/撤销复位MIPI RX
362
363- 复位MIPI RX
364
365    ```c
366    int32_t MipiCsiResetRx(DevHandle handle, uint8_t comboDev);
367    ```
368
369    **表 11** MipiCsiResetRx的参数和返回值描述
370
371    | 参数 | 参数描述 |
372    | ---------- | --------------------- |
373    | handle | DevHandle类型,控制器操作句柄 |
374    | comboDev | uint8_t类型,MIPI RX或LVDS通路序号 |
375    | **返回值** | **返回值描述** |
376    | HDF_SUCCESS | 复位成功 |
377    | 负数 | 复位失败 |
378
379    ```c
380    int32_t ret;
381    uint8_t comboDev;
382
383    // 通路序号为0
384    comboDev = 0;
385    // 复位MIPI RX
386    ret = MipiCsiResetRx(MipiCsiHandle, comboDev);
387    if (ret != HDF_SUCCESS) {
388        HDF_LOGE("MipiCsiResetRx: mipi csi reset rx fail, ret=%d\n", ret);
389        return ret;
390    }
391    ```
392
393- 撤销复位MIPI RX
394
395    ```c
396    int32_t MipiCsiUnresetRx(DevHandle handle, uint8_t comboDev);
397    ```
398
399    **表 12** MipiCsiUnresetRx的参数和返回值描述
400
401    | 参数 | 参数描述 |
402    | ---------- | --------------------- |
403    | handle | DevHandle类型,控制器操作句柄 |
404    | comboDev | uint8_t类型,MIPI RX或LVDS通路序号 |
405    | **返回值** | **返回值描述** |
406    | HDF_SUCCESS | 撤销复位成功 |
407    | 负数 | 撤销复位失败 |
408
409    ```c
410    int32_t ret;
411    uint8_t comboDev;
412
413    // 通路序号为0
414    comboDev = 0;
415    // 撤销复位MIPI RX
416    ret = MipiCsiUnresetRx(MipiCsiHandle, comboDev);
417    if (ret != HDF_SUCCESS) {
418        HDF_LOGE("MipiCsiUnresetRx: mipi csi unreset rx fail, ret=%d\n", ret);
419        return ret;
420    }
421    ```
422
423#### 使能/关闭MIPI的时钟
424
425- 使能MIPI的时钟
426
427    ```c
428    int32_t MipiCsiEnableClock(DevHandle handle, uint8_t comboDev);
429    ```
430
431    **表 13** MipiCsiEnableClock的参数和返回值描述
432
433    <a name="table13_MIPI_CSIDes"></a>
434
435    | 参数 | 参数描述 |
436    | ---------- | -------------- |
437    | handle | DevHandle类型,控制器操作句柄 |
438    | comboDev | uint8_t类型,通路序号 |
439    | **返回值** | **返回值描述** |
440    | HDF_SUCCESS | 使能成功 |
441    | 负数 | 使能失败 |
442
443    ```c
444    int32_t ret;
445    uint8_t comboDev;
446
447    // 通路序号为0
448    comboDev = 0;
449    // 使能MIPI的时钟
450    ret = MipiCsiEnableClock(MipiCsiHandle, comboDev);
451    if (ret != HDF_SUCCESS) {
452        HDF_LOGE("MipiCsiEnableClock: mipi csi enable clock fail, ret=%d\n", ret);
453        return ret;
454    }
455    ```
456
457- 关闭MIPI的时钟
458
459    ```c
460    int32_t MipiCsiDisableClock(DevHandle handle, uint8_t comboDev);
461    ```
462
463    **表 14** MipiCsiDisableClock的参数和返回值描述
464
465    <a name="table14_MIPI_CSIDes"></a>
466
467    | 参数 | 参数描述 |
468    | ---------- | -------------- |
469    | handle | DevHandle类型,控制器操作句柄 |
470    | comboDev | uint8_t类型,通路序号 |
471    | **返回值** | **返回值描述** |
472    | HDF_SUCCESS | 关闭成功 |
473    | 负数 | 关闭失败 |
474
475    ```c
476    int32_t ret;
477    uint8_t comboDev;
478
479    // 通路序号为0
480    comboDev = 0;
481    // 关闭MIPI的时钟
482    ret = MipiCsiDisableClock(MipiCsiHandle, comboDev);
483    if (ret != HDF_SUCCESS) {
484        HDF_LOGE("MipiCsiDisableClock: mipi csi disable clock fail, ret=%d\n", ret);
485        return ret;
486    }
487    ```
488
489#### 使能/关闭MIPI上的Sensor时钟<a name="section2.7_MIPI_CSIDes"></a>
490
491- 使能MIPI上的Sensor时钟
492
493    ```c
494    int32_t MipiCsiEnableSensorClock(DevHandle handle, uint8_t snsClkSource);
495    ```
496
497    **表 15** MipiCsiEnableSensorClock的参数和返回值描述
498
499    <a name="table15_MIPI_CSIDes"></a>
500
501    | 参数 | 参数描述 |
502    | ------------ | ------------------------------------------------ |
503    | handle | DevHandle类型,控制器操作句柄 |
504    | snsClkSource | uint8_t类型,传感器的时钟信号线号,在软件中称为传感器的时钟源 |
505    | **返回值** | **返回值描述** |
506    | HDF_SUCCESS | 使能成功 |
507    | 负数 | 使能失败 |
508
509    ```c
510    int32_t ret;
511    uint8_t snsClkSource;
512
513    // 传感器的时钟信号线号为0
514    snsClkSource = 0;
515    // 使能MIPI上的Sensor时钟
516    ret = MipiCsiEnableSensorClock(MipiCsiHandle, snsClkSource);
517    if (ret != HDF_SUCCESS) {
518        HDF_LOGE("MipiCsiEnableSensorClock: mipi csi enable sensor clock fail, ret=%d\n", ret);
519        return ret;
520    }
521    ```
522
523- 关闭MIPI上的Sensor时钟
524
525    ```c
526    int32_t MipiCsiDisableSensorClock(DevHandle handle, uint8_t snsClkSource);
527    ```
528
529    **表 16** MipiCsiDisableSensorClock的参数和返回值描述
530
531    <a name="table16_MIPI_CSIDes"></a>
532
533    | 参数 | 参数描述 |
534    | ------------ | ------------------------------------------------ |
535    | handle | DevHandle类型,控制器操作句柄 |
536    | snsClkSource | uint8_t类型,传感器的时钟信号线号,在软件中称为传感器的时钟源 |
537    | **返回值** | **返回值描述** |
538    | HDF_SUCCESS | 关闭成功 |
539    | 负数 | 关闭失败 |
540
541    ```c
542    int32_t ret;
543    uint8_t snsClkSource;
544
545    // 传感器的时钟信号线号为0
546    snsClkSource = 0;
547    // 关闭MIPI上的Sensor时钟
548    ret = MipiCsiDisableSensorClock(MipiCsiHandle, snsClkSource);
549    if (ret != HDF_SUCCESS) {
550        HDF_LOGE("MipiCsiDisableSensorClock: mipi csi disable sensor clock fail, ret=%d\n", ret);
551        return ret;
552    }
553    ```
554
555#### 释放MIPI CSI控制器操作句柄<a name="section2.8_MIPI_CSIDes"></a>
556
557MIPI CSI使用完成之后,需要释放控制器操作句柄,释放句柄的函数如下所示:
558
559```c
560void MipiCsiClose(DevHandle handle);
561```
562
563该函数会释放掉由MipiCsiOpen申请的资源。
564
565**表 17** MipiCsiClose的参数和返回值描述
566
567<a name="table17_MIPI_CSIDes"></a>
568
569| 参数 | 参数描述 |
570| ------------ | ------------------------------------------------ |
571| handle | DevHandle类型,MIPI CSI控制器操作句柄 |
572
573```c
574MipiCsiClose(MIPIHandle); // 释放掉MIPI CSI控制器操作句柄
575```
576
577## 使用实例<a name="section3_MIPI_CSIDes"></a>
578
579本例拟对Hi3516DV300开发板上MIPI CSI设备进行操作。
580
581MIPI CSI完整的使用示例如下所示:
582
583```c
584#include "hdf_log.h"
585#include "mipi_csi_if.h"
586#include "securec.h"
587
588enum InterfaceType {
589    INTERFACE_MIPI = 0,
590    INTERFACE_LVDS,
591    INTERFACE_CMOS,
592    INTERFACE_BUTT
593};
594
595static void InitMipiDevAttr(MipiDevAttr *mipiAttr)
596{
597    MipiDevAttr attr;
598    if (mipiAttr == NULL) {
599        return;
600    }
601
602    HDF_LOGI("InitMipiDevAttr: enter.");
603    (void)memset_s(&attr, sizeof(MipiDevAttr), 0, sizeof(MipiDevAttr));
604    attr.inputDataType = DATA_TYPE_RAW_12BIT;
605    attr.wdrMode = HI_MIPI_WDR_MODE_NONE;
606    // laneId: -1 - disable
607    attr.laneId[0] = 0;          // 0 -- laneId 0
608    attr.laneId[1] = 1;          // 1 -- laneId 1
609    attr.laneId[2] = 2;          // 2 -- laneId 2
610    attr.laneId[3] = 3;          // 3 -- laneId 3
611
612    // Used by the HI_MIPI_WDR_MODE_DT, This is not fully tested!
613    if (attr.wdrMode == HI_MIPI_WDR_MODE_DT) {
614        attr.dataType[0] = 0x39; // 0x39 -- data type reserved
615        attr.dataType[1] = 0x39; // 0x39 -- data type reserved
616        attr.dataType[2] = 0x39; // 0x39 -- data type reserved
617        attr.dataType[3] = 0x39; // 0x39 -- data type reserved
618    }
619
620    *mipiAttr = attr;
621}
622
623static int MipiGetIntputModeType(InputMode inputMode)
624{
625    switch (inputMode) {
626        case INPUT_MODE_SUBLVDS:
627        case INPUT_MODE_LVDS:
628        case INPUT_MODE_HISPI:
629            return INTERFACE_LVDS;
630        case INPUT_MODE_MIPI:
631            return INTERFACE_MIPI;
632        case INPUT_MODE_CMOS:
633        case INPUT_MODE_BT1120:
634        case INPUT_MODE_BT656:
635        case INPUT_MODE_BYPASS:
636            return INTERFACE_CMOS;
637        default:
638            break;
639    }
640
641    return INTERFACE_BUTT;
642}
643
644static void InitLvdsDevAttr(LvdsDevAttr *lvdsAttr)
645{
646    int i;
647    int j;
648    int k;
649    LvdsDevAttr attr;
650
651    if (lvdsAttr == NULL) {
652        return;
653    }
654
655    (void)memset_s(&attr, sizeof(LvdsDevAttr), 0, sizeof(LvdsDevAttr));
656    attr.inputDataType = DATA_TYPE_RAW_12BIT;
657    attr.wdrMode = HI_WDR_MODE_NONE;
658    // LVDS synchronization mode. LVDS_SYNC_MODE_SOF, LVDS_SYNC_MODE_SAV
659    attr.syncMode = LVDS_SYNC_MODE_SOF;
660    // LVDS Vsync type. LVDS_VSYNC_NORMAL, LVDS_VSYNC_SHARE, LVDS_VSYNC_HCONNECT
661    attr.vsyncAttr.syncType = LVDS_VSYNC_NORMAL;
662    // hconnect vsync blanking len, valid when the syncType is LVDS_VSYNC_HCONNECT
663    // This is not fully tested!
664    if (attr.vsyncAttr.syncType == LVDS_VSYNC_HCONNECT) {
665        attr.vsyncAttr.hblank1 = 0;
666        attr.vsyncAttr.hblank2 = 0;
667    }
668    // frame identification code: LVDS_FID_NONE, LVDS_FID_IN_SAV, LVDS_FID_IN_DATA
669    attr.fidAttr.fidType = LVDS_FID_NONE;
670    // Sony DOL has the Frame Information Line, in DOL H-Connection mode, should
671    // configure this flag as false to disable output the Frame Information Line.
672    // This is not fully tested!
673    attr.fidAttr.outputFil = 'm';
674    // LVDS bit size end mode: LVDS_ENDIAN_LITTLE, LVDS_ENDIAN_BIG
675    attr.dataEndian = LVDS_ENDIAN_LITTLE;
676    // sync code endian: little/big, LVDS_ENDIAN_LITTLE, LVDS_ENDIAN_BIG
677    attr.syncCodeEndian = LVDS_ENDIAN_LITTLE;
678    // laneId: -1 - disable
679    attr.laneId[0] = 0; // 0 -- laneId 0
680    attr.laneId[1] = 1; // 1 -- laneId 1
681    attr.laneId[2] = 2; // 2 -- laneId 2
682    attr.laneId[3] = 3; // 3 -- laneId 3
683
684    /* each vc has 4 params, syncCode[i]:
685        syncMode is SYNC_MODE_SOF: SOF, EOF, SOL, EOL
686        syncMode is SYNC_MODE_SAV: invalid sav, invalid eav, valid sav, valid eav
687       This is not fully tested! */
688    for (i = 0; i < LVDS_LANE_NUM; i++) {
689        for (j = 0; j < WDR_VC_NUM; j++) {
690            for (k = 0; k < SYNC_CODE_NUM; k++) {
691                attr.syncCode[i][j][k] = 0; // 0 -- frame0 sof
692            }
693        }
694    }
695
696    *lvdsAttr = attr;
697}
698
699static int32_t PalMipiCsiTestSample(void)
700{
701    uint8_t id;
702    int32_t ret;
703    uint8_t comboDev;
704    uint8_t snsClkSource;
705    uint8_t snsResetSource;
706    uint8_t devno;
707    LaneDivideMode laneMode;
708    PhyCmvMode CmvMode;
709    ComboDevAttr attr;
710    DevHandle MipiCsiHandle = NULL;
711    enum InterfaceType interType;
712
713    // 控制器ID号
714    id = 0;
715    // 获取控制器操作句柄
716    MipiCsiHandle = MipiCsiOpen(id);
717    if (MipiCsiHandle == NULL) {
718        HDF_LOGE("PalMipiCsiTestSample: mipi csi open fail!\n");
719        return HDF_FAILURE;
720    }
721
722    // Lane模式参数为0
723    laneMode = LANE_DIVIDE_MODE_0;
724    // 设置MIPI RX的Lane分布
725    ret = MipiCsiSetHsMode(MipiCsiHandle, laneMode);
726    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
727        HDF_LOGE("PalMipiCsiTestSample: mipi csi set hs mode fail, ret=%d\n", ret);
728        return ret;
729    }
730
731    // 通路序号为0
732    comboDev = 0;
733    // 使能MIPI的时钟
734    ret = MipiCsiEnableClock(MipiCsiHandle, comboDev);
735    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
736        HDF_LOGE("PalMipiCsiTestSample: mipi csi enable clock fail, ret=%d\n", ret);
737        return ret;
738    }
739
740    // 复位MIPI RX
741    ret = MipiCsiResetRx(MipiCsiHandle, comboDev);
742    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
743        HDF_LOGE("PalMipiCsiTestSample: mipi csi reset rx fail, ret=%d\n", ret);
744        return ret;
745    }
746
747    // 传感器的时钟信号线号为0
748    snsClkSource = 0;
749    // 使能MIPI上的Sensor时钟
750    ret = MipiCsiEnableSensorClock(MipiCsiHandle, snsClkSource);
751    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
752        HDF_LOGE("PalMipiCsiTestSample: mipi csi enable sensor clock fail, ret=%d\n", ret);
753        return ret;
754    }
755    snsResetSource = 0;
756    // 复位Sensor
757    ret = MipiCsiResetSensor(MipiCsiHandle, snsResetSource);
758    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
759        HDF_LOGE("PalMipiCsiTestSample: mipi csi reset sensor fail, ret=%d\n", ret);
760        return ret;
761    }
762
763    // MIPI参数配置如下
764    (void)memset_s(&attr, sizeof(ComboDevAttr), 0, sizeof(ComboDevAttr));
765    attr.devno = 0;                    // 设备0
766    attr.inputMode = INPUT_MODE_MIPI;  // 输入模式为MIPI
767    attr.dataRate = MIPI_DATA_RATE_X1; // 每时钟输出1像素
768    attr.imgRect.x = 0;                // 0: 图像传感器左上位置
769    attr.imgRect.y = 0;                // 0: 图像传感器右上位置
770    attr.imgRect.width = 2592;         // 2592: 图像传感器宽度大小
771    attr.imgRect.height = 1944;        // 1944: 图像传感器高度尺寸
772    interType = MipiGetIntputModeType(attr.inputMode);
773    if (interType == INTERFACE_MIPI) {
774        HDF_LOGI("PalMipiCsiTestSample: call[InitMipiDevAttr].");
775        InitMipiDevAttr(&attr.mipiAttr);
776    } else if (interType == INTERFACE_LVDS) {
777        HDF_LOGI("PalMipiCsiTestSample: call[InitLvdsDevAttr].");
778        InitLvdsDevAttr(&attr.lvdsAttr);
779    } else {
780        HDF_LOGE("PalMipiCsiTestSample: interType = %d is error!", attr.inputMode);
781    }
782    // 写入配置数据
783    ret = MipiCsiSetComboDevAttr(MipiCsiHandle, &attr);
784    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
785        HDF_LOGE("PalMipiCsiTestSample: mipi csi set combo devAttr fail, ret=%d\n", ret);
786        return ret;
787    }
788
789    // 共模电压模式参数为0
790    CmvMode = PHY_CMV_GE1200MV;
791    // 设备编号为0
792    devno = 0;
793    // 设置共模电压模式
794    ret = MipiCsiSetPhyCmvmode(MipiCsiHandle, devno, CmvMode);
795    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
796        HDF_LOGE("PalMipiCsiTestSample: mipi csi set phy cmv mode fail, ret=%d\n", ret);
797        return ret;
798    }
799
800    // 通路序号为0
801    comboDev = 0;
802    // 撤销复位MIPI RX
803    ret = MipiCsiUnresetRx(MipiCsiHandle, comboDev);
804    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
805        HDF_LOGE("PalMipiCsiTestSample: mipi csi unreset rx fail, ret=%d\n", ret);
806        return ret;
807    }
808
809    // 关闭MIPI的时钟
810    ret = MipiCsiDisableClock(MipiCsiHandle, comboDev);
811    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
812        HDF_LOGE("PalMipiCsiTestSample: mipi csi disable clock fail, ret=%d\n", ret);
813        return ret;
814    }
815
816    // 传感器撤销复位信号线号为0
817    snsResetSource = 0;
818    // 撤销复位Sensor
819    ret = MipiCsiUnresetSensor(MipiCsiHandle, snsResetSource);
820    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
821        HDF_LOGE("PalMipiCsiTestSample: mipi csi unreset sensor fail, ret=%d\n", ret);
822        return ret;
823    }
824
825    // 关闭MIPI上的Sensor时钟
826    ret = MipiCsiDisableSensorClock(MipiCsiHandle, snsClkSource);
827    if (ret != HDF_SUCCESS && ret != HDF_ERR_NOT_SUPPORT) {
828        HDF_LOGE("PalMipiCsiTestSample: mipi csi disable sensor clock fail, ret=%d\n", ret);
829        return ret;
830    }
831    HDF_LOGI("PalMipiCsiTestSample: function tests end.");
832    // 释放MIPI DSI设备句柄
833    MipiCsiClose(MipiCsiHandle);
834    return ret;
835}
836```
837
838