2.7. SPI

2.7.1. Introduction

Serial Peripheral Interface Bus (SPI) is a synchronous serial communication interface specification for short-range communication. The full-duplex communication mode is used between devices, which is a master-slave mode of one master and one or more slaves, and requires at least 4 wires. In fact, 3 wires are also available (when transmitting in one direction), including SDI (data input), SDO (data output), SCLK (clock), CS (chip select). The SPI devices in the BL series MCU have the following characteristics:

  • It can be used as both SPI master and SPI slave.

  • The transmit and receive channels each have a FIFO with a depth of 4 words

  • Both master and slave devices support 4 clock formats (CPOL, CPHA)

  • Both master and slave devices support 1/2/3/4 byte transmission mode

  • Flexible clock configuration, up to 40M clock

  • Configurable MSB/LSB priority transmission

  • Receive filter function

  • Timeout mechanism under slave device

  • Support polling, interrupt, DMA transfer

2.7.2. SPI Device Structure Definition

typedef struct spi_device
{
    struct device parent;
    uint8_t id;
    uint32_t clk;
    uint8_t mode;
    uint8_t direction;
    uint8_t clk_polaraity;
    uint8_t clk_phase;
    uint8_t datasize;
    uint8_t fifo_threshold;
    void* tx_dma;
    void* rx_dma;
} spi_device_t;
  • parent inherit the properties of the parent class

  • id SPI id, 0 means SPI0

  • clk SPI clock frequency

  • mode master mode or slave mode

  • direction transmission first mode

  • clk_polaraity clock polarity

  • clk_phase clock phase

  • datasize data transmission bit width

  • fifo_threshold fifo threshold, the maximum is 4

  • tx_dma additional send dma handle

  • rx_dma dditional receive dma handle

mode provides the following types

#define SPI_SLVAE_MODE                                0
#define SPI_MASTER_MODE                               1

direction provides the following types

#define SPI_LSB_BYTE0_DIRECTION_FIRST 0
#define SPI_LSB_BYTE3_DIRECTION_FIRST 1
#define SPI_MSB_BYTE0_DIRECTION_FIRST 2
#define SPI_MSB_BYTE3_DIRECTION_FIRST 3

clk_polaraity provides the following types

#define SPI_POLARITY_LOW                              0
#define SPI_POLARITY_HIGH                             1

clk_phase provides the following types

#define SPI_PHASE_1EDGE                               0
#define SPI_PHASE_2EDGE                               1

datasize provides the following types

#define SPI_DATASIZE_8BIT                            0
#define SPI_DATASIZE_16BIT                           1
#define SPI_DATASIZE_24BIT                           2
#define SPI_DATASIZE_32BIT                           3

2.7.3. SPI Device Parameter Configuration Table

Each SPI device has a parameter configuration macro, the macro definition is located in the peripheral_config.h file under the bsp/board/xxx directory, and the variable definition is located in hal_spi.c, so the user does not need to define variable. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_SPI0, SPI0_CONFIG will take effect, and the SPI0 device can be registered and used.

/*Parameter configuration macro*/
#if defined(BSP_USING_SPI0)
#ifndef SPI0_CONFIG
#define SPI0_CONFIG \
{   \
.id = 0, \
.clk = 18000000,\
.mode = SPI_MASTER_MODE, \
.direction = SPI_MSB_BYTE0_DIRECTION_FIRST, \
.clk_polaraity = SPI_POLARITY_LOW, \
.clk_phase = SPI_PHASE_1EDGE, \
.datasize = SPI_DATASIZE_8BIT, \
.fifo_threshold = 1, \
}
#endif
#endif

/*Variable definition*/
static spi_device_t spix_device[SPI_MAX_INDEX] =
{
#ifdef BSP_USING_SPI0
    SPI0_CONFIG,
#endif
};

备注

The above configuration can be modified through SPI_DEV(dev)->xxx and can only be used before calling device_open.

2.7.4. SPI Device Interface

SPI device interface follows which provided by the standard device driver management layer.

2.7.4.1. spi_register

spi_register is used to register an SPI device standard driver interface. Before registering, you need to open the macro definition of the corresponding SPI device. For example, define the macro BSP_USING_SPI0 before you can use the SPI0 device. After the registration is completed, other interfaces can be used. If no macro is defined, the SPI device cannot be used.

int spi_register(enum spi_index_type index, const char *name);
  • index device index to be registered

  • name device name to be registered

index is used to select SPI device configuration, one index corresponds to one SPI device configuration, for example, SPI0_INDEX corresponds to SPI0_CONFIG configuration, and index has the following optional types

enum spi_index_type
{
#ifdef BSP_USING_SPI0
    SPI0_INDEX,
#endif
    SPI_MAX_INDEX
};

2.7.4.2. device_open

device_open is used to open the device,this funtion calls spi_open actually.

int device_open(struct device *dev, uint16_t oflag);
  • dev device handle

  • oflag open mode

  • return error code, 0 means opening is successful, others mean errors

oflag provides the following types

#define DEVICE_OFLAG_STREAM_TX  0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX  0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX     0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX     0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX     0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX     0x020 /* The device is turned on in DMA receiving mode */

2.7.4.3. device_close

device_close is used to close the device,this funtion calls spi_close actually.

int device_close(struct device *dev);
  • dev device handle

  • return error code, 0 means closing is successful, others means error

2.7.4.4. device_control

device_control is used to control the device and modify parameters according to commands.This funtion calls spi_control actually.

int device_control(struct device *dev, int cmd, void *args);
  • dev device handle

  • cmd device control command

  • args control parameters

  • return Different control commands return different meanings.

In addition to standard control commands, SPI devices also have their own special control commands.

#define DEVICE_CTRL_SPI_CONFIG_CLOCK       0x10

args input is different depending on cmd, the list is as follows:

table1

cmd

args

description

DEVICE_CTRL_SET_INT

NULL

Enable spi device interrupt

DEVICE_CTRL_CLR_INT

NULL

Disable spi device interrupt

DEVICE_CTRL_RESUME

NULL

Resume spi device

DEVICE_CTRL_SUSPEND

NULL

Suspend spi device

DEVICE_CTRL_ATTACH_TX_DMA

NULL

Link to tx dma device

DEVICE_CTRL_ATTACH_RX_DMA

NULL

Link to rx dma device

DEVICE_CTRL_SPI_CONFIG_CLOCK

NULL

Modify SPI device clock

DEVICE_CTRL_TX_DMA_SUSPEND

NULL

Suspend spi tx dma mode

DEVICE_CTRL_RX_DMA_SUSPEND

NULL

Suspend spi rx dma mode

DEVICE_CTRL_TX_DMA_RESUME

NULL

Resume spi tx dma mode

DEVICE_CTRL_RX_DMA_RESUME

NULL

Resume spi rx dma mode

2.7.4.5. device_write

device_write is used to send data. The sending mode can be polling, interrupt, dma according to the open mode.This funtion calls spi_write actually.

int device_write(struct device *dev, uint32_t pos, const void *buffer, uint32_t size);
  • dev device handle

  • pos useless

  • buffer the buffer to be written

  • size the length to be written

  • return error code, 0 means writing is successful, others mean errors

2.7.4.6. device_read

device_read is used to receive data, and the receiving mode can be polling, interrupt, dma according to the open mode.This funtion calls spi_read actually.

int device_read(struct device *dev, uint32_t pos, void *buffer, uint32_t size);
  • dev device handle

  • pos useless

  • buffer the buffer to be read

  • size the length to be read

  • return error code, 0 means successful reading, others mean errors

2.7.4.7. device_set_callback

device_set_callback is used to register an SPI device interrupt callback function.

int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
  • dev device handle

  • callback the interrupt callback function to be registered

    • dev device handle

    • args receive and send buffer, the data type is uint8_t*

    • size transmission length

    • event interrupt event type

event type definition is as follows:

enum spi_event_type
{
    SPI_EVENT_TX_FIFO,
    SPI_EVENT_RX_FIFO,
    SPI_EVENT_UNKNOWN
};

2.7.4.8. spi_transmit

spi_transmit is used to send data from SPI devices.

int spi_transmit(struct device *dev, void *buffer, uint32_t size, uint8_t type);
  • dev device handle

  • buffer send data buffer

  • size send length

  • type send bit width type

type provides the following types

#define SPI_TRANSFER_TYPE_8BIT    0
#define SPI_TRANSFER_TYPE_16BIT   1
#define SPI_TRANSFER_TPYE_24BIT   2
#define SPI_TRANSFER_TYPE_32BIT   3

2.7.4.9. spi_receive

spi_receive is used to receive data from SPI devices.

int spi_receive(struct device *dev, void *buffer, uint32_t size, uint8_t type);
  • dev device handle

  • buffer receive data buffer

  • size receiving length

  • type bit width type

2.7.4.10. spi_transmit_receive

spi_transmit_receive is used to send and receive data from SPI devices.

int spi_transmit_receive(struct device *dev, const void *send_buf, void *recv_buf, uint32_t length, uint8_t type);
  • dev device handle

  • send_buf send data buffer

  • recv_buf receive data buffer

  • length send and receive length

  • type bit width type