SPI Master
Introduction
SPI is a high-speed, full-duplex, synchronous serial communication protocol. In SPI communication, devices are divided into master (Master) and slave (Slave). The SPI-Master acts as the main controller, responsible for initiating the communication process, controlling the timing and rate of data transmission, and managing the entire communication flow. It plays a leading role in SPI communication, capable of actively sending instructions or data to SPI slave devices and receiving responses from slave devices.
Function List
Initialization — Initialize the SPI driver.
Synchronous Data Transfer — Ends the transfer when data transmission is completed or transmission times out.
Asynchronous Data Transfer — Ends the transfer after data transmission is completed and enters the callback function.
Function Overview
Full-Duplex Communication SPI supports simultaneous sending and receiving of data, where data transmission and reception can occur simultaneously within each clock cycle.
Clock Control SPI Master generates and controls the serial clock signal (SCLK) to synchronize data transmission.
Chip Select Management SPI-M can select different slave devices for communication by controlling the chip select signal (CS).
Data Transmission Control SPI Master controls the direction of data transmission and decides when to send and receive data.
High Transmission Rate Compared to interfaces like I2C, SPI has a higher transmission rate, making it suitable for high-speed data transmission applications.
SPI has four transmission modes as shown in the table below
SPI Mode |
CPOL |
CPHA |
Description |
---|---|---|---|
Mode 0 |
0 |
0 |
SCLK is low when idle, data is sampled on the rising edge |
Mode 1 |
0 |
1 |
SCLK is low when idle, data is sampled on the falling edge |
Mode 2 |
1 |
0 |
SCLK is high when idle, data is sampled on the falling edge |
Mode 3 |
1 |
1 |
SCLK is high when idle, data is sampled on the rising edge |
SPI Master Hardware Wiring
Initializing SPI
Before using SPI, you need to call the
wm_drv_spim_init()
function to allocate resources for SPI and receive the SPI device identifier with thewm_device_t
structure. Example:wm_device_t *spi_dev; spi_dev = wm_drv_spim_init("spi");When initializing, simply pass the string
"spi"
.Note
If SPI is already initialized, you can directly call
wm_dt_get_device_by_name
to get the SPI device pointer.SPI-related configurations can be changed in the device tree.
SPI Synchronous Transmission
Setting Transmission Parameters
The API will return after the end of transmissions or timeout. The user can set the maximum waiting time. If transmission does not end within this time, it will return immediately.
The SPI device can communicate with the slave using SPI. The default GPIO pins for SPI are CLK: GPIO17, MISO: GPIO16, and MOSI: GPIO21. If necessary, these can be modified in the device tree.
Different slaves need to select their own CS pin. W800 provides CS GPIO as GPIO0, GPIO20, GPIO30, GPIO39.
CS pins and other parameters are all in the
wm_dt_hw_spim_dev_cfg_t
structure.Use synchronous transmission by calling
wm_drv_spim_transceive_sync()
and passing thewm_dt_hw_spim_dev_cfg_t
andtransceive_t
structures.1. SPI Device Parameter Configuration
The transmission frequency, mode, and pins of SPI can be configured in the
wm_dt_hw_spim_dev_cfg_t
structure. Example:wm_device_t *spi_dev; spi_dev = wm_drv_spim_init("spi"); wm_dt_hw_spim_dev_cfg_t config = { .freq = 2, // 2M clock .mode = 0, // SPI mode .pin_cs = { .pin_num = WM_GPIO_NUM_20, .pin_mux = WM_GPIO_IOMUX_FUN5, }, };2. SPI Chip Select Pin Configuration
SPI transmission pins need to be configured separately, set to floating output mode as chip select pins, active low. Example:
// SPI GPIO config wm_drv_gpio_iomux_func_sel(config.pin_cs.pin_num, WM_GPIO_IOMUX_FUN5); wm_drv_gpio_set_pullmode(config.pin_cs.pin_num, WM_GPIO_FLOAT); wm_drv_gpio_set_dir(config.pin_cs.pin_num, WM_GPIO_DIR_OUTPUT); wm_drv_gpio_data_set(config.pin_cs.pin_num);3. SPI Transmission Parameter Configuration
The data sent and transmitted by SPI need to set tx_buffer and rx_buffer. The data to be sent is stored in tx_buffer, and the received data is stored in rx_buffer.
Supports non-empty tx buffer and rx buffer, simultaneous transmission and reception.
Supports empty tx buffer and non-empty rx buffer, only receive without sending data.
Supports non-empty tx buffer and empty rx buffer, only send without receiving data.
Example configuration:
uint32_t tx_len = 8; uint8_t *tx_buf = NULL; uint32_t rx_len = 8; uint8_t *rx_buf = NULL; tx_buf = malloc(tx_len); rx_buf = malloc(rx_len); transceive_t desc = { .tx_buf = tx_buf, .tx_len = tx_len, .rx_buf = rx_buf, .rx_len = rx_len, };
Starting Synchronous Data Transmission
After completing the synchronous transmission parameter configuration, call
wm_drv_spim_transceive_sync()
for synchronous transmission. Pass the device descriptor, SPI device parameters, transmission parameters, and timeout period in milliseconds.// Set TX data for (int i = 0; i < tx_len; i++) { tx_buf[i] = 0xAA; } wm_drv_spim_transceive_sync(spi_dev, &config, &desc, 1000);
Deinitializing SPI
If SPI is no longer needed for data transmission, call
wm_drv_spim_deinit()
to remove the driver and release the allocated resources.
SPI Asynchronous Transmission
Setting Transmission Parameters
When calling this interface, the API will return immediately after passing relevant parameters to the driver. The underlying transmit and receive will actively call the user-registered callback after completion.
The SPI device can communicate with the slave using SPI. The default GPIO pins for SPI are CLK: GPIO17, MISO: GPIO16, and MOSI: GPIO21. If necessary, these can be modified in the device tree.
Different slaves need to select their own CS pin. W800 provides CS GPIO as GPIO0, GPIO20, GPIO30, GPIO39.
CS pins and other parameters are all in the
wm_dt_hw_spim_dev_cfg_t
structure.Use synchronous transmission by calling
wm_drv_spim_transceive_sync()
and passing thewm_dt_hw_spim_dev_cfg_t
andtransceive_t
structures.1. SPI Device Parameter Configuration
The transmission frequency, mode, and pins of SPI can be configured in the
wm_dt_hw_spim_dev_cfg_t
structure. Example:wm_device_t *spi_dev; spi_dev = wm_drv_spim_init("spi"); wm_dt_hw_spim_dev_cfg_t config = { .freq = 2, // 2M clock .mode = 0, .pin_cs = { .pin_num = WM_GPIO_NUM_20, .pin_mux = WM_GPIO_IOMUX_FUN5, }, };2. SPI Chip Select Pin Configuration
SPI transmission pins need to be configured separately, set to floating output mode as chip select pins, active low. Example:
// SPI GPIO config wm_drv_gpio_iomux_func_sel(config.pin_cs.pin_num, WM_GPIO_IOMUX_FUN5); wm_drv_gpio_set_pullmode(config.pin_cs.pin_num, WM_GPIO_FLOAT); wm_drv_gpio_set_dir(config.pin_cs.pin_num, WM_GPIO_DIR_OUTPUT); wm_drv_gpio_data_set(config.pin_cs.pin_num);3. SPI Transmission Parameter Configuration
The data sent and transmitted by SPI need to set tx_buffer and rx_buffer. The data to be sent is stored in tx_buffer, and the received data is stored in rx_buffer.
Supports non-empty tx buffer and rx buffer, simultaneous transmission and reception.
Supports empty tx buffer and non-empty rx buffer, only receive without sending data.
Supports non-empty tx buffer and empty rx buffer, only send without receiving data.
Example configuration:
uint32_t tx_len = 8; uint8_t *tx_buf = NULL; uint32_t rx_len = 8; uint8_t *rx_buf = NULL; tx_buf = malloc(tx_len); rx_buf = malloc(rx_len); transceive_t desc = { .tx_buf = tx_buf, .tx_len = tx_len, .rx_buf = rx_buf, .rx_len = rx_len, };4. Configuring SPI Callback Function
After asynchronous transmission ends, the callback function will be called. This function will pass an integer
result
and user datadata
. The returned data type iswm_spim_callback_t
. Example:void example_spim_async_callback(int result, void *data) { printf("SPI callback: transmit result: %d\n", result); }
Starting Asynchronous Data Transmission
After completing the asynchronous transmission parameter configuration, call
wm_drv_spim_transceive_async()
for asynchronous transmission. Pass the device descriptor, SPI device parameters, transmission parameters, callback function, and user data.// Set TX data for (int i = 0; i < tx_len; i++) { tx_buf[i] = 0xAA; } wm_drv_spim_transceive_async(spi_dev, &config, &desc, example_spim_async_callback, NULL);
Deinitializing SPI
If SPI is no longer needed for data transmission, call
wm_drv_spim_deinit()
to remove the driver and release the allocated resources.
Notes
Note
Align the starting address of the send and receive to 4 bytes, and align the length to 4 bytes for optimal SPI efficiency.
It is best if the sending length is not less than the receiving length, otherwise, the receiver might receive some invalid data.
Supports sending-only or receiving-only.
There is no limit to the sending or receiving length.
Application Example
For basic SPI usage examples, refer to examples/peripheral/spi_master
API Reference
For related SPI APIs, refer to: