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 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 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 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