1e41f4b71Sopenharmony_ci# SPI
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## 概述
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### 功能简介
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciSPI指串行外设接口(Serial Peripheral Interface),是一种高速的,全双工,同步的通信总线。SPI是由Motorola公司开发,用于在主设备和从设备之间进行通信。
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciSPI接口定义了操作SPI设备的通用方法集合,包括:
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci- SPI设备句柄获取和释放。
12e41f4b71Sopenharmony_ci  
13e41f4b71Sopenharmony_ci- SPI读写:从SPI设备读取或写入指定长度数据。
14e41f4b71Sopenharmony_ci 
15e41f4b71Sopenharmony_ci- SPI自定义传输:通过消息传输结构体执行任意读写组合过程。
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci- SPI设备配置:获取和设置SPI设备属性。
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci### 运作机制
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci在HDF框架中,SPI的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,若设备过多可能增加内存占用。
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为:
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci- 驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci- device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ci**图 1** SPI独立服务模式结构图<a name="fig1"></a>  
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci![SPI独立服务模式结构图](figures/独立服务模式结构图.png)
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ciSPI模块各分层作用:
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ci- 接口层提供打开SPI设备、SPI写数据、SPI读数据、SPI传输、配置SPI设备属性、获取SPI设备属性、关闭SPI设备的接口。
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci- 核心层主要提供SPI控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互。
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci- 适配层主要是将钩子函数的功能实例化,实现具体的功能。
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciSPI以主从方式工作,通常有一个主设备和一个或者多个从设备。主设备和从设备之间一般用4根线相连,它们分别是:
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci- SCLK:时钟信号,由主设备产生;
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci- MOSI:主设备数据输出,从设备数据输入;
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci- MISO:主设备数据输入,从设备数据输出;
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci- CS:片选,从设备使能信号,由主设备控制。
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci一个主设备和两个从设备的连接示意图如图2所示,Device A和Device B共享主设备的SCLK、MISO和MOSI三根引脚,Device A的片选CS0连接主设备的CS0,Device B的片选CS1连接主设备的CS1。
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci**图 2** SPI主从设备连接示意图
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci![SPI主从设备连接示意图](figures/SPI主从设备连接示意图.png)
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ci- SPI通信通常由主设备发起,通过以下步骤完成一次通信:
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ci    1. 通过CS选中要通信的从设备,在任意时刻,一个主设备上最多只能有一个从设备被选中。
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci    2. 通过SCLK给选中的从设备提供时钟信号。
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ci    3. 基于SCLK时钟信号,主设备数据通过MOSI发送给从设备,同时通过MISO接收从设备发送的数据,完成通信。
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci- 根据SCLK时钟信号的CPOL(Clock Polarity,时钟极性)和CPHA(Clock Phase,时钟相位)的不同组合,SPI有以下四种工作模式:
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ci    - CPOL=0,CPHA=0 时钟信号idle状态为低电平,第一个时钟边沿采样数据。
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci    - CPOL=0,CPHA=1 时钟信号idle状态为低电平,第二个时钟边沿采样数据。
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci    - CPOL=1,CPHA=0 时钟信号idle状态为高电平,第一个时钟边沿采样数据。
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci    - CPOL=1,CPHA=1 时钟信号idle状态为高电平,第二个时钟边沿采样数据。
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ci### 约束与限制
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ciSPI模块当前只支持主机模式,不支持从机模式。
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci## 使用指导
80e41f4b71Sopenharmony_ci
81e41f4b71Sopenharmony_ci### 场景介绍
82e41f4b71Sopenharmony_ci
83e41f4b71Sopenharmony_ciSPI通常用于与闪存、实时时钟、传感器以及模数/数模转换器等支持SPI协议的设备进行通信。
84e41f4b71Sopenharmony_ci
85e41f4b71Sopenharmony_ci### 接口说明
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ciSPI模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/spi_if.h88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci**表 1** SPI驱动API接口功能介绍
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci| 接口名 | 接口描述 |
92e41f4b71Sopenharmony_ci| -------- | -------- |
93e41f4b71Sopenharmony_ci| DevHandle SpiOpen(const struct SpiDevInfo \*info) | 获取SPI设备句柄 |
94e41f4b71Sopenharmony_ci| void SpiClose(DevHandle handle) | 释放SPI设备句柄 |
95e41f4b71Sopenharmony_ci| int32_t SpiRead(DevHandle handle, uint8_t \*buf, uint32_t len) | 读取指定长度的数据 |
96e41f4b71Sopenharmony_ci| int32_t SpiWrite(DevHandle handle, uint8_t \*buf, uint32_t len) | 写入指定长度的数据 |
97e41f4b71Sopenharmony_ci| int32_t SpiTransfer(DevHandle handle, struct SpiMsg \*msgs, uint32_t count) | SPI数据传输接口 |
98e41f4b71Sopenharmony_ci| int32_t SpiSetCfg(DevHandle handle, struct SpiCfg \*cfg) | 根据指定参数,配置SPI设备 |
99e41f4b71Sopenharmony_ci| int32_t SpiGetCfg(DevHandle handle, struct SpiCfg \*cfg) | 获取SPI设备配置参数 |
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ci### 使用流程
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci使用SPI的一般流程如下图所示。
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci**图 3** SPI使用流程图
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci![SPI使用流程图](figures/SPI使用流程图.png)
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci#### 获取SPI设备句柄
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci在使用SPI进行通信时,首先要调用SpiOpen获取SPI设备句柄,该函数会返回指定总线号和片选号的SPI设备句柄。
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci```c
114e41f4b71Sopenharmony_ciDevHandle SpiOpen(const struct SpiDevInfo *info); 
115e41f4b71Sopenharmony_ci```
116e41f4b71Sopenharmony_ci
117e41f4b71Sopenharmony_ci**表 2** SpiOpen参数和返回值描述
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci| **参数** | **参数描述** |
120e41f4b71Sopenharmony_ci| -------- | -------- |
121e41f4b71Sopenharmony_ci| info | 结构体类型,SPI设备描述符 |
122e41f4b71Sopenharmony_ci| **返回值** | **返回值描述** |
123e41f4b71Sopenharmony_ci| NULL | 获取SPI设备句柄失败 |
124e41f4b71Sopenharmony_ci| 设备句柄 | 获取对应的SPI设备句柄成功 |
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ci假设系统中的SPI设备总线号为0,片选号为0,获取该SPI设备句柄的示例如下:
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci```c
129e41f4b71Sopenharmony_cistruct SpiDevInfo spiDevinfo;       // SPI设备描述符
130e41f4b71Sopenharmony_ciDevHandle spiHandle = NULL;         // SPI设备句柄
131e41f4b71Sopenharmony_cispiDevinfo.busNum = 0;              // SPI设备总线号
132e41f4b71Sopenharmony_cispiDevinfo.csNum = 0;               // SPI设备片选号
133e41f4b71Sopenharmony_ci
134e41f4b71Sopenharmony_ci// 获取SPI设备句柄
135e41f4b71Sopenharmony_cispiHandle = SpiOpen(&spiDevinfo);
136e41f4b71Sopenharmony_ciif (spiHandle == NULL) {
137e41f4b71Sopenharmony_ci    HDF_LOGE("SpiOpen: spi open fail!\n");
138e41f4b71Sopenharmony_ci    return HDF_FAILURE;
139e41f4b71Sopenharmony_ci}
140e41f4b71Sopenharmony_ci```
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ci#### 获取SPI设备属性
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci在获取到SPI设备句柄之后,需要配置SPI设备属性。配置SPI设备属性之前,可以先获取SPI设备属性,获取SPI设备属性的函数如下所示:
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci```c
147e41f4b71Sopenharmony_ciint32_t SpiGetCfg(DevHandle handle, struct SpiCfg *cfg);
148e41f4b71Sopenharmony_ci```
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci**表 3** SpiGetCfg参数和返回值描述
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ci| **参数** | **参数描述** |
153e41f4b71Sopenharmony_ci| -------- | -------- |
154e41f4b71Sopenharmony_ci| handle | DevHandle类型,SPI设备句柄 |
155e41f4b71Sopenharmony_ci| cfg | 结构体指针类型,SPI设备配置参数 |
156e41f4b71Sopenharmony_ci| **返回值** | **返回值描述** |
157e41f4b71Sopenharmony_ci| HDF_SUCCESS | 获取设备属性成功 |
158e41f4b71Sopenharmony_ci| 负数 | 获取设备属性失败 |
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci```c
161e41f4b71Sopenharmony_ciint32_t ret;
162e41f4b71Sopenharmony_cistruct SpiCfg cfg = {0};                // SPI配置信息
163e41f4b71Sopenharmony_ciret = SpiGetCfg(spiHandle, &cfg);       // 获取SPI设备属性
164e41f4b71Sopenharmony_ciif (ret != HDF_SUCCESS) {
165e41f4b71Sopenharmony_ci    HDF_LOGE("SpiGetCfg: failed, ret %d\n", ret);
166e41f4b71Sopenharmony_ci    return ret;
167e41f4b71Sopenharmony_ci}
168e41f4b71Sopenharmony_ci```
169e41f4b71Sopenharmony_ci
170e41f4b71Sopenharmony_ci#### 配置SPI设备属性
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci在获取到SPI设备句柄之后,需要配置SPI设备属性,配置SPI设备属性的函数如下所示:
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ci```c
175e41f4b71Sopenharmony_ciint32_t SpiSetCfg(DevHandle handle, struct SpiCfg *cfg);
176e41f4b71Sopenharmony_ci```
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci**表 4** SpiSetCfg参数和返回值描述
179e41f4b71Sopenharmony_ci
180e41f4b71Sopenharmony_ci| **参数** | **参数描述** |
181e41f4b71Sopenharmony_ci| -------- | -------- |
182e41f4b71Sopenharmony_ci| handle | DevHandle类型,SPI设备句柄 |
183e41f4b71Sopenharmony_ci| cfg | 结构体指针类型,SPI设备配置参数 |
184e41f4b71Sopenharmony_ci| **返回值** | **返回值描述** |
185e41f4b71Sopenharmony_ci| HDF_SUCCESS | 配置设备属性成功 |
186e41f4b71Sopenharmony_ci| 负数 | 配置设备属性失败 |
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci```c
189e41f4b71Sopenharmony_ciint32_t ret;
190e41f4b71Sopenharmony_cistruct SpiCfg cfg = {0};                     // SPI配置信息
191e41f4b71Sopenharmony_cicfg.mode = SPI_MODE_LOOP;                    // 以回环模式进行通信
192e41f4b71Sopenharmony_cicfg.transferMode = PAL_SPI_POLLING_TRANSFER; // 以轮询的方式进行通信
193e41f4b71Sopenharmony_cicfg.maxSpeedHz = 115200;                     // 最大传输频率
194e41f4b71Sopenharmony_cicfg.bitsPerWord = 8;                         // 读写位宽为8比特
195e41f4b71Sopenharmony_ciret = SpiSetCfg(spiHandle, &cfg);            // 配置SPI设备属性
196e41f4b71Sopenharmony_ciif (ret != HDF_SUCCESS) {
197e41f4b71Sopenharmony_ci    HDF_LOGE("SpiSetCfg: failed, ret %d\n", ret);
198e41f4b71Sopenharmony_ci    return ret;
199e41f4b71Sopenharmony_ci}
200e41f4b71Sopenharmony_ci```
201e41f4b71Sopenharmony_ci
202e41f4b71Sopenharmony_ci#### 进行SPI通信
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci- 向SPI设备写入指定长度的数据
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci    如果只向SPI设备写一次数据,则可以通过以下函数完成:
207e41f4b71Sopenharmony_ci
208e41f4b71Sopenharmony_ci    ```c
209e41f4b71Sopenharmony_ci    int32_t SpiWrite(DevHandle handle, uint8_t *buf, uint32_t len);
210e41f4b71Sopenharmony_ci    ```
211e41f4b71Sopenharmony_ci
212e41f4b71Sopenharmony_ci    **表 5** SpiWrite参数和返回值描述
213e41f4b71Sopenharmony_ci
214e41f4b71Sopenharmony_ci    | **参数** | **参数描述** |
215e41f4b71Sopenharmony_ci    | -------- | -------- |
216e41f4b71Sopenharmony_ci    | handle | DevHandle类型,SPI设备句柄 |
217e41f4b71Sopenharmony_ci    | buf | uint8_t类型指针,待写入数据 |
218e41f4b71Sopenharmony_ci    | len | uint32_t类型,待写入的数据长度 |
219e41f4b71Sopenharmony_ci    | **返回值** | **返回值描述** |
220e41f4b71Sopenharmony_ci    | HDF_SUCCESS | 写入成功 |
221e41f4b71Sopenharmony_ci    | 负数 | 写入失败 |
222e41f4b71Sopenharmony_ci
223e41f4b71Sopenharmony_ci    ```c
224e41f4b71Sopenharmony_ci    int32_t ret;
225e41f4b71Sopenharmony_ci    uint8_t wbuff[4] = {0x12, 0x34, 0x56, 0x78};
226e41f4b71Sopenharmony_ci    // 向SPI设备写入指定长度的数据
227e41f4b71Sopenharmony_ci    ret = SpiWrite(spiHandle, wbuff, 4);
228e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
229e41f4b71Sopenharmony_ci        HDF_LOGE("SpiWrite: failed, ret %d\n", ret);
230e41f4b71Sopenharmony_ci        return ret;
231e41f4b71Sopenharmony_ci    }
232e41f4b71Sopenharmony_ci    ```
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci- 从SPI设备读取指定长度的数据
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci    如果只读取一次数据,则可以通过以下函数完成:
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_ci    ```c
239e41f4b71Sopenharmony_ci    int32_t SpiRead(DevHandle handle, uint8_t *buf, uint32_t len); 
240e41f4b71Sopenharmony_ci    ```
241e41f4b71Sopenharmony_ci
242e41f4b71Sopenharmony_ci    **表 6** SpiRead参数和返回值描述
243e41f4b71Sopenharmony_ci
244e41f4b71Sopenharmony_ci    | **参数** | **参数描述** |
245e41f4b71Sopenharmony_ci    | -------- | -------- |
246e41f4b71Sopenharmony_ci    | handle | DevHandle类型,SPI设备句柄 |
247e41f4b71Sopenharmony_ci    | buf | uint8_t类型指针,待读取数据 |
248e41f4b71Sopenharmony_ci    | len | uint32_t类型,待读取的数据长度 |
249e41f4b71Sopenharmony_ci    | **返回值** | **返回值描述** |
250e41f4b71Sopenharmony_ci    | HDF_SUCCESS | 读取成功 |
251e41f4b71Sopenharmony_ci    | 负数 | 读取失败 |
252e41f4b71Sopenharmony_ci
253e41f4b71Sopenharmony_ci    ```c
254e41f4b71Sopenharmony_ci    int32_t ret;
255e41f4b71Sopenharmony_ci    uint8_t rbuff[4] = {0};
256e41f4b71Sopenharmony_ci    // 从SPI设备读取指定长度的数据
257e41f4b71Sopenharmony_ci    ret = SpiRead(spiHandle, rbuff, 4);
258e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
259e41f4b71Sopenharmony_ci        HDF_LOGE("SpiRead: failed, ret %d\n", ret);
260e41f4b71Sopenharmony_ci        return ret;
261e41f4b71Sopenharmony_ci    }
262e41f4b71Sopenharmony_ci    ```
263e41f4b71Sopenharmony_ci
264e41f4b71Sopenharmony_ci- 自定义传输
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ci    如果需要发起一次自定义传输,则可以通过以下函数完成:
267e41f4b71Sopenharmony_ci
268e41f4b71Sopenharmony_ci    ```c
269e41f4b71Sopenharmony_ci    int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs, uint32_t count);
270e41f4b71Sopenharmony_ci    ```
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ci    **表 7** SpiTransfer参数和返回值描述
273e41f4b71Sopenharmony_ci
274e41f4b71Sopenharmony_ci    | **参数** | **参数描述** |
275e41f4b71Sopenharmony_ci    | -------- | -------- |
276e41f4b71Sopenharmony_ci    | handle | DevHandle类型,SPI设备句柄 |
277e41f4b71Sopenharmony_ci    | msgs | 结构体指针,待传输数据的数组 |
278e41f4b71Sopenharmony_ci    | count | uint32_t类型,msgs数组长度 |
279e41f4b71Sopenharmony_ci    | **返回值** | **返回值描述** |
280e41f4b71Sopenharmony_ci    | HDF_SUCCESS | 传输执行成功 |
281e41f4b71Sopenharmony_ci    | 负数 | 传输执行失败 |
282e41f4b71Sopenharmony_ci
283e41f4b71Sopenharmony_ci    ```c
284e41f4b71Sopenharmony_ci    int32_t ret;
285e41f4b71Sopenharmony_ci    uint8_t wbuff[1] = {0x12};
286e41f4b71Sopenharmony_ci    uint8_t rbuff[1] = {0};
287e41f4b71Sopenharmony_ci    struct SpiMsg msg;        // 自定义传输的消息
288e41f4b71Sopenharmony_ci    msg.wbuf = wbuff;         // 写入的数据
289e41f4b71Sopenharmony_ci    msg.rbuf = rbuff;         // 读取的数据
290e41f4b71Sopenharmony_ci    msg.len = 1;              // 读取、写入数据的长度都是1
291e41f4b71Sopenharmony_ci    msg.csChange = 1;         // 进行下一次传输前关闭片选
292e41f4b71Sopenharmony_ci    msg.delayUs = 0;          // 进行下一次传输前不进行延时
293e41f4b71Sopenharmony_ci    msg.speed = 115200;       // 本次传输的速度
294e41f4b71Sopenharmony_ci    // 进行一次自定义传输,传输的msg个数为1
295e41f4b71Sopenharmony_ci    ret = SpiTransfer(spiHandle, &msg, 1);
296e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
297e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
298e41f4b71Sopenharmony_ci        return ret;
299e41f4b71Sopenharmony_ci    }
300e41f4b71Sopenharmony_ci    ```
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci#### 销毁SPI设备句柄
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ciSPI通信完成之后,需要销毁SPI设备句柄,销毁SPI设备句柄的函数如下所示:
305e41f4b71Sopenharmony_ci
306e41f4b71Sopenharmony_ci```c
307e41f4b71Sopenharmony_civoid SpiClose(DevHandle handle);
308e41f4b71Sopenharmony_ci```
309e41f4b71Sopenharmony_ci
310e41f4b71Sopenharmony_ci该函数会释放掉申请的资源。
311e41f4b71Sopenharmony_ci
312e41f4b71Sopenharmony_ci**表 8** SpiClose参数描述
313e41f4b71Sopenharmony_ci
314e41f4b71Sopenharmony_ci| **参数** | **参数描述** |
315e41f4b71Sopenharmony_ci| -------- | -------- |
316e41f4b71Sopenharmony_ci| handle | DevHandle类型,SPI设备句柄 |
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ci```c
319e41f4b71Sopenharmony_ciSpiClose(spiHandle); // 销毁SPI设备句柄
320e41f4b71Sopenharmony_ci```
321e41f4b71Sopenharmony_ci
322e41f4b71Sopenharmony_ci### 使用实例
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci本例拟对Hi3516DV300开发板上SPI设备进行操作。
325e41f4b71Sopenharmony_ci
326e41f4b71Sopenharmony_ciSPI设备完整的使用示例如下所示,首先获取SPI设备句柄,然后配置SPI设备属性,接着调用读写接口进行数据传输,最后销毁SPI设备句柄。
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci```c
329e41f4b71Sopenharmony_ci#include "hdf_log.h"
330e41f4b71Sopenharmony_ci#include "spi_if.h"
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_civoid SpiTestSample(void)
333e41f4b71Sopenharmony_ci{
334e41f4b71Sopenharmony_ci    int32_t ret;
335e41f4b71Sopenharmony_ci    struct SpiCfg cfg;                      // SPI配置信息
336e41f4b71Sopenharmony_ci    struct SpiDevInfo spiDevinfo;           // SPI设备描述符
337e41f4b71Sopenharmony_ci    DevHandle spiHandle = NULL;             // SPI设备句柄
338e41f4b71Sopenharmony_ci    struct SpiMsg msg;                      // 自定义传输的消息
339e41f4b71Sopenharmony_ci    uint8_t rbuff[4] = { 0 };
340e41f4b71Sopenharmony_ci    uint8_t wbuff[4] = { 0x12, 0x34, 0x56, 0x78 };
341e41f4b71Sopenharmony_ci    uint8_t wbuff2[4] = { 0xa1, 0xb2, 0xc3, 0xd4 };
342e41f4b71Sopenharmony_ci
343e41f4b71Sopenharmony_ci    spiDevinfo.busNum = 0;                  // SPI设备总线号
344e41f4b71Sopenharmony_ci    spiDevinfo.csNum = 0;                   // SPI设备片选号
345e41f4b71Sopenharmony_ci    spiHandle = SpiOpen(&spiDevinfo);       // 根据spiDevinfo获取SPI设备句柄
346e41f4b71Sopenharmony_ci    if (spiHandle == NULL) {
347e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTestSample: spi open fail!\n");
348e41f4b71Sopenharmony_ci        return;
349e41f4b71Sopenharmony_ci    }
350e41f4b71Sopenharmony_ci    // 获取SPI设备属性
351e41f4b71Sopenharmony_ci    ret = SpiGetCfg(spiHandle, &cfg);
352e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
353e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTestSample: spi get cfg fail, ret:%d!\n", ret);
354e41f4b71Sopenharmony_ci        goto err;
355e41f4b71Sopenharmony_ci    }
356e41f4b71Sopenharmony_ci    cfg.maxSpeedHz = 115200;                // 将最大时钟频率改为115200
357e41f4b71Sopenharmony_ci    cfg.bitsPerWord = 8;                    // 传输位宽改为8比特
358e41f4b71Sopenharmony_ci    // 配置SPI设备属性
359e41f4b71Sopenharmony_ci    ret = SpiSetCfg(spiHandle, &cfg);
360e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
361e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTestSample: spi set cfg fail, ret:%d!\n", ret);
362e41f4b71Sopenharmony_ci        goto err;
363e41f4b71Sopenharmony_ci    }
364e41f4b71Sopenharmony_ci    /* 向SPI设备写入指定长度的数据 */
365e41f4b71Sopenharmony_ci    ret = SpiWrite(spiHandle, wbuff, 4);
366e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
367e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTestSample: spi write fail, ret:%d!\n", ret);
368e41f4b71Sopenharmony_ci        goto err;
369e41f4b71Sopenharmony_ci    }
370e41f4b71Sopenharmony_ci    /* 从SPI设备读取指定长度的数据 */
371e41f4b71Sopenharmony_ci    ret = SpiRead(spiHandle, rbuff, 4);
372e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
373e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTestSample: spi read fail, ret:%d!\n", ret);
374e41f4b71Sopenharmony_ci        goto err;
375e41f4b71Sopenharmony_ci    }
376e41f4b71Sopenharmony_ci    msg.wbuf = wbuff2;                      // 写入的数据
377e41f4b71Sopenharmony_ci    msg.rbuf = rbuff;                       // 读取的数据
378e41f4b71Sopenharmony_ci    msg.len = 4;                            // 读取写入数据的长度为4
379e41f4b71Sopenharmony_ci    msg.keepCs = 0;                         // 当前传输完成后是否保持CS活动,1表述保持,0表示关闭CS
380e41f4b71Sopenharmony_ci    msg.delayUs = 0;                        // 进行下一次传输前不进行延时
381e41f4b71Sopenharmony_ci    msg.speed = 115200;                     // 本次传输的速度
382e41f4b71Sopenharmony_ci    // 进行一次自定义传输,传输的msg个数为1
383e41f4b71Sopenharmony_ci    ret = SpiTransfer(spiHandle, &msg, 1);
384e41f4b71Sopenharmony_ci    if (ret != HDF_SUCCESS) {
385e41f4b71Sopenharmony_ci        HDF_LOGE("SpiTestSample: spi transfer fail, ret:%d!\n", ret);
386e41f4b71Sopenharmony_ci        goto err;
387e41f4b71Sopenharmony_ci    }
388e41f4b71Sopenharmony_ci    HDF_LOGD("SpiTestSample: function tests end!");
389e41f4b71Sopenharmony_cierr:
390e41f4b71Sopenharmony_ci    // 销毁SPI设备句柄
391e41f4b71Sopenharmony_ci    SpiClose(spiHandle);
392e41f4b71Sopenharmony_ci}
393e41f4b71Sopenharmony_ci```
394