SPI Slave Write GPIO

The sample demonstrates how SPI0 slave sends data and SPI1 master receives data by GPIO in interrupt mode. Because the SPI slave does not support sending data when the TX FIFO is empty, the sample toggles a GPIO pin to notify the master after the slave sends data.

Requirements

For hardware requirements, please refer to the Requirements.

Wiring

Connect P1_4 (master SCK) to P1_0 (slave SCK), connect P1_7 (master CS) to P1_3 (slave CS), connect P1_6 (master MISO) to P1_2 (slave MISO), connect P1_5 (master MOSI) to P1_1 (slave MOSI), and connect P2_3 (master GPIO input) to P2_4 (slave GPIO output) on EVB. The hardware connection of SPI sample code is shown in the figure below.

../../../_images/SPI_Demo_8_1_Hardware_Connection_Diagram.png

SPI Sample Code Hardware Connection Diagram

Configurations

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

    • #define SPI1_SCK P1_4

    • #define SPI1_MOSI P1_5

    • #define SPI1_MISO P1_6

    • #define SPI1_CS P1_7

    • #define SPI0_SCK P1_0

    • #define SPI0_MOSI P1_1

    • #define SPI0_MISO P1_2

    • #define SPI0_CS P1_3

    • #define GPIO_PIN1 P2_3

    • #define GPIO_PIN0 P2_4

  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.

    spi_slave_gpio_demo();
    

Building and Downloading

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

Experimental Verification

  1. Press the Reset button on the EVB.

  2. The slave device sends data to TX FIFO, toggle GPIO to notify master, then master device sends data to slave.

  3. When the data length in the master or slave TX FIFO is equal to or below its threshold value, trigger the SPI_INT_TXE interrupt and prints log.

    spi1_handler: SPI1 TX FIFO Empty
    spi0_handler: SPI0 TX FIFO Empty
    
  4. When the data length in slave RX FIFO is equal to or above its threshold value plus 1, trigger the SPI_INT_RXF interrupt. Then the data is received in array SPI_ReadINTBuf and printed in Debug Analyzer.

    spi0_handler: SPI_ReadINTBuf[0] 0x11
    ...
    spi0_handler: SPI_ReadINTBuf[5] 0x66
    
  5. When the data length in master RX FIFO is equal to or above its threshold value plus 1, trigger the SPI_INT_RXF interrupt. Then the data is received in array SPI1_ReadINTBuf and printed in Debug Analyzer.

    spi1_handler: SPI1_ReadINTBuf[0] 0x11
    ...
    spi1_handler: SPI1_ReadINTBuf[5] 0x66
    

Code Overview

Source Code Directory

  • For project directory, please refer to Source Code Directory.

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

GPIO Interrupt Initialization Flow

  1. Call hal_gpio_init() to enable GPIO clock.

  2. Call hal_gpio_int_init() to initialize GPIO interrupt.

  3. Call hal_gpio_set_debounce_time() to set GPIO debounce time.

  4. Call hal_gpio_init_pin() to initialize the GPIO peripheral and call hal_gpio_set_up_irq() to initialize interrupt-related parameters. The GPIO initialization parameters are configured as shown in the table below.

GPIO Input0 Initialization Parameters

GPIO Hardware Parameters

GPIO

PIN Number

GPIO_PIN1

GPIO Type

GPIO_TYPE_AUTO

GPIO Mode

GPIO_DIR_INPUT

GPIO Pull Value

GPIO_PULL_UP

Interrupt Type

GPIO_IRQ_EDGE

Interrupt Polarity

GPIO_IRQ_ACTIVE_LOW

Debounce Enable

true

  1. Call hal_gpio_register_isr_callback() to register gpio interrupt callback.

  2. Call hal_gpio_irq_enable() to enable gpio interrupt.

GPIO Output Initialization Flow

  1. Call hal_gpio_init() to enable GPIO clock.

  2. Call hal_gpio_init_pin() to initialize the GPIO peripheral. The GPIO initialization parameters are configured as shown in the table below.

GPIO Output0 Initialization Parameters

GPIO Hardware Parameters

GPIO

PIN Number

GPIO_PIN0

GPIO Type

GPIO_TYPE_AUTO

GPIO Mode

GPIO_DIR_OUTPUT

GPIO Pull Value

GPIO_PULL_UP

  1. Call hal_gpio_set_level() to output low level.

SPI Initialization Flow (SPI0 Slave)

The initialization flow for peripherals can refer to Initialization Flow.

SPI initialization flow is shown in the following figure.

../../../_images/SPI_Initialization_Flow_Chart.png

SPI Initialization Flow Chart

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

    static void board_spi_init(void)
    {
       Pinmux_Config(SPI0_SCK, SPI0_CLK_SLAVE);
       Pinmux_Config(SPI0_MOSI, SPI0_SI_SLAVE);
       Pinmux_Config(SPI0_MISO, SPI0_SO_SLAVE);
       Pinmux_Config(SPI0_CS, SPI0_SS_N_0_SLAVE);
    
       Pad_Config(SPI0_SCK, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(SPI0_MOSI, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(SPI0_MISO, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(SPI0_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 SPI0 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

    Frame Format

    SPI_InitTypeDef::SPI_FrameFormat

    SPI_Frame_Motorola

    Transmit FIFO Threshold Level

    SPI_InitTypeDef::SPI_TxThresholdLevel

    0

    Receive FIFO Threshold Level

    SPI_InitTypeDef::SPI_RxThresholdLevel

    0

  4. Call SPI_Cmd() to enable SPI.

  5. Call SPI_INTConfig() to enable RX FIFO full interrupt SPI_INT_RXF and TX FIFO underflow interrupt SPI_INT_TUF.

  6. Call RamVectorTableUpdate() to register SPI0 interrupt handler.

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

SPI Initialization Flow (SPI1 Master)

SPI initialization flow can refer to SPI Initialization Flow Chart.

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

    static void board_spi_init(void)
    {
       Pinmux_Config(SPI1_SCK, SPI1_CLK_MASTER);
       Pinmux_Config(SPI1_MOSI, SPI1_MO_MASTER);
       Pinmux_Config(SPI1_MISO, SPI1_MI_MASTER);
       Pinmux_Config(SPI1_CS, SPI1_SS_N_0_MASTER);
    
       Pad_Config(SPI1_SCK, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(SPI1_MOSI, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(SPI1_MISO, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_HIGH);
       Pad_Config(SPI1_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 SPI1 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_Master

    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

    Clock Div

    SPI_InitTypeDef::SPI_BaudRatePrescaler

    400

    Frame Format

    SPI_InitTypeDef::SPI_FrameFormat

    SPI_Frame_Motorola

    Transmit FIFO Threshold Level

    SPI_InitTypeDef::SPI_TxThresholdLevel

    0

    Receive FIFO Threshold Level

    SPI_InitTypeDef::SPI_RxThresholdLevel

    0

  4. Call SPI_Cmd() to enable SPI.

  5. Call SPI_INTConfig() to enable RX FIFO full interrupt SPI_INT_RXF.

  6. Call RamVectorTableUpdate() to register SPI1 interrupt handler.

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

Functional Implementation

Send Data by Interrupt

  1. Call SPI_SendBuffer() to send the data in SPI_WriteBuf to the slave.

  2. Call SPI_INTConfig() to enable TX FIFO empty interrupt SPI_INT_TXE.

Interrupt Handle

  1. When the transmit buffer reaches or goes below the TX FIFO threshold level (SPI_InitTypeDef::SPI_TxThresholdLevel), TX FIFO empty interrupt will be triggered and enters the interrupt handler:

    1. Call SPI_GetINTStatus() to check SPI_INT_TXE interrupt status.

    2. Call SPI_INTConfig() to disable SPI_INT_TXE.

  2. When the receive buffer reaches or goes above the RX FIFO threshold level (SPI_InitTypeDef::SPI_RxThresholdLevel + 1), RX full interrupt will be triggered and enters the interrupt handler:

    1. Call SPI_GetINTStatus() to check SPI_INT_RXF interrupt status.

    2. Call SPI_GetRxFIFOLen() to get the data length in RX FIFO.

    3. Call SPI_ReceiveData() to receive data from RX FIFO.

  3. 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_GetINTStatus() to check SPI_INT_TUF interrupt status.

    2. Call SPI_INTConfig() to disable TX FIFO underflow interrupt SPI_INT_TUF.