1@page page_device_spi SPI Device
2
3# Introduction to SPI
4
5SPI (Serial Peripheral Interface) is a high-speed, full-duplex, synchronous communication bus commonly used for short-range communication. It is mainly used in EEPROM, FLASH, real-time clock, AD converter, and digital signal processing and between the device and the digital signal decoder. SPI generally uses 4 lines of communication, as shown in the following figure:
6
7![Ways of communication from SPI Master to SPI Slave](figures/spi1.png)
8
9* MOSI :SPI Bus Master Output/Slave Input.
10
11* MISO :SPI Bus Master Input/Slave Output.
12
13* SCLK :Serial Clock, Master device outputs clock signal to slave device.
14
15* CS : select the slave device, also called SS, CSB, CSN, EN, etc., the master device outputs a chip select signal to the slave device.
16
17The SPI works in master-slave mode and usually has one master and one or more slaves. The communication is initiated by the master device. The master device selects the slave device to communicate through CS, and then provides a clock signal to the slave device through SCLK. The data is output to the slave device through the MOSI, and the data sent by the slave device is received through the MISO.
18
19As shown in the figure below, the chip has two SPI controllers. The SPI controller corresponds to the SPI master. Each SPI controller can connect multiple SPI slaves. The slave devices mounted on the same SPI controller share three signal pins: SCK, MISO, MOSI, but the CS pins of each slave device are independent.
20
21![Connect from one SPI controller to multiple SPI slaves](figures/spi2.png)
22
23The master device selects the slave device by controlling the CS pin, typically active low. Only one CS pin is active on an SPI master, and the slave connected to the active CS pin can now communicate with the master.
24
25The slave's clock is provided by the master through SCLK, and MOSI and MISO complete the data transfer based on SCLK. The working timing mode of the SPI is determined by the phase relationship between CPOL (Clock Polarity) and CPHA (Clock Phase). CPOL represents the state of the initial level of the clock signal. A value of 0 indicates that the initial state of the clock signal is low, and a value of 1 indicates that the initial level of the clock signal is high. CPHA indicates on which clock edge the data is sampled. A value of 0 indicates that the data is sampled on the first clock change edge, and a value of 1 indicates that the data is sampled on the second clock change edge. There are 4 working timing modes according to different combinations of CPOL and CPHA: ①CPOL=0, CPHA=0; ②CPOL=0, CPHA=1; ③CPOL=1, CPHA=0; ④CPOL=1, CPHA=1. As shown below:
26
27![4 working timing modes of SPI](figures/spi5.png)
28
29**QSPI:** QSPI is short for Queued SPI and is an extension of the SPI interface from Motorola, which is more extensive than SPI applications. Based on the SPI protocol, Motorola has enhanced its functionality, added a queue transfer mechanism, and introduced a queue serial peripheral interface protocol (QSPI protocol). Using this interface, users can transfer transmission queues containing up to 16 8-bit or 16-bit data at one time. Once the transfer is initiated, CPU is not required until the end of the transfer, greatly improving the transfer efficiency. Compared to SPI, the biggest structural feature of QSPI is the replacement of the transmit and receive data registers of the SPI with 80 bytes of RAM.
30
31**Dual SPI Flash:** For SPI Flash, full-duplex is not commonly used. You can send a command byte into Dual mode and let it work in half-duplex mode to double data transfer. Thus, MOSI becomes SIO0 (serial io 0), and MISO becomes SIO1 (serial io 1), so that 2 bit data can be transmitted in one clock cycle, which doubles the data transmission.
32
33**Quad SPI Flash:** Similar to the Dual SPI, Quad SPI Flash adds two I/O lines (SIO2, SIO3) to transfer 4 bits of data in one clock.
34
35So for SPI Flash, there are three types of standard SPI Flash, Dual SPI Flash, Quad SPI Flash. At the same clock, the higher the number of lines, the higher the transmission rate.
36
37# Mount SPI Device
38
39The SPI driver registers the SPI bus and the SPI device needs to be mounted to the SPI bus that has already been registered.
40
41```C
42rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
43                                  const char           *name,
44                                  const char           *bus_name,
45                                  void                 *user_data)
46```
47
48| **Parameter** | Description                |
49| -------- | ---------------------------------- |
50| device     | SPI device handle                  |
51| name     |  SPI device name                  |
52| bus_name     | SPI bus name                  |
53| user_data     | user data pointer                |
54| **Return** | ——                                 |
55| RT_EOK     | Success     |
56| Other Errors | Failure |
57
58This function is used to mount an SPI device to the specified SPI bus, register the SPI device with the kernel, and save user_data to the control block of the SPI device.
59
60The general SPI bus naming principle is spix, and the SPI device naming principle is spixy. For example, spi10 means device 0 mounted on the spi1 bus. User_data is generally the CS pin pointer of the SPI device. When data is transferred, the SPI controller will operate this pin for chip select.
61
62If you use the BSP in the `rt-thread/bsp/stm32` directory, you can use the following function to mount the SPI device to the bus:
63
64```c
65rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, GPIO_TypeDef* cs_gpiox, uint16_t cs_gpio_pin);
66```
67
68The following sample code mounts the SPI FLASH W25Q128 to the SPI bus:
69
70```c
71static int rt_hw_spi_flash_init(void)
72{
73    __HAL_RCC_GPIOB_CLK_ENABLE();
74    rt_hw_spi_device_attach("spi1", "spi10", GPIOB, GPIO_PIN_14);
75
76    if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10"))
77    {
78        return -RT_ERROR;
79    };
80
81    return RT_EOK;
82}
83/* Export to automatic initialization */
84INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
85```
86
87# Configuring SPI Device
88
89The SPI device's transmission parameters need to be configured after the SPI device is mounted to the SPI bus.
90
91```c
92rt_err_t rt_spi_configure(struct rt_spi_device *device,
93                          struct rt_spi_configuration *cfg)
94```
95
96| **Parameter** | **Description**              |
97| -------- | ---------------------------------- |
98| device   | SPI device handle               |
99| cfg      | SPI configuration parameter pointer |
100| **Return** | ——                                 |
101| RT_EOK     | Success       |
102
103This function saves the configuration parameters pointed to by `cfg` to the control block of the SPI device device, which is used when transferring data.
104
105The `struct rt_spi_configuration` prototype is as follows:
106
107```c
108struct rt_spi_configuration
109{
110    rt_uint8_t mode;        /* mode */
111    rt_uint8_t data_width;  /* data width, 8 bits, 16 bits, 32 bits */
112    rt_uint16_t reserved;   /* reserved */
113    rt_uint32_t max_hz;     /* maximum frequency */
114};
115```
116
117**Mode: **Contains MSB/LSB, master-slave mode, timing mode, etc. The available macro combinations are as follows:
118
119```c
120/* Set the data transmission order whether the MSB bit is first or the LSB bit is before */
121#define RT_SPI_LSB      (0<<2)                        /* bit[2]: 0-LSB */
122#define RT_SPI_MSB      (1<<2)                        /* bit[2]: 1-MSB */
123
124/* Set the master-slave mode of the SPI */
125#define RT_SPI_MASTER   (0<<3)                        /* SPI master device */
126#define RT_SPI_SLAVE    (1<<3)                        /* SPI slave device */
127
128/* Set clock polarity and clock phase */
129#define RT_SPI_MODE_0   (0 | 0)                       /* CPOL = 0, CPHA = 0 */
130#define RT_SPI_MODE_1   (0 | RT_SPI_CPHA)             /* CPOL = 0, CPHA = 1 */
131#define RT_SPI_MODE_2   (RT_SPI_CPOL | 0)             /* CPOL = 1, CPHA = 0 */
132#define RT_SPI_MODE_3   (RT_SPI_CPOL | RT_SPI_CPHA)   /* CPOL = 1, CPHA = 1 */
133
134#define RT_SPI_CS_HIGH  (1<<4)                        /* Chipselect active high */
135#define RT_SPI_NO_CS    (1<<5)                        /* No chipselect */
136#define RT_SPI_3WIRE    (1<<6)                        /* SI/SO pin shared */
137#define RT_SPI_READY    (1<<7)                        /* Slave pulls low to pause */
138```
139
140**Data width:** The data width format that can be sent and received by the SPI master and SPI slaves is set to 8-bit, 16-bit or 32-bit.
141
142**Maximum Frequency:** Set the baud rate for data transfer, also based on the baud rate range at which the SPI master and SPI slaves operate.
143
144The example for configuration is as follows:
145
146```c
147    struct rt_spi_configuration cfg;
148    cfg.data_width = 8;
149    cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
150    cfg.max_hz = 20 * 1000 *1000;                           /* 20M */
151
152    rt_spi_configure(spi_dev, &cfg);
153```
154
155# QSPI Configuration
156
157To configure the transmission parameters of a QSPI device, use the following function:
158
159```c
160rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg);
161```
162
163| **Parameter** | **Description**                 |
164| -------- | ---------------------------------- |
165| device   | QSPI device handle           |
166| cfg      | QSPI configuration parameter pointer |
167| **Return** | ——                                 |
168| RT_EOK     | Success       |
169
170This function saves the configuration parameters pointed to by `cfg` to the control block of the QSPI device, which is used when transferring data.
171
172The `struct rt_qspi_configuration` prototype is as follows:
173
174```c
175struct rt_qspi_configuration
176{
177    struct rt_spi_configuration parent;    /* SPI device configuration parent */
178    rt_uint32_t medium_size;               /* medium size */
179    rt_uint8_t ddr_mode;                   /* double rate mode */
180    rt_uint8_t qspi_dl_width ;             /* QSPI bus width, single line mode 1 bit, 2 line mode 2 bits, 4 line mode 4 bits */
181};
182```
183
184# Access SPI Device
185
186In general, the MCU's SPI device communicates as a master and slave. In the RT-Thread, the SPI master is virtualized as an SPI bus device. The application uses the SPI device management interface to access the SPI slave device. The main interfaces are as follows:
187
188| **Function** | **Description**                |
189| -------------------- | ---------------------------------- |
190| rt_device_find()  | Find device handles based on SPI device name |
191| rt_spi_transfer_message()     | Custom transfer data |
192| rt_spi_transfer()     | Transfer data once |
193| rt_spi_send()     | Send data once |
194| rt_spi_recv()     | Receive data one |
195| rt_spi_send_then_send()  | Send data twice |
196| rt_spi_send_then_recv()  | Send then Receive |
197
198>The SPI data transfer related interface will call rt_mutex_take(). This function cannot be called in the interrupt service routine, which will cause the assertion to report an error.
199
200## Find SPI Device
201
202Before using the SPI device, you need to find and obtain the device handle according to the SPI device name, so that you can operate the SPI device. The device function is as follows.
203
204```c
205rt_device_t rt_device_find(const char* name);
206```
207
208| **Parameter** | **Description**                                              |
209| ------------- | ------------------------------------------------------------ |
210| name          | Device name                                                  |
211| **Return**    | ——                                                           |
212| device handle | Finding the corresponding device will return the corresponding device handle |
213| RT_NULL       | Corresponding device object unfound                          |
214
215In general, the name of the SPI device registered to the system is spi10, qspi10, etc. The usage examples are as follows:
216
217```c
218#define W25Q_SPI_DEVICE_NAME     "qspi10"   /* SPI device name */
219struct rt_spi_device *spi_dev_w25q;     /* SPI device handle */
220
221/* Find the spi device to get the device handle */
222spi_dev_w25q = (struct rt_spi_device *)rt_device_find(W25Q_SPI_DEVICE_NAME);
223```
224
225## Transfer Custom Data
226
227By obtaining the SPI device handle, the SPI device management interface can be used to access the SPI device device for data transmission and reception. You can transfer messages by the following function:
228
229```c
230struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device  *device,struct rt_spi_message *message);
231```
232
233| **Parameter**    | **Description**                                              |
234| ---------------- | ------------------------------------------------------------ |
235| device           | SPI device handle                                            |
236| message          | message pointer                                              |
237| **Return**       | ——                                                           |
238| RT_NULL          | Send successful                                              |
239| Non-null pointer | Send failed, return a pointer to the remaining unsent message |
240
241This function can transmit a series of messages, the user can customize the value of each parameter of the message structure to be transmitted, so that the data transmission mode can be conveniently controlled. The `struct rt_spi_message` prototype is as follows:
242
243```c
244struct rt_spi_message
245{
246    const void *send_buf;           /* Send buffer pointer */
247    void *recv_buf;                 /* Receive buffer pointer */
248    rt_size_t length;               /* Send/receive data bytes */
249    struct rt_spi_message *next;    /* Pointer to the next message to continue sending */
250    unsigned cs_take    : 1;        /* Take chip selection*/
251    unsigned cs_release : 1;        /* Release chip selection */
252};
253```
254send_buf :sendbuf is the send buffer pointer. When the value is RT_NULL, it means that the current transmission is only receiving state, and no data needs to be sent.
255
256recv_buf :recvbuf is the receive buffer pointer. When the value is RT_NULL, it means that the current transmission is in the transmit-only state. It does not need to save the received data, so the received data is directly discarded.
257
258length :The unit of length is word, that is, when the data length is 8 bits, each length occupies 1 byte; when the data length is 16 bits, each length occupies 2 bytes.
259
260next :The parameter next is a pointer to the next message to continue to send. If only one message is sent, the value of this pointer is RT_NULL. Multiple messages to be transmitted are connected together in a singly linked list by the next pointer.
261
262cs_take :A cs_take value of 1 means that the corresponding CS is set to a valid state before data is transferred.
263
264cs_release :A cs_release value of 1 indicates that the corresponding CS is released after the data transfer ends.
265
266>When send_buf or recv_buf is not empty, the available size for both cannot be less than length.
267If you use this function to transfer messages, the first message sent by cs_take needs to be set to 1. Set the chip to be valid, and the cs_release of the last message needs to be set to 1. Release the chip select.
268
269An example of use is as follows:
270
271```c
272#define W25Q_SPI_DEVICE_NAME     "qspi10"   /* SPI device name */
273struct rt_spi_device *spi_dev_w25q;         /* SPI device handle */
274struct rt_spi_message msg1, msg2;
275rt_uint8_t w25x_read_id = 0x90;             /* command */
276rt_uint8_t id[5] = {0};
277
278/* Find the spi device to get the device handle */
279spi_dev_w25q = (struct rt_spi_device *)rt_device_find(W25Q_SPI_DEVICE_NAME);
280/* Send command to read ID */
281struct rt_spi_message msg1, msg2;
282
283msg1.send_buf   = &w25x_read_id;
284msg1.recv_buf   = RT_NULL;
285msg1.length     = 1;
286msg1.cs_take    = 1;
287msg1.cs_release = 0;
288msg1.next       = &msg2;
289
290msg2.send_buf   = RT_NULL;
291msg2.recv_buf   = id;
292msg2.length     = 5;
293msg2.cs_take    = 0;
294msg2.cs_release = 1;
295msg2.next       = RT_NULL;
296
297rt_spi_transfer_message(spi_dev_w25q, &msg1);
298rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", id[3], id[4]);
299```
300
301## Transfer Data Once
302
303If only transfer data for once, use the following function:
304
305```c
306rt_size_t rt_spi_transfer(struct rt_spi_device *device,
307                          const void           *send_buf,
308                          void                  *recv_buf,
309                          rt_size_t             length);
310```
311
312| **Parameter** | **Description**  |
313|----------|----------------------|
314| device   | SPI device handle |
315| send_buf | Send data buffer pointer |
316| recv_buf | Receive data buffer pointer |
317| length   | Length of data send/received |
318| **Return** | ——                   |
319| 0   | Transmission failed |
320| Non-0 Value | Length of data successfully transferred |
321
322This function is equivalent to calling `rt_spi_transfer_message()` to transfer a message. When starting to send data, the chip is selected. When the function returns, the chip is released. The message parameter is configured as follows:
323
324```c
325struct rt_spi_message msg;
326
327msg.send_buf   = send_buf;
328msg.recv_buf   = recv_buf;
329msg.length     = length;
330msg.cs_take    = 1;
331msg.cs_release = 1;
332msg.next        = RT_NULL;
333```
334
335## Send Data Once
336
337If only send data once and ignore the received data, use the following function:
338
339```c
340rt_size_t rt_spi_send(struct rt_spi_device *device,
341                      const void           *send_buf,
342                      rt_size_t             length)
343```
344
345| **Parameter** | **Description** |
346|----------|--------------------|
347| device   | SPI device handle |
348| send_buf | Send data buffer pointer |
349| length   | Length of data sent |
350| **Return** | ——                 |
351| 0    | Transmission failed |
352| Non-0 Value | Length of data successfully transferred |
353
354Call this function to send the data of the buffer pointed to by send_buf, ignoring the received data. This function is a wrapper of the `rt_spi_transfer()` function.
355
356This function is equivalent to calling  `rt_spi_transfer_message()` to transfer a message. When the data starts to be sent, the chip is selected. When the function returns, the chip is released. The message parameter is configured as follows:
357
358```c
359struct rt_spi_message msg;
360
361msg.send_buf   = send_buf;
362msg.recv_buf   = RT_NULL;
363msg.length     = length;
364msg.cs_take    = 1;
365msg.cs_release = 1;
366msg.next       = RT_NULL;
367```
368
369## Receive Data Once
370
371If only receive data once,  use the following function:
372
373```c
374rt_size_t rt_spi_recv(struct rt_spi_device *device,
375                      void                 *recv_buf,
376                      rt_size_t             length);
377```
378
379| **Parameter** | **Description** |
380|----------|--------------------|
381| device   | SPI device handle |
382| recv_buf | Send data buffer pointer |
383| length   | Length of data sent |
384| **Return** | ——                 |
385| 0    | Transmission failed |
386| Non-0 Value | Length of data successfully transferred |
387
388Call this function to receive the data and save it to the buffer pointed to by recv_buf. This function is a wrapper of the `rt_spi_transfer()` function. The SPI bus protocol stipulates that the master can only generate a clock, so when receiving data, the master will send the data 0XFF.
389
390This function is equivalent to calling  `rt_spi_transfer_message()` to transfer a message. When receiving data, the chip is selected. When the function returns, the chip is released. The message parameter is configured as follows:
391
392```c
393struct rt_spi_message msg;
394
395msg.send_buf   = RT_NULL;
396msg.recv_buf   = recv_buf;
397msg.length     = length;
398msg.cs_take    = 1;
399msg.cs_release = 1;
400msg.next       = RT_NULL;
401```
402
403## Send Data Twice in Succession
404
405If need to send data of 2 buffers in succession and the CS is not released within the process, you can call the following function:
406
407```c
408rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
409                               const void           *send_buf1,
410                               rt_size_t             send_length1,
411                               const void           *send_buf2,
412                               rt_size_t             send_length2);
413```
414
415| **Parameter** | **Description**        |
416|--------------|---------------------------|
417| device       | SPI device handle |
418| send_buf1    | Send data buffer pointer 1 |
419| send_length1 | Send data buffer length 1 |
420| send_buf2    | Send data buffer pointer 2 |
421| send_length2 | Send data buffer length 2 |
422| **Return** | ——                        |
423| RT_EOK       | Send Successful |
424| -RT_EIO     | Send Failed        |
425
426This function can continuously send data of 2 buffers, ignore the received data, select the CS when send_buf1 is sent, and release the CS after sending send_buf2.
427
428This function is suitable for writing a piece of data to the SPI device, sending data such as commands and addresses for the first time, and sending data of the specified length for the second time. The reason is that it is sent twice instead of being merged into one data block, or `rt_spi_send()`is called twice, because in most data write operations, commands and addresses need to be sent first, and the length is usually only a few bytes. If send it in conjunction with the data that follows, it will need a memory space request and a lot of data handling. If `rt_spi_send()`is called twice, the chip select will be released after the command and address are sent. Most SPI devices rely on setting the chip select once to be the start of the command, so the chip selects the command or address after sending. After the data is released, the operation is discarded.
429
430This function is equivalent to calling  `rt_spi_transfer_message()` to transfer 2 messages. The message parameter is configured as follows:
431
432```c
433struct rt_spi_message msg1,msg2;
434
435msg1.send_buf   = send_buf1;
436msg1.recv_buf   = RT_NULL;
437msg1.length     = send_length1;
438msg1.cs_take    = 1;
439msg1.cs_release = 0;
440msg1.next       = &msg2;
441
442msg2.send_buf   = send_buf2;
443msg2.recv_buf   = RT_NULL;
444msg2.length     = send_length2;
445msg2.cs_take    = 0;
446msg2.cs_release = 1;
447msg2.next       = RT_NULL;
448```
449
450## Receive Data After Sending Data
451
452If need to send data to the slave device first, then receive the data sent from the slave device, and the CS is not released within the process, call the following function to implement:
453
454```c
455rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
456                               const void           *send_buf,
457                               rt_size_t             send_length,
458                               void                 *recv_buf,
459                               rt_size_t             recv_length);
460```
461
462| **Parameter** | **Description**       |
463|-------------|--------------------------|
464| device      | SPI slave device handle |
465| send_buf    | Send data buffer pointer |
466| send_length | Send data buffer length |
467| recv_buf | Receive data buffer pointer |
468| recv_length | Receive data buffer length |
469| **Return** | ——                       |
470| RT_EOK      | Successful            |
471| -RT_EIO    | Failed                |
472
473This function select CS when sending the first data send_buf when the received data is ignored, and the second data is sent. At this time, the master device will send the data 0XFF, and the received data will be saved in recv_buf, and CS will be released when the function returns.
474
475This function is suitable for reading a piece of data from the SPI slave device. The first time it will send some command and address data, and then receive the data of the specified length.
476
477This function is equivalent to calling  `rt_spi_transfer_message()` to transfer 2 messages. The message parameter is configured as follows:
478
479```c
480struct rt_spi_message msg1,msg2;
481
482msg1.send_buf   = send_buf;
483msg1.recv_buf   = RT_NULL;
484msg1.length     = send_length;
485msg1.cs_take    = 1;
486msg1.cs_release = 0;
487msg1.next       = &msg2;
488
489msg2.send_buf   = RT_NULL;
490msg2.recv_buf   = recv_buf;
491msg2.length     = recv_length;
492msg2.cs_take    = 0;
493msg2.cs_release = 1;
494msg2.next       = RT_NULL;
495```
496
497The SPI device management module also provides  `rt_spi_sendrecv8()` and `rt_spi_sendrecv16()` functions, both are wrapper of the `rt_spi_send_then_recv()`. `rt_spi_sendrecv8()` sends a byte data and receives one byte data, and`rt_spi_sendrecv16()` sends 2 bytes. The section data receives 2 bytes of data at the same time.
498
499# Access QSPI Device
500
501The data transfer interface of QSPI is as follows:
502
503| **P**arameter | **Description**                 |
504| -------------------- | ----------------------------|
505| rt_qspi_transfer_message()     | Transfer message |
506| rt_qspi_send_then_recv()     | Send then receive |
507| rt_qspi_send()               | Send data once |
508
509>The QSPI data transfer related interface will call rt_mutex_take(). This function cannot be called in the interrupt service routine, which will cause the assertion to report an error.
510
511## Transfer Data
512
513Transfer messages by the following function:
514
515```c
516rt_size_t rt_qspi_transfer_message(struct rt_qspi_device  *device, struct rt_qspi_message *message);
517```
518
519| **Parameter** | **Description**                          |
520|----------|--------------------------------------------|
521| device   | QSPI device handle             |
522| message  | Message pointer                     |
523| **Return** | ——                                          |
524| Actual transmitted message size |                      |
525
526The message `structure struct rt_qspi_message` prototype is as follows:
527
528```c
529struct rt_qspi_message
530{
531    struct rt_spi_message parent;   /* inhert from struct rt_spi_message */
532
533    struct
534    {
535        rt_uint8_t content;         /* Instruction content */
536        rt_uint8_t qspi_lines;      /* Instruction mode, single line mode 1 bit, 2 line mode 2 bits, 4 line mode 4 bits */
537    } instruction;                  /* Instruction phase */
538
539     struct
540    {
541        rt_uint32_t content;        /* Address/alternate byte content */
542        rt_uint8_t size;            /* Address/alternate byte size */
543        rt_uint8_t qspi_lines;      /* Address/alternate byte mode, single line mode 1 bit, 2 line mode 2 bits, 4 line mode 4 bits */
544    } address, alternate_bytes;     /* Address/alternate byte stage */
545
546    rt_uint32_t dummy_cycles;       /* Dummy cycle */
547    rt_uint8_t qspi_data_lines;     /* QSPI data line */
548};
549```
550
551## Receive Data
552
553Use the following function to receive data:
554
555```c
556rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device,
557                                const void *send_buf,
558                                rt_size_t send_length,
559                                void *recv_buf,
560                                rt_size_t recv_length);
561```
562
563| **Parameter** | **Description**       |
564|-------------|--------------------------|
565| device      | QSPI device handle |
566| send_buf    | Send data buffer pointer |
567| send_length | Send data length |
568| recv_buf    | Receive data buffer pointer |
569| recv_length | Receive data length |
570| **Return** | ——                       |
571| RT_EOK      | Successful            |
572| Other Errors | Failed             |
573
574The send_buf parameter contains the sequence of commands that will be sent.
575
576## Send Data
577
578```c
579rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
580```
581
582| **Parameter** | **Description**       |
583|-------------|--------------------------|
584| device      | QSPI device handle |
585| send_buf    | Send data buffer pointer |
586| length      | Send data length |
587| **Return** | ——                       |
588| RT_EOK      | Successful            |
589| Other Errors | Failed                |
590
591The send_buf parameter contains the sequence of commands and data to be sent.
592
593# Special Usage Scenarios
594
595In some special usage scenarios, a device wants to monopolize the bus for a period of time, and the CS is always valid during the period, during which the data transmission may be intermittent, then the relevant interface can be used as shown. The transfer data function must use `rt_spi_transfer_message()`, and this function must set the cs_take and cs_release of the message to be transmitted to 0 value, because the CS has already used other interface control, and does not need to control during data transmission.
596
597## Acquire the SPI bus
598
599In the case of multi-threading, the same SPI bus may be used in different threads. In order to prevent the data being transmitted by the SPI bus from being lost, the slave device needs to acquire the right to use the SPI bus before starting to transfer data. To transfer data using the bus, use the following function to acquire the SPI bus:
600
601```c
602rt_err_t rt_spi_take_bus(struct rt_spi_device *device);
603```
604
605| **Parameter** | **Description** |
606|----------|---------------|
607| device   | SPI device handle |
608| **Return** | ——            |
609| RT_EOK   | Successful |
610| Other Errors | Failed     |
611
612## Select CS
613
614After obtaining the usage right of the bus from the device, you need to set the corresponding chip selection signal to be valid. You can use the following function to select the CS:
615
616```c
617rt_err_t rt_spi_take(struct rt_spi_device *device);
618```
619
620| **Parameter** | **Description** |
621|----------|---------------|
622| device   | SPI device handle |
623| **Return** | ——            |
624| 0        | Successful |
625| Other Errors | Failed     |
626
627## Add a New Message
628
629When using `rt_spi_transfer_message()` to transfer messages, all messages to be transmitted are connected in the form of a singly linked list. Use the following function to add a new message to be sent to the message list:
630
631```c
632void rt_spi_message_append(struct rt_spi_message *list,
633                           struct rt_spi_message *message);
634```
635
636| **Parameter** | **Description**                     |
637| ------------- | ----------------------------------- |
638| list          | Message link node to be transmitted |
639| message       | New message pointer                 |
640
641## Release CS
642
643After the device data transfer is completed, CS need to be released. Use the following function to release the CS:
644
645```c
646rt_err_t rt_spi_release(struct rt_spi_device *device);
647```
648
649| **Parameter** | **D**escription |
650|----------|---------------|
651| device   | SPI device handle |
652| Return | ——            |
653| 0        | Successful |
654| Other Errors | Failed     |
655
656## Release Data Bus
657
658The slave device does not use the SPI bus to transfer data. The bus must be released as soon as possible so that other slave devices can use the SPI bus to transfer data. The following function can be used to release the bus:
659
660```c
661rt_err_t rt_spi_release_bus(struct rt_spi_device *device);
662```
663
664| **Parameter** | **Description** |
665|----------|---------------|
666| device   | SPI device handle |
667| **Return** | ——            |
668| RT_EOK   | Successful |
669
670# SPI Device Usage Example
671
672The specific use of the SPI device can be referred to the following sample code. The sample code first finds the SPI device to get the device handle, and then uses the rt_spi_transfer_message() send command to read the ID information.
673
674```c
675/*
676 * Program listing: This is a SPI device usage routine
677 * The routine exports the spi_w25q_sample command to the control terminal
678 * Command call format: spi_w25q_sample spi10
679 * Command explanation: The second parameter of the command is the name of the SPI device to be used. If it is empty, the default SPI device is used.
680 * Program function: read w25q ID data through SPI device
681*/
682
683#include <rtthread.h>
684#include <rtdevice.h>
685
686#define W25Q_SPI_DEVICE_NAME     "qspi10"
687
688static void spi_w25q_sample(int argc, char *argv[])
689{
690    struct rt_spi_device *spi_dev_w25q;
691    char name[RT_NAME_MAX];
692    rt_uint8_t w25x_read_id = 0x90;
693    rt_uint8_t id[5] = {0};
694
695    if (argc == 2)
696    {
697        rt_strncpy(name, argv[1], RT_NAME_MAX);
698    }
699    else
700    {
701        rt_strncpy(name, W25Q_SPI_DEVICE_NAME, RT_NAME_MAX);
702    }
703
704    /* Find the spi device to get the device handle */
705    spi_dev_w25q = (struct rt_spi_device *)rt_device_find(name);
706    if (!spi_dev_w25q)
707    {
708        rt_kprintf("spi sample run failed! can't find %s device!\n", name);
709    }
710    else
711    {
712        /* Method 1: Send the command to read the ID using rt_spi_send_then_recv() */
713        rt_spi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id, 5);
714        rt_kprintf("use rt_spi_send_then_recv() read w25q ID is:%x%x\n", id[3], id[4]);
715
716        /* Method 2: Send the command to read the ID using rt_spi_transfer_message() */
717        struct rt_spi_message msg1, msg2;
718
719        msg1.send_buf   = &w25x_read_id;
720        msg1.recv_buf   = RT_NULL;
721        msg1.length     = 1;
722        msg1.cs_take    = 1;
723        msg1.cs_release = 0;
724        msg1.next       = &msg2;
725
726        msg2.send_buf   = RT_NULL;
727        msg2.recv_buf   = id;
728        msg2.length     = 5;
729        msg2.cs_take    = 0;
730        msg2.cs_release = 1;
731        msg2.next       = RT_NULL;
732
733        rt_spi_transfer_message(spi_dev_w25q, &msg1);
734        rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", id[3], id[4]);
735
736    }
737}
738/* Export to the msh command list */
739MSH_CMD_EXPORT(spi_w25q_sample, spi w25q sample);
740```
741
742