SPI Slave High Speed

This document introduces two SPI communication samples. The sample1 demonstrates how SPI0 slave reads data at high speed in DMA mode. The sample2 demonstrates how SPI0 slave sends data at high speed in DMA mode. In both examples, SPI is configured as a slave operating in DMA mode. The chip writes data to the SPI master or reads data from it.

Requirements

For hardware requirements, please refer to the Requirements.

Wiring

Connect P1_1 (slave CS) to the CS of SPI master device, connect P0_0 (slave SCK) to the SCK of SPI master device, connect P0_1 (slave MISO) to the MISO of SPI master device, and connect P1_0 (slave MOSI) to the MOSI of SPI master device. The hardware connection of SPI sample code is shown in the figure below.

../../../_images/SPI_Demo_9_1_Hardware_Connection_Diagram.png

SPI Sample Code Hardware Connection Diagram

Configurations

  1. The following macros can be configured to modify pin definitions.

    • #define PIN_SPI_SCK P0_0

    • #define PIN_SPI_MOSI P1_0

    • #define PIN_SPI_MISO P0_1

    • #define PIN_SPI_CS P1_1

  2. The entry function are as follows, call this function in main() to run this sample code. For more details, please refer to the Initialization.

    For sample 1, use the following entry function:

    spi_slave_rx_dma_hs_demo();
    

    For sample 2, use the following entry function:

    spi_slave_tx_dma_hs_demo();
    

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

Sample 1 Verification

  1. Press the Reset button on the EVB.

  2. After the master device sends data to the chip, the chip stores the received the data in array read_buf.

  3. When completing the transmission, it enters the GDMA interrupt and prints the received data.

    spi_slave_rx_dma_handler! rx_len_all 1000
    spi_slave_rx_dma_handler: read_buf
    ...
    spi_slave_rx_dma_handler: read_buf
    

Sample 2 Verification

  1. Press the Reset button on the EVB.

  2. The chip sends the data in array sendbuf to TX FIFO immediately. When the master device sends data, the data transmission is started.

  3. When completing the transmission, it enters the GDMA interrupt and prints log.

    spi_slave_tx_dma_handler! tx_len_all 1000
    

Code Overview

Source Code Directory

For both samples, please refer to the Source Code Directory for the project directory.

Sample 1 source code:

  • Source code directory: sdk\src\sample\io_demo\spi\slave\spi_slave_rx_dma_hs_demo.c .

Sample 2 source code:

  • Source code directory: sdk\src\sample\io_demo\spi\slave\spi_slave_tx_dma_hs_demo.c .

RX DMA Initialization Flow

The initialization flow for peripherals can refer to Initialization Flow.

The SPI RX DMA initialization flow requires first initializing the SPI peripheral, followed by RX DMA initialization. The SPI initialization flow can refer to SPI Initialization Flow Chart. The SPI RX DMA initialization flow can refer to SPI RX DMA Initialization Flow Chart.

  1. Call Pad_Config() and Pinmux_Config() to initialize the pin.

    static void board_spi_init(void)
    {
       Pinmux_Config(PIN_SPI_SCK, SPI_CLK_SLAVE);
       Pinmux_Config(PIN_SPI_MOSI, SPI_MO_SLAVE);
       Pinmux_Config(PIN_SPI_MISO, SPI_MI_SLAVE);
       Pinmux_Config(PIN_SPI_CS, SPI_SS_N_0_SLAVE);
    
       Pad_Config(PIN_SPI_SCK, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(PIN_SPI_MOSI, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(PIN_SPI_MISO, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(PIN_SPI_CS, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the SPI clock and function.

  3. Initialize the SPI peripheral:

    1. Define the SPI_InitTypeDef type SPI_InitStructure, and call SPI_StructInit() to pre-fill SPI_InitStructure with default values.

    2. Modify the SPI_InitStructure parameters as needed. The SPI initialization parameter configuration is shown in the table below.

    3. Call SPI_Init() to initialize the SPI peripheral.

    SPI Initialization Parameters

    SPI Hardware Parameters

    Setting in the SPI_InitStructure

    SPI

    Direction

    SPI_InitTypeDef::SPI_Direction

    SPI_Direction_FullDuplex

    Device Role (SPI Master or SPI Slave)

    SPI_InitTypeDef::SPI_Mode

    SPI_Mode_Slave

    Data Frame Size

    SPI_InitTypeDef::SPI_DataSize

    SPI_DataSize_8b

    Clock Polarity

    SPI_InitTypeDef::SPI_CPOL

    SPI_CPOL_High

    Clock Phase

    SPI_InitTypeDef::SPI_CPHA

    SPI_CPHA_1Edge

    RX Water Level

    SPI_InitTypeDef::SPI_RxWaterlevel

    31

  4. Call SPI_Cmd() to enable SPI.

  5. Call RCC_PeriphClockCmd() to enable the GDMA clock and function.

  6. Call GDMA_channel_request to request a free GDMA channel and register the GDMA interrupt handler.

  7. Initialize the GDMA peripheral:

    1. Define the GDMA_InitTypeDef type GDMA_InitStruct, and call GDMA_StructInit() to pre-fill GDMA_InitStruct with default values.

    2. Modify the GDMA_InitStruct parameters as needed. The GDMA initialization parameter configuration is shown in the table below.

    3. Call GDMA_Init() to initialize the GDMA peripheral.

    GDMA Initialization Parameters

    GDMA Hardware Parameters

    Setting in the GDMA_InitStruct

    GDMA

    Channel Num

    GDMA_InitTypeDef::GDMA_ChannelNum

    SPI_SLAVE_RX_DMA_CHANNEL_NUM

    Transfer Direction

    GDMA_InitTypeDef::GDMA_DIR

    GDMA_DIR_PeripheralToMemory

    Buffer Size

    GDMA_InitTypeDef::GDMA_BufferSize

    TEST_SIZE

    Source Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_SourceInc

    DMA_SourceInc_Fix

    Destination Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_DestinationInc

    DMA_DestinationInc_Inc

    Source Data Size

    GDMA_InitTypeDef::GDMA_SourceDataSize

    GDMA_DataSize_Byte

    Destination Data Size

    GDMA_InitTypeDef::GDMA_DestinationDataSize

    GDMA_DataSize_Byte

    Source Burst Transaction Length

    GDMA_InitTypeDef::GDMA_SourceMsize

    GDMA_Msize_32

    Destination Burst Transaction Length

    GDMA_InitTypeDef::GDMA_DestinationMsize

    GDMA_Msize_32

    Source Address

    GDMA_InitTypeDef::GDMA_SourceAddr

    SPI0->DR

    Destination Address

    GDMA_InitTypeDef::GDMA_DestinationAddr

    read_buf

    Source Handshake

    GDMA_InitTypeDef::GDMA_SourceHandshake

    GDMA_Handshake_SPI0_RX

  8. Call GDMA_INTConfig() to enable GDMA transfer complete interrupt GDMA_INT_Transfer.

  9. Call NVIC_Init() to enable NVIC of GDMA.

TX DMA Initialization Flow

The initialization flow for peripherals can refer to Initialization Flow.

The SPI TX DMA initialization flow requires first initializing the SPI peripheral, followed by TX DMA initialization. The SPI initialization flow can refer to SPI Initialization Flow Chart. The SPI TX DMA initialization flow can refer to SPI TX DMA Initialization Flow Chart.

  1. Call Pad_Config() and Pinmux_Config() to initialize the pin.

    static void board_spi_init(void)
    {
       Pinmux_Config(PIN_SPI_SCK, SPI_CLK_MASTER);
       Pinmux_Config(PIN_SPI_MOSI, SPI_MO_MASTER);
       Pinmux_Config(PIN_SPI_MISO, SPI_MI_MASTER);
       Pinmux_Config(PIN_SPI_CS, SPI_SS_N_0_MASTER);
    
       Pad_Config(PIN_SPI_SCK, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE,
                   PAD_OUT_HIGH);
       Pad_Config(PIN_SPI_MOSI, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE,
                   PAD_OUT_HIGH);
       Pad_Config(PIN_SPI_MISO, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE,
                   PAD_OUT_HIGH);
       Pad_Config(PIN_SPI_CS, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the SPI clock and function.

  3. Initialize the SPI peripheral:

    1. Define the SPI_InitTypeDef type SPI_InitStructure, and call SPI_StructInit() to pre-fill SPI_InitStructure with default values.

    2. Modify the SPI_InitStructure parameters as needed. The SPI initialization parameter configuration is shown in the table below.

    3. Call SPI_Init() to initialize the SPI peripheral.

    SPI Initialization Parameters

    SPI Hardware Parameters

    Setting in the SPI_InitStructure

    SPI

    Direction

    SPI_InitTypeDef::SPI_Direction

    SPI_Direction_FullDuplex

    Device Role (SPI Master or SPI Slave)

    SPI_InitTypeDef::SPI_Mode

    SPI_Mode_Slave

    Data Frame Size

    SPI_InitTypeDef::SPI_DataSize

    SPI_DataSize_8b

    Clock Polarity

    SPI_InitTypeDef::SPI_CPOL

    SPI_CPOL_High

    Clock Phase

    SPI_InitTypeDef::SPI_CPHA

    SPI_CPHA_1Edge

    TX Water Level

    SPI_InitTypeDef::SPI_TxWaterlevel

    46

  4. Call SPI_Cmd() to enable SPI.

  5. Call SPI_INTConfig() to enable TX FIFO overflow SPI_INT_TXO and TX FIFO underflow interrupt SPI_INT_TUF.

  6. Call NVIC_Init() to enable NVIC of SPI.

  7. Call RCC_PeriphClockCmd() to enable the GDMA clock and function.

  8. Call GDMA_channel_request to request a free GDMA channel and register the GDMA interrupt handler.

  9. Initialize the GDMA peripheral:

    1. Define the GDMA_InitTypeDef type GDMA_InitStruct, and call GDMA_StructInit() to pre-fill GDMA_InitStruct with default values.

    2. Modify the GDMA_InitStruct parameters as needed. The GDMA initialization parameter configuration is shown in the table below.

    3. Call GDMA_Init() to initialize the GDMA peripheral.

    GDMA Initialization Parameters

    GDMA Hardware Parameters

    Setting in the GDMA_InitStruct

    GDMA

    Channel Num

    GDMA_InitTypeDef::GDMA_ChannelNum

    SPI_SLAVE_TX_DMA_CHANNEL_NUM

    Transfer Direction

    GDMA_InitTypeDef::GDMA_DIR

    GDMA_DIR_MemoryToPeripheral

    Buffer Size

    GDMA_InitTypeDef::GDMA_BufferSize

    TEST_SIZE

    Source Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_SourceInc

    DMA_SourceInc_Inc

    Destination Address Increment or Decrement

    GDMA_InitTypeDef::GDMA_DestinationInc

    DMA_DestinationInc_Fix

    Source Data Size

    GDMA_InitTypeDef::GDMA_SourceDataSize

    GDMA_DataSize_Byte

    Destination Data Size

    GDMA_InitTypeDef::GDMA_DestinationDataSize

    GDMA_DataSize_Byte

    Source Burst Transaction Length

    GDMA_InitTypeDef::GDMA_SourceMsize

    GDMA_Msize_16

    Destination Burst Transaction Length

    GDMA_InitTypeDef::GDMA_DestinationMsize

    GDMA_Msize_16

    Source Address

    GDMA_InitTypeDef::GDMA_SourceAddr

    sendbuf

    Destination Address

    GDMA_InitTypeDef::GDMA_DestinationAddr

    SPI0->DR

    Destination Handshake

    GDMA_InitTypeDef::GDMA_DestHandshake

    GDMA_Handshake_SPI0_TX

  10. Call GDMA_INTConfig() to enable GDMA transfer complete interrupt GDMA_INT_Transfer.

  11. Call NVIC_Init() to enable NVIC of GDMA.

Functional Implementation

Slave Receive Data by DMA in High Speed

  1. Call pm_cpu_slow_freq_set() to config the slow clock for high speed. For specific value, please refer to High Speed.

  2. Call SPI_GDMACmd() to disable and then enable SPI GDMA RX Function.

  3. Call GDMA_Cmd() to enable DMA transfers.

Slave Send Data by DMA in High Speed

  1. Call pm_cpu_slow_freq_set() to config the slow clock for high speed. For specific value, please refer to High Speed.

  2. Call SPI_GDMACmd() to disable and then enable SPI GDMA TX Function.

  3. Call GDMA_Cmd() to enable DMA transfers.

Slave TX Interrupt Handle

  1. If clocks sent by the master when the slave is at the empty FIFO level, TX FIFO underflow interrupt will be triggered and enters the interrupt handler:

    1. Call SPI_INTConfig() to disable TX underflow interrupt SPI_INT_TUF.

    2. Call SPI_ClearINTPendingBit() to clear SPI_INT_TUF interrupt.

    3. Call SPI_Cmd() to reset SPI slave for recover.

  2. If SPI attempts to write into the TX FIFO after it has been completely filled, TX FIFO overflow interrupt will be triggered and enters the interrupt handler:

    1. Call SPI_INTConfig() to disable TX overflow interrupt SPI_INT_TXO.

    2. Call SPI_ClearINTPendingBit() to clear SPI_INT_TXO interrupt.

Slave GDMA Interrupt Handle

When GDMA transfer is completed, transfer complete interrupt is triggered:

  1. Call GDMA_GetTransferLen() to get the GDMA transfer data length.

  2. Call GDMA_INTConfig() to disable GDMA transfer complete interrupt GDMA_INT_Transfer.

  3. Call GDMA_ClearINTPendingBit() to clear GDMA_INT_Transfer interrupt.