SPI Master RGB Write

This document introduces three SPI communication samples. The samples demonstrate how SPI uses one data line to control an LED in three different modes: polling (sample1), interrupt (sample2), and DMA (sample3). In all three examples, the SPI is configured as a master, the clock is set to 10MHz, the direction is full-duplex, and the data frame size is 12 bits. The chip writes RGB data to the SPI slave to light up the LED.

Requirements

For hardware requirements, please refer to the Requirements.

Wiring

Connect P1_0 (SPI master MOSI) to the LED controller.

Configurations

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

    • #define PIN_SPI_MOSI P1_0

  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_rgb_polling_demo();
    

    For sample 2, use the following entry function:

    spi_rgb_interrupt_demo();
    

    For sample 3, use the following entry function:

    spi_rgb_dma_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, convert rgb_data into SPI_WriteBuf in preparation for sending.

  2. Send SPI_WriteBuf with a data length of 91 to LED controller.

Sample 2 Verification

  1. Press the Reset button on the EVB, convert rgb_data into SPI_WriteBuf in preparation for sending.

  2. Send SPI_WriteBuf with a data length of 24 to LED controller. When the data length in TX FIFO is equal to or below its threshold value, trigger the SPI_INT_TXE interrupt and prints log.

    spi_tx_handler: SPI TX FIFO Empty
    

Sample 3 Verification

  1. Press the Reset button on the EVB, convert rgb_data into SPI_WriteBuf in preparation for sending.

  2. Send SPI_WriteBuf with a data length of 24 to LED controller. When completing the transmission, it enters the GDMA interrupt and prints log.

    spi_tx_dma_handler
    

Code Overview

Source Code Directory

For all three 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\polling\spi_rgb_polling_demo.c .

Sample 2 source code:

  • Source code directory: sdk\src\sample\io_demo\spi\interrupt\spi_rgb_interrupt_demo.c .

Sample 3 source code:

  • Source code directory: sdk\src\sample\io_demo\gdma\spi_dma\spi_rgb_dma_demo.c .

RGB Polling Initialization Flow

The initialization flow for peripherals can refer to Initialization Flow.

The SPI initialization flow can refer to SPI Initialization Flow Chart.

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

    static void board_spi_init(void)
    {
       Pinmux_Config(PIN_SPI1_MOSI, SPI1_MO_MASTER);
       Pad_Config(PIN_SPI1_MOSI, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, 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_Master

    Data Frame Size

    SPI_InitTypeDef::SPI_DataSize

    SPI_DataSize_12b

    Clock Polarity

    SPI_InitTypeDef::SPI_CPOL

    SPI_CPOL_High

    Clock Phase

    SPI_InitTypeDef::SPI_CPHA

    SPI_CPHA_1Edge

    Clock Div

    SPI_InitTypeDef::SPI_BaudRatePrescaler

    4

    Frame Format

    SPI_InitTypeDef::SPI_FrameFormat

    SPI_Frame_Motorola

  4. Call SPI_Cmd() to enable SPI.

RGB Interrupt Initialization Flow

The initialization flow for peripherals can refer to Initialization Flow.

The 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(PIN_SPI1_MOSI, SPI1_MO_MASTER);
       Pad_Config(PIN_SPI1_MOSI, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, 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_Master

    Data Frame Size

    SPI_InitTypeDef::SPI_DataSize

    SPI_DataSize_12b

    Clock Polarity

    SPI_InitTypeDef::SPI_CPOL

    SPI_CPOL_High

    Clock Phase

    SPI_InitTypeDef::SPI_CPHA

    SPI_CPHA_1Edge

    Clock Div

    SPI_InitTypeDef::SPI_BaudRatePrescaler

    4

    Frame Format

    SPI_InitTypeDef::SPI_FrameFormat

    SPI_Frame_Motorola

    Transmit FIFO Threshold Level

    SPI_InitTypeDef::SPI_TxThresholdLevel

    0

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

  5. Call SPI_Cmd() to enable SPI.

RGB DMA Initialization Flow

The SPI RGB 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 RCC_PeriphClockCmd() to enable the GDMA clock and function.

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

  3. 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_DMA_CHANNEL_NUM

    Transfer Direction

    GDMA_InitTypeDef::GDMA_DIR

    GDMA_DIR_MemoryToPeripheral

    Buffer Size

    GDMA_InitTypeDef::GDMA_BufferSize

    RGB_DATA_LEN

    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_HalfWord

    Destination Data Size

    GDMA_InitTypeDef::GDMA_DestinationDataSize

    GDMA_DataSize_HalfWord

    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

    SPI_WriteBuf

    Destination Address

    GDMA_InitTypeDef::GDMA_DestinationAddr

    SPI1->DR

    Destination Handshake

    GDMA_InitTypeDef::GDMA_DestHandshake

    GDMA_Handshake_SPI1_TX

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

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

Functional Implementation

Master Send RGB Data by Polling

  1. Call SPI_SendHalfWord() to send the 12 bits data in SPI_WriteBuf to the slave.

  2. Call SPI_GetFlagState() to check SPI_FLAG_BUSY flag state, and wait for the SPI data transfer to complete.

static void led_control_rgb_to_spi_buffer(uint32_t data)
{
   for (uint32_t i = 0; i < RGB_DATA_LEN; i++)
   {
      if (data & BIT(RGB_DATA_LEN - i - 1)) //1bit
      {
            SPI_WriteBuf[i] = 0xFF8;
      }
      else
      {
            SPI_WriteBuf[i] = 0xE00;
      }
   }
}

uint32_t rgb_data = 0xa5a5a5; //24bits RGB sample
led_control_rgb_to_spi_buffer(rgb_data);

SPI_SendHalfWord(SPI1, SPI_WriteBuf, DATA_LEN);
while (SPI_GetFlagState(SPI1, SPI_FLAG_BUSY));

Master Send RGB Data by Interrupt

  1. Call SPI_SendHalfWord() to send the 12 bits data in SPI_WriteBuf to the slave.

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

  3. 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.

static void spi_tx_handler(void)
{
   if (SPI_GetINTStatus(SPI_MASTER, SPI_INT_TXE) == SET)
   {
      SPI_INTConfig(SPI_MASTER, SPI_INT_TXE, DISABLE);
      IO_PRINT_INFO0("spi_tx_handler: SPI TX FIFO Empty");
   }
}

Master Send RGB Data by DMA

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

  2. Call GDMA_Cmd() enable DMA to send data in SPI_WriteBuf to the slave.

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

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

    2. Call GDMA_ClearINTPendingBit() to clear GDMA_INT_Transfer interrupt.

static void spi_tx_dma_handler(void)
{
   IO_PRINT_INFO0("spi_tx_dma_handler");
   GDMA_INTConfig(SPI_DMA_CHANNEL_NUM, GDMA_INT_Transfer, DISABLE);
   GDMA_ClearINTPendingBit(SPI_DMA_CHANNEL_NUM, GDMA_INT_Transfer);
}