SPI Development Guide_Rev1.0

中文

Revision History

Version

Date

Author

Revision Content

Rev1.0

23-09-11

TL

Initial document creation

Rev1.1

24-03-25

SXX

Changed document name

Rev1.2

25-01-14

YMX

1. Added reference pin multiplexing table description for different modules supporting SPI
2. Removed all function links to resolve DingTalk to Feishu link issues
3. Deleted complete code in the last chapter, sample code is subject to SDK

Rev1.3

25-04-18

Zhang Hao

Added common issues section

Rev1.4

26-04-22

ZXQ

Modified according to review

1 Introduction

1.1 Document Introduction

This document introduces the LTE-EC71X SPI interface APIs. The API interfaces are declared in the file: components/kernel/lierda_api/liot_spi/liot_spi.h.

The LTE-EC71X series modules support up to 2 SPI channels. For SPI support on different modules, please refer to the corresponding “Pin Multiplexing Table”.

1.2 SPI Bus Principle Introduction

Serial Peripheral Interface (SPI) is a synchronous serial communication interface used for full-duplex, high-speed data transmission between microcontrollers and peripheral devices.

The LTE-EC71X series modules support up to 2 SPI buses (SPI0 and SPI1), each SPI supports the following functional features:

Main Functional Features:

  1. Full-duplex synchronous communication: Supports simultaneous sending and receiving of data

  2. Master-slave mode: Supports master-slave mode operation

  3. Multi-slave support: Each SPI supports up to 2 chip selects (CS0, CS1)

  4. Configurable clock frequency: Supports multiple clock frequencies: 812.5KHz, 1.625MHz, 3.25MHz, 6.5MHz, 13MHz

  5. Flexible data frame format: Data frame size is configurable (4~16 bits, default 8 bits)

  6. Multiple transmission modes: Supports polling, interrupt, and DMA transmission methods

  7. Configurable clock polarity and phase: Supports 4 SPI working modes (CPOL/CPHA combinations)

  8. MSB first transmission: Data is always transmitted with the Most Significant Bit (MSB) first

Communication Interfaces:

  • MOSI: Master Output, Slave Input

  • MISO: Master Input, Slave Output

  • SCLK: Serial Clock, generated by master device

  • CS: Chip Select signal, active low (configurable)

2 API Function Overview

Function

Description

liot_spi_init()

This function is used to initialize SPI

liot_spi_init_ext()

This function is used to initialize SPI (configure SPI bus parameters)

liot_spi_write_read()

This function is used to simultaneously send and receive data through SPI

liot_spi_read()

This function is used to receive data through SPI

liot_spi_write()

This function is used to send data through SPI

liot_spi_release()

This function is used to release SPI bus

3 Type Descriptions

3.1 liot_errcode_spi_e

SPI API execution result error codes.

  1. Definition

typedef enum
{
    LIOT_SPI_SET_CB_ERR = -1,
    LIOT_SPI_SUCCESS    = 0,
    LIOT_SPI_ERROR = 1 | (LIOT_COMPONENT_BSP_SPI << 16), // Other SPI bus errors
    LIOT_SPI_PARAM_TYPE_ERROR,                           // Parameter type error
    LIOT_SPI_PARAM_DATA_ERROR,                           // Parameter data error
    LIOT_SPI_PARAM_ACQUIRE_ERROR,                        // Parameter cannot be acquired
    LIOT_SPI_PARAM_NULL_ERROR,                           // Parameter NULL error
    LIOT_SPI_DEV_NOT_ACQUIRE_ERROR,                      // Cannot acquire SPI bus
    LIOT_SPI_PARAM_LENGTH_ERROR,                         // Parameter length error
    LIOT_SPI_MALLOC_MEM_ERROR,                           // Memory allocation error
    LIOT_SPI_ADDR_ALIGNED_ERROR,                         // Address not 4-byte aligned
    LIOT_SPI_MUTEX_CREATE_ERROR,                         // Mutex creation failed
    LIOT_SPI_MUTEX_LOCK_ERROR,                           // Mutex lock timeout
    LIOT_SPI_UNKNOWN_ERROR,
} liot_errcode_spi_e;
  1. Parameters

  • LIOT_SPI_SET_CB_ERR: Failed to set callback.

  • LIOT_SPI_SUCCESS: Function executed successfully.

  • LIOT_SPI_ERROR: Function execution failed.

  • LIOT_SPI_PARAM_TYPE_ERROR: Parameter type error.

  • LIOT_SPI_PARAM_DATA_ERROR: Parameter data error.

  • LIOT_SPI_PARAM_ACQUIRE_ERROR: Parameter cannot be acquired.

  • LIOT_SPI_PARAM_NULL_ERROR: Pointer parameter is NULL.

  • LIOT_SPI_DEV_NOT_ACQUIRE_ERROR: Cannot acquire SPI bus.

  • LIOT_SPI_PARAM_LENGTH_ERROR: Parameter length error.

  • LIOT_SPI_MALLOC_MEM_ERROR: Memory allocation error.

  • LIOT_SPI_ADDR_ALIGNED_ERROR: Address not 4-byte aligned (this error usually occurs in DMA transmission mode)

  • LIOT_SPI_MUTEX_CREATE_ERROR: Mutex creation failed.

  • LIOT_SPI_MUTEX_LOCK_ERROR: Mutex lock timeout.

  • LIOT_SPI_UNKNOWN_ERROR: Unknown error.

3.2 liot_spi_config_s

SPI bus parameter configuration structure is defined as follows:

  1. Definition

typedef struct{
    liot_spi_input_mode_e input_mode;
    liot_spi_port_e port;
    unsigned int framesize;
    liot_spi_clk_e spiclk;
    liot_spi_cs_pol_e cs_polarity0;
    liot_spi_cs_pol_e cs_polarity1;
    liot_spi_cpol_pol_e cpol;
    liot_spi_cpha_pol_e cpha;
    liot_spi_input_sel_e input_sel;
    liot_spi_transfer_mode_e transmode;
    liot_spi_cs_sel_e cs;
    liot_spi_clk_delay_e clk_delay;
    liot_spi_device_mode_e device_mode;
    liot_spi_data_msb_lsb_e data_msb_lsb;
    liot_spi_irq_callback irq_callback;
} liot_spi_config_s;
  1. Parameters

Type

Parameter

Description

liot_spi_input_mode_e

input_mode

SPI input function

liot_spi_port_e

port

SPI bus number, only supports LIOT_SPI_PORT0 and LIOT_SPI_PORT1

unsigned int

framesize

Data frame size. Range: 4~16; Default: 8; Unit: bit

liot_spi_clk_e

spiclk

SPI clock frequency

liot_spi_cs_pol_e

cs_polarity0

CS0 pin level

liot_spi_cs_pol_e

cs_polarity1

CS1 pin level

liot_spi_cpol_pol_e

cpol

Clock polarity

liot_spi_cpha_pol_e

cpha

Clock phase

liot_spi_input_sel_e

input_sel

Data input pin

liot_spi_transfer_mode_e

transmode

SPI transmission mode

liot_spi_cs_sel_e

cs

CS pin

liot_spi_clk_delay_e

clk_delay

MISO delay sampling

liot_spi_device_mode_e

device_mode

Master-slave mode and master-slave simplex mode selection

liot_spi_data_msb_lsb_e

data_msb_lsb

msb first or lsb first

liot_spi_irq_callback

irq_callback

SPI transfer completion callback function

3.3 liot_spi_input_mode_e

SPI input function enumeration is defined as follows:

  1. Definition

typedef enum{
    LIOT_SPI_INPUT_FALSE, // SPI does not allow input (read)
    LIOT_SPI_INPUT_TRUE,  // SPI allows input (read)
} liot_spi_input_mode_e;
  1. Parameters

  • LIOT_SPI_INPUT_FALSE: Disable SPI input (read) function.

  • LIOT_SPI_INPUT_TRUE: Enable SPI input (read) function.

3.4 liot_spi_port_e

SPI bus number enumeration is defined as follows:

  1. Definition

typedef enum{
    LIOT_SPI_PORT0, // SPI0 bus
    LIOT_SPI_PORT1, // SPI1 bus
} liot_spi_port_e;
  1. Parameters

  • LIOT_SPI_PORT0: SPI0 bus.

  • LIOT_SPI_PORT1: SPI1 bus.

3.5 liot_spi_clk_e

SPI clock frequency enumeration is defined as follows:

  1. Definition

typedef enum{
    LIOT_SPI_CLK_INVALID  = -1,       // Invalid clock selection
    LIOT_SPI_CLK_812_5KHZ = 812500,   // Clock: 812.5K
    LIOT_SPI_CLK_1_625MHZ = 1625000,  // Clock: 1.625M
    LIOT_SPI_CLK_3_25MHZ  = 3250000,  // Clock: 3.125M
    LIOT_SPI_CLK_6_5MHZ   = 6500000,  // Clock: 6.5M
    LIOT_SPI_CLK_13MHZ    = 13000000, // Clock: 13M
} liot_spi_clk_e;
  1. Parameters

  • LIOT_SPI_CLK_INVALID: Invalid parameter.

  • LIOT_SPI_CLK_812_5KHZ: Clock frequency is 812.5 kHz.

  • LIOT_SPI_CLK_1_625MHZ: Clock frequency is 1.625 MHz.

  • LIOT_SPI_CLK_3_25MHZ: Clock frequency is 3.25 MHz.

  • LIOT_SPI_CLK_6_5MHZ: Clock frequency is 6.5 MHz.

  • LIOT_SPI_CLK_13MHZ: Clock frequency is 13 MHz.

Note: These enumeration values are just some commonly used clock frequencies. Others are also supported. You can directly configure the corresponding values, such as 10k (10000), 80k (80000), etc.

3.6 liot_spi_cs_pol_e

CS pin level enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_CS_ACTIVE_HIGH, // During SPI bus operation, CS pin is high
        LIOT_SPI_CS_ACTIVE_LOW,  // During SPI bus operation, CS pin is low
    } liot_spi_cs_pol_e;
  1. Parameters

  • LIOT_SPI_CS_ACTIVE_HIGH: During SPI bus operation, CS pin is high.

  • LIOT_SPI_CS_ACTIVE_LOW: During SPI bus operation, CS pin is low.

3.7 liot_spi_cpol_pol_e

Clock polarity enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_CPOL_LOW = 0, // When SPI is disabled, CLK line is low level, first edge is rising edge
        LIOT_SPI_CPOL_HIGH,    // When SPI is disabled, CLK line is high level, first edge is falling edge
    } liot_spi_cpol_pol_e;
  1. Parameters

  • LIOT_SPI_CPOL_LOW: When SPI is disabled, CLK line is low level, first edge is rising edge.

  • LIOT_SPI_CPOL_HIGH: When SPI is disabled, CLK line is high level, first edge is falling edge.

3.8 liot_spi_cpha_pol_e

Clock phase enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_CPHA_1Edge, // Sample on first edge
        LIOT_SPI_CPHA_2Edge,  // Sample on second edge
    } liot_spi_cpha_pol_e;
  1. Parameters

LIOT_SPI_CPHA_1Edge: Data sampling starts from the first clock edge.

LIOT_SPI_CPHA_2Edge: Data sampling starts from the second clock edge.

3.9 liot_spi_input_sel_e

Data input pin enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_DI_0 = 0, // Select DI0 as data input pin, not use now
        LIOT_SPI_DI_1,     // Select DI1 as data input pin
        LIOT_SPI_DI_2,     // Select DI2 as data input pin, not use now
    } liot_spi_input_sel_e;
  1. Parameters

LIOT_SPI_DI_0: DI0 is data input pin (currently not supported)

LIOT_SPI_DI_1: DI1 is data input pin

LIOT_SPI_DI_2: DI2 is data input pin (currently not supported)

Note: MISO pin currently does not support configuration, use default DI1.

3.10 liot_spi_transfer_mode_e

SPI transmission mode enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_DIRECT_POLLING = 0, // FIFO read/write, polling wait
        LIOT_SPI_DIRECT_IRQ,         // FIFO read/write, interrupt notification
        LIOT_SPI_DMA_IRQ,            // DMA read/write, interrupt notification
    } liot_spi_transfer_mode_e;
  1. Parameters

LIOT_SPI_DIRECT_POLLING: FIFO read/write, polling wait.

LIOT_SPI_DIRECT_IRQ: FIFO read/write, interrupt notification.

LIOT_SPI_DMA_IRQ: DMA read/write, interrupt notification.

3.11 liot_spi_cs_sel_e

CS pin enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_CS0 = 0, // Select cs0 as SPI chip select CS pin
        LIOT_SPI_CS1,     // Select cs1 as SPI chip select CS pin
        LIOT_SPI_CS2,     // Select cs2 as SPI chip select CS pin, not use now
        LIOT_SPI_CS3,     // Select cs3 as SPI chip select CS pin, not use now
    } liot_spi_cs_sel_e;
  1. Parameters

LIOT_SPI_CS0: CS0 is SPI’s CS pin.

LIOT_SPI_CS1: CS1 is SPI’s CS pin.

LIOT_SPI_CS2: CS2 is SPI’s CS pin (currently not supported).

LIOT_SPI_CS3: CS3 is SPI’s CS pin (currently not supported).

3.12 liot_spi_clk_delay_e

MISO delay sampling enumeration is defined as follows:

  1. Declaration

typedef enum{
        LIOT_SPI_CLK_DELAY_0 = 0,  // No delay, default state
        LIOT_SPI_CLK_DELAY_1,      // MISO delay one edge sampling
    } liot_spi_clk_delay_e;
  1. Parameters

LIOT_SPI_CLK_DELAY_0: MISO no delay sampling.

LIOT_SPI_CLK_DELAY_1: MISO delay one clock edge sampling.

3.13 liot_spi_device_mode_e

Device mode enumeration is defined as follows:

  1. Declaration

typedef enum
    {
        LIOT_SPI_DEVICE_MODE_INVALID = 0,
        LIOT_SPI_DEVICE_MODE_MASTER, // SPI master mode, full duplex
        LIOT_SPI_DEVICE_MODE_SLAVE,  // SPI slave mode, full duplex
        LIOT_SPI_DEVICE_MODE_MASTER_SIMPLEX, // SPI master mode, half duplex, shared MOSI for transmit/receive
        LIOT_SPI_DEVICE_MODE_SLAVE_SIMPLEX,  // SPI slave mode, half duplex, shared MISO for transmit/receive
    } liot_spi_device_mode_e;
  1. Parameters

  • LIOT_SPI_DEVICE_MODE_INVALID: Invalid mode

  • LIOT_SPI_DEVICE_MODE_MASTER: Master mode

  • LIOT_SPI_DEVICE_MODE_SLAVE: Slave mode

  • LIOT_SPI_DEVICE_MODE_MASTER_SIMPLEX: Master mode, half duplex, shared MOSI for transmit/receive

  • LIOT_SPI_DEVICE_MODE_SLAVE_SIMPLEX: Slave mode, half duplex, shared MISO for transmit/receive

3.14 liot_spi_data_msb_lsb_e

MSB/LSB enumeration is defined as follows:

  1. Declaration

typedef enum
    {
        LIOT_SPI_DATA_MSB_LSB = 0,  // MSB first
        LIOT_SPI_DATA_LSB_MSB,      // LSB first
    } liot_spi_data_msb_lsb_e;
  1. Parameters

  • LIOT_SPI_DATA_MSB_LSB: MSB first

  • LIOT_SPI_DATA_LSB_MSB: LSB first

3.15 liot_spi_irq_callback

Callback type is defined as follows:

  1. Declaration

typedef void (*liot_spi_irq_callback)(uint32_t event);
  1. Parameters

This is a function pointer. After SPI transfer is completed, this function will be called back in the interrupt.

4 API Function Details

4.1 liot_spi_init

This function is used to initialize SPI and should be called before using other SPI APIs. Before calling this function, you need to set the specified GPIO pin to SPI function through liot_pin_set_func (refer to demo call for details).

The default configuration of liot_spi_config_s is as follows:

struct liot_spi_config_s defaultCfg{
    .input_mode = LIOT_SPI_INPUT_TRUE,       // Enable read function
    .framesize = 8,                          // Number of bits per transmission
    .cs_polarity0 = LIOT_SPI_CS_ACTIVE_LOW,  // cs0 active low
    .cs_polarity1 = LIOT_SPI_CS_ACTIVE_LOW,  // cs1 active low
    .cpol = LIOT_SPI_CPOL_LOW,               // SPI clk initial level is low
    .cpha = LIOT_SPI_CPHA_1Edge,             // Sample on first spi clk edge, rising edge
    .input_sel = LIOT_SPI_DI_1,              // MISO uses default pin, cannot configure others
    .cs = LIOT_SPI_CS0,                      // Use CS0
    .clk_delay = LIOT_SPI_CLK_DELAY_0        // No delay for sampling
};
  1. Declaration

liot_errcode_spi_e liot_spi_init(liot_spi_port_e port,
                                   liot_spi_transfer_mode_e transmode,
                                   liot_spi_clk_e spiclk);
  1. Parameters

    port: [In] SPI bus number.

    transmode: [In] SPI transmission mode.

    spiclk: [In] SPI clock frequency.

  2. Return Value

  • liot_errcode_spi_e: Execution result code, see 3.1 for reference.

4.2 liot_spi_init_ext

This function is used to initialize SPI (configure SPI bus parameters) and should be called before using other SPI APIs.

This function can be used to select SPI bus, configure SPI input function, clock frequency, data frame size, CS pin and pin level, clock polarity, clock phase, data input pin, transmission mode, and MISO delay sampling. Before calling this function, you need to set related GPIO pins to SPI function through liot_pin_set_func().

  1. Declaration

liot_errcode_spi_e liot_spi_init_ext(liot_spi_config_s spi_config);
  1. Parameters

    spi_config: [In] SPI bus parameter configuration.

  2. Return Value

liot_errcode_spi_e: Execution result code, see 3.1 for reference.

Note: There are two initialization functions, liot_spi_init and liot_spi_init_ext. The difference is that liot_spi_init can only configure port, transmission mode, and clk;

While liot_spi_init_ext function can configure all SPI-related settings through the liot_spi_config_s structure.

4.3 liot_spi_write_read

This function is used to simultaneously send and receive data through SPI (full-duplex mode, simultaneous send and receive, must have send buffer and receive buffer).

  1. Declaration

liot_errcode_spi_e liot_spi_write_read(liot_spi_port_e port,
                                        unsigned char *inbuf,
                                        unsigned char *outbuf,
                                        unsigned int len);
  1. Parameters

    port: [In] SPI bus number.

    inbuf: [Out] Received data.

    outbuf: [In] Data to send.

    len: [In] Length of data to send and receive.

  2. Return Value

liot_errcode_spi_e: Execution result code, see 3.1 for reference.

4.4 liot_spi_read

This function is used to receive data through SPI.

  1. Declaration

liot_errcode_spi_e liot_spi_read(liot_spi_port_e port,
                          unsigned char *buf,
                          unsigned int len);
  1. Parameters

    port: [in] SPI bus number.

    buf: [Out] Received data.

    len: [In] Length of received data. Unit: bytes.

  2. Return Value

liot_errcode_spi_e: Execution result code, see 3.1 for reference.

4.5 liot_spi_write

This function is used to send data through SPI.

  1. Declaration

liot_errcode_spi_e liot_spi_write(liot_spi_port_e port,
                          unsigned char *buf,
                          unsigned int len);
  1. Parameters

    port: [In] SPI bus number.

    buf: [In] Data to send.

    len: [In] Length of data to send. Unit: bytes.

  2. Return Value

liot_errcode_spi_e: Execution result code, see 3.1 for reference.

4.6 liot_spi_release

This function is used to release SPI bus.

  1. Declaration

liot_errcode_spi_e liot_spi_release(liot_spi_port_e port);
  1. Parameters

    port: [In] SPI bus number.

  2. Return Value

liot_errcode_spi_e: Execution result code, see 3.1 for reference.

5 Code Example

5.1 Sample Code Reference

Refer to LSDK/examples/demo/src/demo_spi.c file.

#include "lierda_app_main.h"
#include "liot_gpio2.h"
#include "liot_os.h"
#include "liot_spi.h"
#include <string.h>

// Define SPI pin configurations for different chips
#define LIOT_CUR_SPI0_MOSI_PIN_MUN (85)
#define LIOT_CUR_SPI0_MISO_PIN_MUN (84)
#define LIOT_CUR_SPI0_CLK_PIN_MUN  (86)
#define LIOT_CUR_SPI0_CS0_PIN_MUN  (83)
#define LIOT_CUR_SPI_PIN_FUNC      (1)


/** @brief Switch for testing SPI master mode, 1 for enabled, 0 for disabled */
#define SPI_MASTER_DEMO 0

/** @brief Switch for testing SPI slave mode, 1 for enabled, 0 for disabled */
#define SPI_SLAVE_DEMO  1

/** @brief Clock speed for SPI testing */
#define SPI_DEMO_CLK_SPEED          8000000U

/** @brief Length of test data */
#define TEST_DATA_LEN              (128)

/** @brief Test data buffer for writing */
unsigned char demo_data_w[TEST_DATA_LEN] = {0};

/** @brief Test data buffer for reading */
unsigned char demo_data_r[TEST_DATA_LEN] = {0};

/**
 * @brief Transfer completion flag in SPI slave mode
 */
uint8_t isTransferDone = 0;

/**
 * @brief Interrupt callback function in SPI slave mode
 *        This function is called when the SPI transfer is completed or an error occurs.
 * @param event Event flag indicating the transfer status
 */
void liot_spi_demo_callback(uint32_t event)
{
    uint8_t i = 0;
    if(event & LIOT_SPI_EVENT_TRANSFER_COMPLETE)
    {
        isTransferDone = 1;
    }
    else
    {
        liot_trace("spi_demo_callback error %d", event);
        for(i = 0; i < TEST_DATA_LEN; i++)
        {
            liot_trace("[%d]Input:0x%x", i, demo_data_r[i]);
        }
    }
}

/**
 * @brief Thread function for SPI master mode testing
 *        This function initializes the SPI master mode and performs data write and read operations in a loop.
 * @param argv Thread parameters
 */
#if SPI_MASTER_DEMO == 1
void liot_spi_demo_thread(void *argv)
{
    unsigned char i = 1;

    // Configuration structure for SPI settings, used to initialize the SPI master mode.
    liot_spi_config_s cfg = {
        .input_mode = LIOT_SPI_INPUT_TRUE,
        .port = LIOT_SPI_PORT0,
        .framesize = 8,
        .spiclk = SPI_DEMO_CLK_SPEED,
        .cs_polarity0 = LIOT_SPI_CS_ACTIVE_LOW,
        .cs_polarity1 = LIOT_SPI_CS_ACTIVE_LOW,
        .cpol = LIOT_SPI_CPOL_HIGH,
        .cpha = LIOT_SPI_CPHA_2Edge,
        .input_sel = LIOT_SPI_DI_1,
        .transmode = LIOT_SPI_DIRECT_POLLING,
        .cs = LIOT_SPI_CS0,
        .clk_delay = LIOT_SPI_CLK_DELAY_0,
        .device_mode = LIOT_SPI_DEVICE_MODE_MASTER,
        .data_msb_lsb = LIOT_SPI_DATA_MSB_LSB,
        .irq_callback = NULL,
    };

    Liot_SetPinFunc(LIOT_CUR_SPI0_MOSI_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    Liot_SetPinFunc(LIOT_CUR_SPI0_MISO_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    Liot_SetPinFunc(LIOT_CUR_SPI0_CLK_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    liot_spi_init_ext(cfg);

    while (1)
    {
        liot_rtos_task_sleep_ms(5000);

        liot_trace("spi demo master running...");
        memset(demo_data_w, i++, TEST_DATA_LEN);
        memset(demo_data_r, 0, TEST_DATA_LEN);

        liot_spi_write_read(LIOT_SPI_PORT0, demo_data_r, demo_data_w, TEST_DATA_LEN);

        liot_trace("Output:0x%x,0x%x,0x%x", demo_data_w[0], demo_data_w[TEST_DATA_LEN/2], demo_data_w[TEST_DATA_LEN-1]);
        liot_trace("Input :0x%x,0x%x,0x%x", demo_data_r[0], demo_data_r[TEST_DATA_LEN/2], demo_data_r[TEST_DATA_LEN-1]);
    }
    liot_rtos_task_delete(NULL);
}
#elif SPI_SLAVE_DEMO == 1

/**
 * @brief Thread function for SPI slave mode testing
 *        This function initializes the SPI slave mode and performs data read and write operations in a loop,
 *        waiting for the transfer to complete.
 *
 * @param argv Thread parameters
 */
void liot_spi_demo_thread(void *argv)
{
    unsigned char i = 1;
    uint32_t timeOut_ms = 5000;

    // Configuration structure for SPI settings, used to initialize the SPI slave mode.
    liot_spi_config_s cfg = {
        .input_mode = LIOT_SPI_INPUT_TRUE,
        .port = LIOT_SPI_PORT0,
        .framesize = 8,
        .spiclk = SPI_DEMO_CLK_SPEED,
        .cs_polarity0 = LIOT_SPI_CS_ACTIVE_LOW,
        .cs_polarity1 = LIOT_SPI_CS_ACTIVE_LOW,
        .cpol = LIOT_SPI_CPOL_HIGH,
        .cpha = LIOT_SPI_CPHA_2Edge,
        .input_sel = LIOT_SPI_DI_1,
        .transmode = LIOT_SPI_DMA_IRQ,
        .cs = LIOT_SPI_CS0,
        .clk_delay = LIOT_SPI_CLK_DELAY_0,
        .device_mode = LIOT_SPI_DEVICE_MODE_SLAVE,
        .data_msb_lsb = LIOT_SPI_DATA_MSB_LSB,
        .irq_callback = liot_spi_demo_callback,
    };

    Liot_SetPinFunc(LIOT_CUR_SPI0_MOSI_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    Liot_SetPinFunc(LIOT_CUR_SPI0_MISO_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    Liot_SetPinFunc(LIOT_CUR_SPI0_CLK_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    Liot_SetPinFunc(LIOT_CUR_SPI0_CS0_PIN_MUN, LIOT_CUR_SPI_PIN_FUNC);
    liot_spi_init_ext(cfg);

    while (1)
    {
        liot_trace("spi demo slave running...");
        memset(demo_data_w, i++, TEST_DATA_LEN);
        memset(demo_data_r, 0, TEST_DATA_LEN);
        timeOut_ms = 5000;

        liot_spi_write_read(LIOT_SPI_PORT0, demo_data_r, demo_data_w, TEST_DATA_LEN);

        do {
            liot_rtos_task_sleep_ms(1);
        } while ((isTransferDone == false) && --timeOut_ms);

        if(timeOut_ms == 0)
            liot_trace("Slave receive failed for timeout\n");

        liot_trace("Output:0x%x,0x%x,0x%x", demo_data_w[0], demo_data_w[TEST_DATA_LEN/2], demo_data_w[TEST_DATA_LEN-1]);
        liot_trace("Input :0x%x,0x%x,0x%x", demo_data_r[0], demo_data_r[TEST_DATA_LEN/2], demo_data_r[TEST_DATA_LEN-1]);
    }
    liot_rtos_task_delete(NULL);
}
#endif

The sample code has two test modes: master and slave. Choose according to your needs. We enable the #define SPI_MASTER_DEMO macro to test in master mode.

Short-circuit the module’s MISO and MOSI, use logic analyzer and log tools to capture waveforms and logs. The execution results are as follows:

_images/spi-guide/image_1.png
_images/spi-guide/image_2.png

As shown in the figure above, the log prints data 0xab consistent with MOSI and MISO output, indicating successful SPI communication.

6 Common Issues

6.1 Which Protocol Does EC718’s CSPI Frame Structure Follow?

MTK protocol.

6.2 Does SPI Support MSB or LSB?

Only supports MSB.