SPI

Last Updated on : 2025-05-12 03:09:46download

Overview

Serial peripheral interface (SPI) is a high-speed, full-duplex, synchronous communication bus. SPI follows a controller–peripheral architecture, where a controller orchestrates communication with one or more peripheral devices.

The signal lines of an SPI controller are described as follows:

  • MISO: Data is sent from the peripheral to the controller.
  • MOSI: Data is sent from the controller to the peripheral.
  • SCK: Serial clock, generated by the controller.
  • CS: Chip select, used to enable the peripheral. This signal can be part of the SPI peripheral or implemented using a GPIO pin.

The following figure shows a typical SPI wiring.

SPI

The four operating modes supported by the SPI bus depend on the combination of clock polarity (CPOL) and clock phase (CPHA).

  • CPOL is used to determine the idle level of the SCLK clock signal. The idle level is low if CPOL is 0, and is high if CPOL is 1.
  • CPHA is used to determine the sampling time. When CPHA is 0, data is sampled on the first clock edge of each cycle and output on the second edge. When CPHA is 1, data is sampled on the second clock edge and output on the first edge.
  • The clock phase and polarity of the SPI main module and the peripheral device communicating with it should be consistent.

The timing of the four operating modes is described as follows:

  • Mode 0: CPOL = 0, CPHA = 0. The SCK line remains idle at low level. Data is sampled on the rising edge of SCK, and changes occur on the falling edge.

  • Mode 1: CPOL = 0, CPHA = 1. The SCK line remains idle at low level. Data is sampled on the falling edge of SCK, and changes occur on the rising edge.

  • Mode 2: CPOL = 1, CPHA = 0. The SCK line remains idle at high level. Data is sampled on the falling edge of SCK, and changes occur on the rising edge.

  • Mode 3: CPOL = 1, CPHA = 1. The SCK line remains idle at high level. Data is sampled on the rising edge of SCK, and changes occur on the falling edge.

API description

tkl_spi_init

OPERATE_RET tkl_spi_init(TUYA_SPI_NUM_E port, CONST TUYA_SPI_BASE_CFG_T *cfg);
  • Features:

    • Initialize the specified SPI instance using the port number and basic configuration, and return the initialization result.
  • Parameters:

    • port: The port number.
    • cfg: Basic SPI configuration.
    typedef struct {
        TUYA_SPI_ROLE_E      role;
        TUYA_SPI_MODE_E      mode;
        TUYA_SPI_TYPE_E      type;
        TUYA_SPI_DATABITS_E  databits;
        TUYA_SPI_BIT_ORDER_E bitorder;
        UINT_T               freq_hz;
        UINT_T               spi_dma_flags; /*!< SPI dma format , 1 use dma */
    } TUYA_SPI_BASE_CFG_T;
    

    TUYA_SPI_ROLE_E

    Name Definition
    TUYA_SPI_ROLE_INACTIVE The SPI is idle.
    TUYA_SPI_ROLE_MASTER The SPI is in full-duplex controller mode.
    TUYA_SPI_ROLE_SLAVE The SPI is in full-duplex peripheral mode.
    TUYA_SPI_ROLE_MASTER_SIMPLEX The SPI is in half-duplex controller mode.
    TUYA_SPI_ROLE_SLAVE_SIMPLEX The SPI is in half-duplex peripheral mode.

    TUYA_SPI_MODE_E

    Name Definition
    TUYA_SPI_MODE0 CPOL = 0, CPHA = 0
    TUYA_SPI_MODE1 CPOL = 0, CPHA = 1
    TUYA_SPI_MODE2 CPOL = 1, CPHA = 0
    TUYA_SPI_MODE3 CPOL = 1, CPHA = 1

    TUYA_SPI_TYPE_E

    Name Definition Remarks
    TUYA_SPI_AUTO_TYPE SS pin mode, automatically configured by hardware Slave select (SS): corresponds to the chip select pin
    TUYA_SPI_SOFT_TYPE SS pin mode, manually configured by software -
    TUYA_SPI_SOFT_ONE_WIRE_TYPE Three-wire mode, with SS pin invalid -

    TUYA_SPI_DATABITS_E

    Name Definition
    TUYA_SPI_DATA_BIT8 8-bit pattern
    TUYA_SPI_DATA_BIT16 16-bit pattern

    TUYA_SPI_BIT_ORDER_E

    Name Definition
    TUYA_SPI_ORDER_MSB2LSB The most significant bit (MSB) first, and the least significant bit (LSB) last
    TUYA_SPI_ORDER_LSB2MSB The LSB first, and the MSB last
  • Return value:

    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_deinit

OPERATE_RET tkl_spi_deinit(TUYA_SPI_NUM_E port);
  • Features:
    • Deinitialize the SPI instance. This interface stops the ongoing transmission (if any) and releases the related software and hardware resources.
  • Parameters:
    • port: The port number.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_send

OPERATE_RET tkl_spi_send(TUYA_SPI_NUM_E port, VOID_T *data, UINT16_T size);
  • Features:
    • Start sending data via SPI.
  • Parameters:
    • port: The port number.
    • data: The buffer address of the data to be sent.
    • size: The size of the data to be sent.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_recv

OPERATE_RET tkl_spi_recv(TUYA_SPI_NUM_E port, VOID_T *data, UINT16_T size);
  • Features:
    • Start receiving data via SPI.
  • Parameters:
    • port: The port number.
    • data: The buffer address of the data to be received.
    • size: The size of the data to be received.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_transfer

OPERATE_RET tkl_spi_transfer(TUYA_SPI_NUM_E port, VOID_T* send_buf, VOID_T* receive_buf, UINT32_T length);
  • Features:
    • Start data transfer via SPI.
  • Parameters:
    • port: The port number.
    • send_buf: The buffer address of the data to be sent.
    • receive_buf: The buffer address of the data to be received.
    • length: The length.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_abort_transfer

OPERATE_RET tkl_spi_abort_transfer(TUYA_SPI_NUM_E port);
  • Features:
    • The SPI stops data transfer, including data sending and receiving.
  • Parameters:
    • port: The port number.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_get_status

OPERATE_RET tkl_spi_get_status(TUYA_SPI_NUM_E port, TUYA_SPI_STATUS_T *status);
  • Features:
    • Get the current status of SPI.
  • Parameters:
    • port: The port number.
  • Return value:
    • The struct of the SPI status. For the definition of SPI status, see TUYA_SPI_STATUS_T.

TUYA_SPI_STATUS_T

Name Definition Remarks
busy: 1 Busy status bit of data transfer, receiving, and sending 1: valid
data_lost: 1 Data loss 1: valid
mode_fault: 1 Mode error 1: valid

tkl_spi_irq_init

OPERATE_RET tkl_spi_irq_init(TUYA_SPI_NUM_E port, TUYA_SPI_IRQ_CB cb);
  • Features:
    • Initialize the SPI interrupt.
  • Parameters:
    • port: The port number.
    • cb: The interrupt callback.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_irq_enable

OPERATE_RET tkl_spi_irq_enable(TUYA_SPI_NUM_E port);
  • Features:
    • Enable SPI interrupts.
  • Parameters:
    • port: The port number.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_irq_disable

OPERATE_RET tkl_spi_irq_disable(TUYA_SPI_NUM_E port);
  • Features:
    • Disable SPI interrupts.
  • Parameters:
    • port: The port number.
  • Return value:
    • OPRT_OK: success. For more information, see the definitions in tuya_error_code.h > OS_ADAPTER_SPI.

tkl_spi_get_data_count

INT32_T tkl_spi_get_data_count(TUYA_SPI_NUM_E port);
  • Features:
    • Get the length in bytes transferred via SPI.
  • Parameters:
    • port: The port number.
  • Return value:
    • < 0: An error occurred.
    • ≥ 0: The length in bytes of the last transfer.
      It can be any operation of tkl_spi_send, tkl_spi_recv, and tkl_spi_transfer.

Example

Example 1

void tuya_spi_test1(void)
{
    OPERATE_RET ret;
    TUYA_SPI_BASE_CFG_T cfg;
    TUYA_SPI_STATUS_T status;
    // Receive buffer
    char rcv_buf[8];
    // Data to send
    char send_buf[8] = {0,1,2,3,4,5,6,7};

    tkl_io_pinmux_config(TUYA_IO_PIN_0, TUYA_SPI0_MISO);
    tkl_io_pinmux_config(TUYA_IO_PIN_1, TUYA_SPI0_MOSI);
    tkl_io_pinmux_config(TUYA_IO_PIN_2, TUYA_SPI0_CS);
    tkl_io_pinmux_config(TUYA_IO_PIN_3, TUYA_SPI0_CLK);

    cfg.role = TUYA_SPI_ROLE_MASTER;
    cfg.mode = TUYA_SPI_MODE0;
    cfg.type = TUYA_SPI_AUTO_TYPE;
    cfg.databits = TUYA_SPI_DATA_BIT8;
    cfg.bitorder = TUYA_SPI_ORDER_MSB2LSB;
    cfg.freq_hz = 1000000;

    ret = tkl_spi_init(TUYA_SPI_NUM_0, &cfg);
    if (ret != OPRT_OK) {
        // Failed
        return;
    }

    ret = tkl_spi_send(TUYA_SPI_NUM_0, send_buf, 8);
    if (ret < 0) {
        // Failed
    }

    tkl_spi_get_status(TUYA_SPI_NUM_0, &status);
    while (status.busy) {
        tkl_spi_get_status(TUYA_SPI_NUM_0, &status);
        tkl_system_sleep(2);
    }

    ret = tkl_spi_recv(TUYA_SPI_NUM_0, rcv_buf, 8);
    if (ret < 0) {
        // Failed
    }

    tkl_spi_get_status(TUYA_SPI_NUM_0, &status);
    while (status.busy) {
        tkl_spi_get_status(TUYA_SPI_NUM_0, &status);
        tkl_system_sleep(2);
    }
    ret = tkl_spi_transfer(TUYA_SPI_NUM_0, send_buf,rcv_buf, 6);
    if (ret < 0) {
        // Failed
    }

    tkl_spi_get_status(TUYA_SPI_NUM_0, &status);
    while (status.busy) {
        tkl_spi_get_status(TUYA_SPI_NUM_0, &status);
        tkl_system_sleep(2);
    }
    // Uninitialize iic
    ret = tkl_spi_deinit(TUYA_SPI_NUM_0);
    if (ret != 0) {
       // Failed
    }
}

Example 2 (Interrupt)

int event_flag = -1;
static void spi_event_cb(TUYA_SPI_NUM_E port, TUYA_SPI_IRQ_EVT_E event)
{
    //printf("\nspi_event_cb_fun:%d\n",event);
    event_flag = event;
}

void tuya_spi_test2(void)
{
    OPERATE_RET ret;
    TUYA_SPI_BASE_CFG_T cfg;
    TUYA_SPI_STATUS_T status;
    // Receive buffer
    char rcv_buf[6];
    // Data to send
    char send_buf[6] = {0x90,0x0,0x0,0x0,0x0,0x0};

    tkl_io_pinmux_config(TUYA_IO_PIN_0, TUYA_SPI0_MISO);
    tkl_io_pinmux_config(TUYA_IO_PIN_1, TUYA_SPI0_MOSI);
    tkl_io_pinmux_config(TUYA_IO_PIN_2, TUYA_SPI0_CS);
    tkl_io_pinmux_config(TUYA_IO_PIN_3, TUYA_SPI0_CLK);

    cfg.role = TUYA_SPI_ROLE_MASTER;
    cfg.mode = TUYA_SPI_MODE0;
    cfg.type = TUYA_SPI_AUTO_TYPE;
    cfg.databits = TUYA_SPI_DATA_BIT8;
    cfg.bitorder = TUYA_SPI_ORDER_MSB2LSB;
    cfg.freq_hz = 1000000;

    ret = tkl_spi_init(TUYA_SPI_NUM_0, &cfg);
    if (ret != OPRT_OK) {
        // Failed
        return;
    }

    tkl_spi_irq_init(TUYA_SPI_NUM_0 , spi_event_cb);
    tkl_spi_irq_enable(TUYA_SPI_NUM_0);

    event_flag = -1;
    ret = tkl_spi_transfer(TUYA_SPI_NUM_0, send_buf,rcv_buf, 6);
    if (ret < 0) {
        // Failed
    }

    while (TUYA_SPI_EVENT_TRANSFER_COMPLETE != event_flag) {
        tkl_system_sleep(2);
    }
    // Transfer completed
    event_flag = -1;
    ret = tkl_spi_send(TUYA_SPI_NUM_0, send_buf, 6);
    if (ret < 0) {
        // Failed
    }
    while (TUYA_SPI_EVENT_TX_COMPLETE != event_flag) {
        tkl_system_sleep(2);
    }
    // Sending completed

    event_flag = -1;
    ret = tkl_spi_recv(TUYA_SPI_NUM_0, rcv_buf, 6);
    if (ret < 0) {
        // Failed
    }
    while (TUYA_SPI_EVENT_RX_COMPLETE != event_flag) {
        tkl_system_sleep(2);
    }
    // Receiving completed
    tkl_spi_irq_disable(TUYA_SPI_NUM_0);
    // Uninitialize iic
    ret = tkl_spi_deinit(TUYA_SPI_NUM_0);
    if (ret != 0) {
       // Failed
    }
}