This is the documentation for the latest (main) development branch. If you are looking for the documentation of previous releases, use the drop-down menu on the left and select the desired version.

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

  1. Initialization — Initialize the SPI driver.

  2. Synchronous Data Transfer — Ends the transfer when data transmission is completed or transmission times out.

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

SPI Wiring Diagram

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 the wm_device_t structure. Example:

wm_device_t *spi_dev;
spi_dev = wm_drv_spim_init("spi");

When initializing, simply pass the string "spi".

Note

  1. If SPI is already initialized, you can directly call wm_dt_get_device_by_name to get the SPI device pointer.

  2. 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 the wm_dt_hw_spim_dev_cfg_t and transceive_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 the wm_dt_hw_spim_dev_cfg_t and transceive_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 data data. The returned data type is wm_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

  1. Align the starting address of the send and receive to 4 bytes, and align the length to 4 bytes for optimal SPI efficiency.

  2. It is best if the sending length is not less than the receiving length, otherwise, the receiver might receive some invalid data.

  3. Supports sending-only or receiving-only.

  4. 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:

SPI master API Reference