LoopBack

This sample demonstrates communication between an SPI master and slave device using an interrupt method.

During the communication process, the master and slave devices exchange data to communicate, and data reception is handled via interrupts.

When the data received by the master or slave device reaches a set threshold, an SPI_INT_RXF interrupt is triggered for data reception.

In this sample, SPI1 is configured as the master device, and SPI0 is configured as the slave device.

Requirements

For requirements, please refer to the Requirements.

Wiring

On the EVB, connect P2_4(Master SCK) to P3_0(Slave SCK), P2_5(Master MOSI) to P3_1(Slave MOSI), P2_6(Master MISO) to P3_2(Slave MISO), and P2_7(Master CS) to P3_3(Slave CS).

Configurations

  1. The following macro can be configured to modify the pin definitions.

    /* SPI1 MASTER pin define*/
    #define SPI_MASTER_SCK_PIN               P2_4
    #define SPI_MASTER_MOSI_PIN              P2_5
    #define SPI_MASTER_MISO_PIN              P2_6
    #define SPI_MASTER_CS_PIN                P2_7
    
    /* SPI0 SLAVE pin define*/
    #define SPI_SLAVE_SCK_PIN                P3_0
    #define SPI_SLAVE_MOSI_PIN               P3_1
    #define SPI_SLAVE_MISO_PIN               P3_2
    #define SPI_SLAVE_CS_PIN                 P3_3
    

Building and Downloading

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

Experimental Verification

  1. When the EVB starts, observe the following log within the Debug Analyzer.

    Start spi loopback test!
    
  2. The master device sends data {0, 1, …, 0x14} to the slave device. The Slave receives the data from the Master, enters the interrupt, prints the length of the data received by the Slave, and prints the data received by the Slave and the data sent by the Master.

    SPI SLAVE receieves 20 data.
    slave_rx_buf[0] = 0x00000001, master_tx_buf[0] = 0x00000001
    slave_rx_buf[1] = 0x00000002, master_tx_buf[1] = 0x00000002
    ...
    slave_rx_buf[19] = 0x00000014, master_tx_buf[19] = 0x00000014
    
  3. The slave device sends data {0x10, 0x11, …, 0x23} to the master device. The Master receives the information sent by the Slave, enters an interrupt, prints the length of the data received by the Master, and prints the data received by the Master and the data sent by the Slave.

    SPI MASTER receieves 20 data
    master_rx_buf[0] = 0x00000010, slave_tx_buf[0] = 0x00000010
    master_rx_buf[1] = 0x00000011, slave_tx_buf[1] = 0x00000011
    ...
    master_rx_buf[19] = 0x00000023, slave_tx_buf[19] = 0x00000023
    

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directory for project file and source code are as follows:

  • Project directory: sdk\samples\peripheral\spi\loopback\proj

  • Source code directory: sdk\samples\peripheral\spi\loopback\src

Initialization

The initialization flow for peripherals can refer to Initialization Flow in General Introduction.

  1. Call Pad_Config() and Pinmux_Config() to configure the PAD and PINMUX of the corresponding pins. Set the PINMUX of SPI1-related pins to the master device function, and set the PINMUX of SPI0-related pins to the slave device function.

    void board_spi_master_init(void)
    {
       Pad_Config(SPI_MASTER_SCK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
       Pad_Config(SPI_MASTER_MOSI_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
       Pad_Config(SPI_MASTER_MISO_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
       Pad_Config(SPI_MASTER_CS_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    
       Pinmux_Deinit(SPI_MASTER_SCK_PIN);
       Pinmux_Deinit(SPI_MASTER_MOSI_PIN);
       Pinmux_Deinit(SPI_MASTER_MISO_PIN);
       Pinmux_Deinit(SPI_MASTER_CS_PIN);
    
       Pinmux_Config(SPI_MASTER_SCK_PIN, SPI1_CLK_MASTER);
       Pinmux_Config(SPI_MASTER_MOSI_PIN, SPI1_MO_MASTER);
       Pinmux_Config(SPI_MASTER_MISO_PIN, SPI1_MI_MASTER);
       Pinmux_Config(SPI_MASTER_CS_PIN, SPI1_CSN_0_MASTER);
    }
    
    void board_spi_slave_init(void)
    {
       Pad_Config(SPI_SLAVE_SCK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
       Pad_Config(SPI_SLAVE_MOSI_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
       Pad_Config(SPI_SLAVE_MISO_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
       Pad_Config(SPI_SLAVE_CS_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    
       /* Must deinit P4_0~P4_3 before use SPI SLAVE!!! */
       Pinmux_Deinit(P4_0);
       Pinmux_Deinit(P4_1);
       Pinmux_Deinit(P4_2);
       Pinmux_Deinit(P4_3);
    
       Pinmux_Deinit(SPI_SLAVE_SCK_PIN);
       Pinmux_Deinit(SPI_SLAVE_MOSI_PIN);
       Pinmux_Deinit(SPI_SLAVE_MISO_PIN);
       Pinmux_Deinit(SPI_SLAVE_CS_PIN);
    
       Pinmux_Config(SPI_SLAVE_SCK_PIN, SPI0_CLK_SLAVE);
       Pinmux_Config(SPI_SLAVE_MOSI_PIN, SPI0_SI_SLAVE);
       Pinmux_Config(SPI_SLAVE_MISO_PIN, SPI0_SO_SLAVE);
       Pinmux_Config(SPI_SLAVE_CS_PIN, SPI0_CSN_0_SLAVE);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the SPI clock.

  3. Initialize the SPI peripheral:

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

    2. Modify the SPI_InitStruct parameters as needed. The SPI0 and SPI1 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_InitStruct

SPI1

SPI0_SLAVE

SPI Transfer Mode

SPI_InitTypeDef::SPI_Direction

SPI_Direction_FullDuplex

SPI_Direction_FullDuplex

SPI Data Size

SPI_InitTypeDef::SPI_DataSize

SPI_DataSize_8b

SPI_DataSize_8b

Clock Mode - CPOL

SPI_InitTypeDef::SPI_CPOL

SPI_CPOL_High

SPI_CPOL_High

Clock Mode - CPHA

SPI_InitTypeDef::SPI_CPHA

SPI_CPHA_2Edge

SPI_CPHA_2Edge

Clock Prescaler

SPI_InitTypeDef::SPI_BaudRatePrescaler

100

100

Frame Format

SPI_InitTypeDef::SPI_FrameFormat

SPI_Frame_Motorola

SPI_Frame_Motorola

RX Threshold

SPI_InitTypeDef::SPI_RxThresholdLevel

SEND_LENGTH - 1

SEND_LENGTH - 1

  1. Call SPI_Cmd() to enable SPI peripheral.

Functional Implementation

  1. Before the master device calls SPI_SendBuffer() to send data, the slave device must first call SPI_SendBuffer() to preload data into the FIFO. Once the master device starts sending data back, it initiates the clock signal, and the slave device follows by transmitting the data.

  2. The master device receives data sent by the slave device, and upon reaching the threshold, it triggers the SPI_INT_RXF interrupt. Similarly, the slave device triggers the interrupt upon receiving data. Within the interrupt function, call SPI_GetRxFIFOLen() and SPI_ReceiveData() to receive the data.

    void SPI_Handler_MASTER(void)
    {
       if (SPI_GetINTStatus(SPI_MASTER, SPI_INT_RXF))
       {
          SPI_INTConfig(SPI_MASTER, SPI_INT_RXF, DISABLE);
          SPI_ClearINTPendingBit(SPI_MASTER, SPI_INT_RXF);
          uint32_t master_rx_len = SPI_GetRxFIFOLen(SPI_MASTER);
          ...
          SPI_INTConfig(SPI_MASTER, SPI_INT_RXF, ENABLE);
       }
    }
    
    void SPI_Handler_SLAVE(void)
    {
       if (SPI_GetINTStatus(SPI_SLAVE, SPI_INT_RXF))
       {
          SPI_INTConfig(SPI_SLAVE, SPI_INT_RXF, DISABLE);
          SPI_ClearINTPendingBit(SPI_SLAVE, SPI_INT_RXF);
          uint32_t slave_rx_len = SPI_GetRxFIFOLen(SPI_SLAVE);
          ...
          SPI_INTConfig(SPI_SLAVE, SPI_INT_RXF, ENABLE);
       }
    
    }