1# SPI 2 3 4## Overview 5 6Serial Peripheral Interface (SPI) is a serial bus specification used for high-speed, full-duplex, and synchronous communication. SPI is developed by Motorola. It is commonly used for communication with flash memory, real-time clocks, sensors, and analog-to-digital (A/D) converters. 7 8SPI works in controller/device mode. Generally, there is one SPI controller that controls one or more SPI devices. They are connected via four wires: 9 - SCLK: clock signal output from the SPI controller 10 - MOSI: data output from the SPI controller to a device 11 - MISO: data output from an SPI device to the controller 12 - Chip select (CS): output from the SPI controller to indicate that data is being sent. It is controlled by the SPI controller. 13 14The figure below shows the connection between one controller and two devices (device A and device B). Device A and device B share three pins (SCLK, MISO, and MOSI) of the controller. CS 0 of device A and CS 1 of device B are connected to CS 0 and CS 1 of the controller, respectively. 15 16 **Figure 1** Connection between the SPI controller and devices 17 18 ![image](figures/spi-controller-device-connection.png) 19 20- SPI communication is usually initiated by the controller and is performed as follows: 21 1. The SPI controller selects a device to communicate on the select line. Only one device can be selected at a time. 22 2. SCLK provides clock signals to the selected device. 23 3. The SPI controller sends data to the device via MOSI, and receives data from the devices via MISO. 24 25- SPI can work in one of the following modes according to the combination of Clock Polarity (CPOL) and Clock Phase (CPHA) of the clock signal: 26 - If both CPOL and CPHA are **0**, the clock signal level is low in the idle state and data is sampled on the first clock edge. 27 - If CPOL is **0** and CPHA is **1**, the clock signal level is low in the idle state and data is sampled on the second clock edge. 28 - If CPOL is **1** and CPHA is **0**, the clock signal level is high in the idle state and data is sampled on the first clock edge. 29 - If both CPOL and CPHA are **1**, the clock signal level is high in the idle state and data is sampled on the second clock edge. 30 31- SPI defines a set of common functions for operating an SPI device, including those for: 32 - Obtaining and releasing an SPI device handle. 33 - Reading or writing data of the specified length from or into an SPI device. 34 - Customizing data reading or writing via **SpiMsg**. 35 - Obtaining and setting SPI device attributes. 36 37> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br> 38> Currently, these functions are only applicable in the communication initiated by the SPI controller. 39 40 41## Available APIs 42 43 **Table 1** SPI driver APIs 44 45| API| Description| 46| -------- | -------- | 47| SpiOpen | Opens an SPI device handle.| 48| SpiClose | Closes an SPI device handle.| 49| SpiRead | Reads data of the specified length from a device.| 50| SpiWrite | Writes data of the specified length to a device.| 51| SpiTransfer | Transfers SPI data.| 52| SpiSetCfg | Sets SPI device attributes.| 53| SpiGetCfg | Obtains SPI device attributes.| 54 55> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br> 56> All APIs described in this document can be called only in kernel mode. 57 58 59## Usage Guidelines 60 61 62### How to Use 63 64The figure below shows the general process of using SPI. 65 66 **Figure 2** Process of using SPI APIs 67 68 ![](figures/using-SPI-process.png) 69 70 71### Opening an SPI Device Handle 72 73Before performing SPI communication, call **SpiOpen** to open the SPI device handle. This function returns the device handle of the SPI based on the specified bus number and CS number. 74 75 76``` 77DevHandle SpiOpen(const struct SpiDevInfo *info); 78``` 79 80 **Table 2** Description of SpiOpen 81 82| **Parameter**| **Description**| 83| -------- | -------- | 84| info | Pointer to the SPI device descriptor.| 85| **Return Value**| **Description**| 86| NULL | The operation failed.| 87| Device handle| The operation is successful. The SPI device handle obtained is returned.| 88 89For example, open the handle of the SPI device, whose bus number and the CS number are both **0**. 90 91 92``` 93struct SpiDevInfo spiDevinfo; /* SPI device descriptor. */ 94DevHandle spiHandle = NULL; /* SPI device handle */ 95spiDevinfo.busNum = 0; /* SPI device bus number. */ 96spiDevinfo.csNum = 0; /* SPI device CS number. */ 97 98/* Obtain the SPI device handle. */ 99spiHandle = SpiOpen(&spiDevinfo); 100if (spiHandle == NULL) { 101 HDF_LOGE("SpiOpen: failed\n"); 102 return; 103} 104``` 105 106 107### Obtaining SPI Device Attributes 108 109After obtaining the SPI device handle, you need to configure the device attributes. Before configuring the device attributes, you can call **SpiGetCfg** to obtain the device attributes. 110 111 112``` 113int32_t SpiGetCfg(DevHandle handle, struct SpiCfg *cfg); 114``` 115 116 **Table 3** Description of SpiGetCfg 117 118| **Parameter**| **Description**| 119| -------- | -------- | 120| handle | SPI device handle.| 121| cfg | Pointer to the SPI device attributes.| 122| **Return Value**| **Description**| 123| 0 | The operation is successful.| 124| Negative value | The operation failed.| 125 126 127``` 128int32_t ret; 129struct SpiCfg cfg = {0}; /* SPI configuration. */ 130ret = SpiGetCfg(spiHandle, &cfg); /* Obtain SPI device attributes. */ 131if (ret != 0) { 132 HDF_LOGE("SpiGetCfg: failed, ret %d\n", ret); 133} 134``` 135 136 137### Setting SPI Device Attributes 138 139After obtaining the SPI device handle, call **SpiSetCfg** to set SPI device attributes. 140 141 142``` 143int32_t SpiSetCfg(DevHandle handle, struct SpiCfg *cfg); 144``` 145 146 **Table 4** Description of SpiSetCfg 147 148| **Parameter**| **Description**| 149| -------- | -------- | 150| handle | SPI device handle.| 151| cfg | Pointer to the SPI device attributes.| 152| **Return Value**| **Description**| 153| 0 | The operation is successful.| 154| Negative value | The operation failed.| 155 156 157``` 158int32_t ret; 159struct SpiCfg cfg = {0}; /* SPI configuration. */ 160cfg.mode = SPI_MODE_LOOP; /* Communicate in loop mode. */ 161cfg.transferMode = PAL_SPI_POLLING_TRANSFER; /* Communicate in polling mode. */ 162cfg.maxSpeedHz = 115200; /* Maximum transfer frequency. */ 163cfg.bitsPerWord = 8; /* The width of per word to be read or written is 8 bits. */ 164ret = SpiSetCfg(spiHandle, &cfg); /* Set SPI device attributes. */ 165if (ret != 0) { 166 HDF_LOGE("SpiSetCfg: failed, ret %d\n", ret); 167} 168``` 169 170 171### Performing SPI Communication 172 173- Write data to an SPI device 174 175 Call **SpiWrite()** to write data to an SPI device only once. 176 177 178 ``` 179 int32_t SpiWrite(DevHandle handle, uint8_t *buf, uint32_t len); 180 ``` 181 182 **Table 5** Description of SpiWrite 183 184| **Parameter**| **Description**| 185| -------- | -------- | 186| handle | SPI device handle.| 187| buf | Pointer to the data to write.| 188| len | Length of the data to write.| 189| **Return Value**| **Description**| 190| 0 | The operation is successful.| 191| Negative value | The operation failed.| 192 193 194 ``` 195 int32_t ret; 196 uint8_t wbuff[4] = {0x12, 0x34, 0x56, 0x78}; 197 /* Write data of the specified length to an SPI device. */ 198 ret = SpiWrite(spiHandle, wbuff, 4); 199 if (ret != 0) { 200 HDF_LOGE("SpiWrite: failed, ret %d\n", ret); 201 } 202 ``` 203 204- Read data from an SPI device 205 206 Call **SpiRead()** to read data from an SPI device only once. 207 208 209 ``` 210 int32_t SpiRead(DevHandle handle, uint8_t *buf, uint32_t len); 211 ``` 212 213 **Table 6** Description of SpiRead 214 215| **Parameter**| **Description**| 216| -------- | -------- | 217| handle | SPI device handle.| 218| buf | Pointer to the data to read.| 219| len | Length of the data to read.| 220| **Return Value**| **Description**| 221| 0 | The operation is successful.| 222| Negative value| The operation failed.| 223 224 225 ``` 226 int32_t ret; 227 uint8_t rbuff[4] = {0}; 228 /* Read data of the specified length from an SPI device. */ 229 ret = SpiRead(spiHandle, rbuff, 4); 230 if (ret != 0) { 231 HDF_LOGE("SpiRead: failed, ret %d\n", ret); 232 } 233 ``` 234 235- Perform a custom transfer 236 237 Call **SpiTransfer()** to perform a custom transfer. 238 239 240 ``` 241 int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs, uint32_t count); 242 ``` 243 244 **Table 7** Description of SpiTransfer 245 246| **Parameter**| **Description**| 247| -------- | -------- | 248| handle | SPI device handle.| 249| msgs | Pointer to the message array to be transferred.| 250| count | Number of messages in the message array.| 251| **Return Value**| **Description**| 252| 0 | The operation is successful.| 253| Negative value| The operation failed.| 254 255 256 ``` 257 int32_t ret; 258 uint8_t wbuff[1] = {0x12}; 259 uint8_t rbuff[1] = {0}; 260 struct SpiMsg msg; /* Custom message to be transferred. */ 261 msg.wbuf = wbuff; /* Data to write. */ 262 msg.rbuf = rbuff; /* Data to read. */ 263 msg.len = 1; /* The length of the data to read or write is 1 bit. */ 264 msg.csChange = 1; /* Close the CS before the next transfer. */ 265 msg.delayUs = 0; /* No delay before the next transfer. */ 266 msg.speed = 115200; /* Transfer speed. */ 267 /* Perform a custom transfer. The number of messages to be transferred is 1. */ 268 ret = SpiTransfer(spiHandle, &msg, 1); 269 if (ret != 0) { 270 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret); 271 } 272 ``` 273 274 275### Closing an SPI Device Handle 276 277After the SPI communication, call **SpiClose()** to close the SPI device handle. 278 279 280``` 281void SpiClose(DevHandle handle); 282``` 283 284This function releases the resources requested by **MipiDsiOpen**. 285 286 **Table 8** Description of SpiClose 287 288| **Parameter**| **Description**| 289| -------- | -------- | 290| handle | SPI device handle.| 291 292 293``` 294SpiClose(spiHandle); /* Close the SPI device handle. */ 295``` 296 297 298## Example 299 300The following example shows how to obtain an SPI device handle, set device attributes, and then read or write data from or into the SPI device, and finally close the SPI device handle. 301 302``` 303#include "hdf_log.h" 304#include "spi_if.h" 305 306void SpiTestSample(void) 307{ 308 int32_t ret; 309 struct SpiCfg cfg; /* SPI device configuration. */ 310 struct SpiDevInfo spiDevinfo; /* SPI device descriptor. */ 311 DevHandle spiHandle = NULL; /* SPI device handle. */ 312 struct SpiMsg msg; /* Custom message to be transferred. */ 313 uint8_t rbuff[4] = { 0 }; 314 uint8_t wbuff[4] = { 0x12, 0x34, 0x56, 0x78 }; 315 uint8_t wbuff2[4] = { 0xa1, 0xb2, 0xc3, 0xd4 }; 316 317 spiDevinfo.busNum = 0; /* SPI device bus number. */ 318 spiDevinfo.csNum = 0; /* SPI device CS number. */ 319 spiHandle = SpiOpen(&spiDevinfo); /* Open the SPI device handle based on spiDevinfo. */ 320 if (spiHandle == NULL) { 321 HDF_LOGE("SpiOpen: failed\n"); 322 return; 323 } 324 /* Obtain SPI attributes. */ 325 ret = SpiGetCfg(spiHandle, &cfg); 326 if (ret != 0) { 327 HDF_LOGE("SpiGetCfg: failed, ret %d\n", ret); 328 goto err; 329 } 330 cfg.maxSpeedHz = 115200; /* Set the maximum clock frequency to 115200. */ 331 cfg.bitsPerWord = 8; /* Set the word width to 8 bits. */ 332 /* Set SPI attributes. */ 333 ret = SpiSetCfg(spiHandle, &cfg); 334 if (ret != 0) { 335 HDF_LOGE("SpiSetCfg: failed, ret %d\n", ret); 336 goto err; 337 } 338 /* Write data of the specified length to an SPI device. */ 339 ret = SpiWrite(spiHandle, wbuff, 4); 340 if (ret != 0) { 341 HDF_LOGE("SpiWrite: failed, ret %d\n", ret); 342 goto err; 343 } 344 /* Read data of the specified length from an SPI device. */ 345 ret = SpiRead(spiHandle, rbuff, 4); 346 if (ret != 0) { 347 HDF_LOGE("SpiRead: failed, ret %d\n", ret); 348 goto err; 349 } 350 msg.wbuf = wbuff2; /* Data to write. */ 351 msg.rbuf = rbuff; /* Data to read. */ 352 msg.len = 4; /* Set the length of the data to read or write to 4 bits. */ 353 msg.csChange = 1; /* Close the CS before the next transfer. */ 354 msg.delayUs = 0; /* No delay before the next transfer. */ 355 msg.speed = 115200; /* Transfer speed. */ 356 /* Perform a custom transfer. The number of messages to be transferred is 1. */ 357 ret = SpiTransfer(spiHandle, &msg, 1); 358 if (ret != 0) { 359 HDF_LOGE("SpiTransfer: failed, ret %d\n", ret); 360 goto err; 361 } 362err: 363 /* Close the SPI device handle. */ 364 SpiClose(spiHandle); 365} 366``` 367