Skip to main content

tkl_spi | SPI Driver

Brief Description

SPI (Serial Peripheral Interface) is a high-speed, full-duplex, synchronous communication bus. SPI operates in a master-slave mode, typically with one master device and one or more slave devices.

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

  • MISO: Master device data input, slave device data output;
  • MOSI: Master device data output, slave device data input;
  • SCK: Clock signal, generated by the master device;
  • CS: Slave device enable signal, controlled by the master device. This signal can be part of the SPI peripheral or implemented with a GPIO pin.

The typical wiring method for the SPI bus is as follows:

image-20220411140500420
image-20220411140500420

The SPI bus supports four working modes, depending on the combination of the serial synchronous clock polarity (CPOL) and the serial synchronous clock phase (CPHA).

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

The timing diagrams for the four working modes are described as follows:

  • Mode 0: CPOL=0, CPHA=0. The SCK serial clock line is idle at a low level, and data is sampled on the rising edge of the SCK clock and switched on the falling edge.
  • Mode 1: CPOL=0, CPHA=1. The SCK serial clock line is idle at a low level, and data is sampled on the falling edge of the SCK clock and switched on the rising edge.
  • Mode 2: CPOL=1, CPHA=0. The SCK serial clock line is idle at a high level, and data is sampled on the falling edge of the SCK clock and switched on the rising edge.
  • Mode 3: CPOL=1, CPHA=1. The SCK serial clock line is idle at a high level, and data is sampled on the rising edge of the SCK clock and switched 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);
  • Function Description:

    • Initializes the corresponding SPI instance via the port number and basic configuration, returning the initialization result.
  • Parameters:

    • port: Port number.

    • cfg: SPI basic 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;
      uint32_t freq_hz;
      uint32_t spi_dma_flags; /*!< SPI dma format , 1 use dma */
      } TUYA_SPI_BASE_CFG_T;

      TUYA_SPI_ROLE_E:

      NameDefinitionRemarks
      TUYA_SPI_ROLE_INACTIVESPI inactive
      TUYA_SPI_ROLE_MASTERSPI full-duplex master mode
      TUYA_SPI_ROLE_SLAVESPI full-duplex slave mode
      TUYA_SPI_ROLE_MASTER_SIMPLEXSPI half-duplex master mode
      TUYA_SPI_ROLE_SLAVE_SIMPLEXSPI half-duplex slave mode

      TUYA_SPI_MODE_E:

      NameDefinitionRemarks
      TUYA_SPI_MODE0CPOL = 0, CPHA = 0
      TUYA_SPI_MODE1CPOL = 0, CPHA = 1
      TUYA_SPI_MODE2CPOL = 1, CPHA = 0
      TUYA_SPI_MODE3CPOL = 1, CPHA = 1

      TUYA_SPI_TYPE_E:

      NameDefinitionRemarks
      TUYA_SPI_AUTO_TYPESS pin mode, hardware auto-configSS: slave select, corresponds to CS pin
      TUYA_SPI_SOFT_TYPESS pin mode, software manual-config
      TUYA_SPI_SOFT_ONE_WIRE_TYPEThree-wire mode, SS pin invalid

      TUYA_SPI_DATABITS_E:

      NameDefinitionRemarks
      TUYA_SPI_DATA_BIT88-bit data mode
      TUYA_SPI_DATA_BIT1616-bit data mode

      TUYA_SPI_BIT_ORDER_E:

      NameDefinitionRemarks
      TUYA_SPI_ORDER_MSB2LSBHigh bit (MSB) first, low bit (LSB) last
      TUYA_SPI_ORDER_LSB2MSBLow bit (LSB) first, high bit (MSB) last
  • Return Value:

    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_deinit

OPERATE_RET tkl_spi_deinit(TUYA_SPI_NUM_E port);
  • Function Description:
    • Deinitializes the SPI instance. This interface will stop the SPI instance and release related software and hardware resources.
  • Parameters:
    • port: Port number.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_send

OPERATE_RET tkl_spi_send(TUYA_SPI_NUM_E port, void *data, uint16_t size);
  • Function Description:
    • SPI starts data transmission.
  • Parameters:
    • port: Port number.
    • data: Buffer address of data to be sent.
    • size: Length of data to be sent.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_recv

OPERATE_RET tkl_spi_recv(TUYA_SPI_NUM_E port, void *data, uint16_t size);
  • Function Description:
    • SPI starts data reception.
  • Parameters:
    • port: Port number.
    • data: Buffer address of data to be received.
    • size: Length of data to be received.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_transfer

OPERATE_RET tkl_spi_transfer(TUYA_SPI_NUM_E port, void* send_buf, void* receive_buf, uint32_t length);
  • Function Description:
    • SPI starts data transfer.
  • Parameters:
    • port: Port number.
    • send_buf: Buffer address of data to be sent.
    • receive_buf: Buffer address of data to be received.
    • length: Length.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_abort_transfer

OPERATE_RET tkl_spi_abort_transfer(TUYA_SPI_NUM_E port);
  • Function Description:
    • SPI aborts data transfer or aborts data sending (receiving).
  • Parameters:
    • port: Port number.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_get_status

OPERATE_RET tkl_spi_get_status(TUYA_SPI_NUM_E port, TUYA_SPI_STATUS_T *status);
  • Function Description:
    • Gets the SPI status at the current time.
  • Parameters:
    • port: Port number.
  • Return Value:
    • The structure of the SPI status, the definition of the SPI status can be found in the definition of TUYA_SPI_STATUS_T.

TUYA_SPI_STATUS_T:

NameDefinitionRemarks
busy : 1Transmission/reception busy status1 is valid
data_lost : 1Data lost1 is valid
mode_fault : 1Mode error1 is valid

tkl_spi_irq_init

OPERATE_RET tkl_spi_irq_init(TUYA_SPI_NUM_E port, TUYA_SPI_IRQ_CB cb);
  • Function Description:
    • SPI interrupt initialization.
  • Parameters:
    • port: Port number.
    • cb: Interrupt callback function.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_irq_enable

OPERATE_RET tkl_spi_irq_enable(TUYA_SPI_NUM_E port);
  • Function Description:
    • Enables SPI interrupt.
  • Parameters:
    • port: Port number.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_irq_disable

OPERATE_RET tkl_spi_irq_disable(TUYA_SPI_NUM_E port);
  • Function Description:
    • Disables SPI interrupt.
  • Parameters:
    • port: Port number.
  • Return Value:
    • OPRT_OK Success, others please refer to the file tuya_error_code.h, OS_ADAPTER_SPI definition section.

tkl_spi_get_data_count

int32_t tkl_spi_get_data_count(TUYA_SPI_NUM_E port);
  • Function Description:
    • Gets the SPI transmission byte length.
  • Parameters:
    • port: Port number.
  • Return Value:
    • Returns < 0 on error. Returns >= 0 for the byte length of the last transmission. This can be from any of the operations tkl_spi_send, tkl_spi_recv, or tkl_spi_transfer.

Examples

1. SPI 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) {
//fail
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
}
}

2. SPI Using Interrupt Example 2

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) {
//fail
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);
}
//up Transfer Complete
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);
}
// up send Complete,

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);
}
// up recv Complete,
tkl_spi_irq_disable(TUYA_SPI_NUM_0);
//uninitialize iic
ret = tkl_spi_deinit(TUYA_SPI_NUM_0);
if (ret != 0) {
//failed
}
}