In-Depth Guide to STM32 SPI Master-Slave Communication

In-Depth Guide to STM32 SPI Master-Slave Communication

SPI, as one of the commonly used communication interfaces for microcontrollers, is frequently utilized for high-speed data exchange with various peripherals. This article will take you deep into the STM32 SPI master-slave communication, mastering this practical skill.

1. Basic Concepts of SPI

SPI (Serial Peripheral Interface) is a synchronous serial communication protocol, typically consisting of four lines:

  • • SCLK: Clock line, generated by the master
    • • MOSI: Master Output/Slave Input
    • • MISO: Master Input/Slave Output
    • • CS/NSS: Chip Select line, used to select the slave

Imagine SPI as a bidirectional conveyor belt, where SCLK is the power of the conveyor, MOSI and MISO are the goods moving in two directions, and CS is the switch button.

Note: SPI is a full-duplex communication, meaning data can be transmitted in both directions simultaneously.

2. STM32 SPI Hardware Circuit

Taking STM32F103 as an example, a typical connection for SPI1 is as follows:

         STM32 (Master)                  Slave Device
         
         PA5(SCK)  ----------------->  SCK
         PA6(MISO) <-----------------  MISO  
         PA7(MOSI) ----------------->  MOSI
         PA4(NSS)  ----------------->  CS

Note: In practical applications, NSS is often simulated by a regular GPIO for more flexible control of multiple slaves.

3. SPI Master Initialization Code

void SPI1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    
    // Enable clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
    
    // Configure GPIO
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // Configure SPI
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);
    
    // Enable SPI
    SPI_Cmd(SPI1, ENABLE);
}

This piece of code is like configuring the working parameters for SPI1. Imagine you are setting up a sewing machine, adjusting stitch length, speed, etc.; here we are also setting parameters such as data width and clock polarity for SPI.

4. SPI Data Transmission and Reception

uint8_t SPI1_ReadWriteByte(uint8_t TxData)
{
    uint8_t retry = 0;
    
    // Wait for the transmit buffer to be empty
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
    {
        if(++retry > 200) return 0;
    }
    
    // Send data
    SPI_I2S_SendData(SPI1, TxData);
    retry = 0;
    
    // Wait for the receive buffer to be non-empty
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
    {
        if(++retry > 200) return 0;
    }
    
    // Return the received data
    return SPI_I2S_ReceiveData(SPI1);
}

This function is like playing ping pong; you hit the ball (send data), then wait for the other side to return a ball (receive data). If the other side takes too long to respond, we stop waiting to avoid the program hanging.

In-Depth Guide to STM32 SPI Master-Slave Communication

5. Practical Application Case: Reading SPI Flash

Suppose we want to read the contents of an SPI Flash chip:

void ReadFlashID(void)
{
    uint8_t Temp = 0;
    
    SPI_CS_Low();  // Pull low chip select, select Flash chip
    
    SPI1_ReadWriteByte(0x9F);  // Send read ID command
    
    Temp = SPI1_ReadWriteByte(0xFF);  // Read manufacturer ID
    printf("Manufacturer ID: 0x%02X\n", Temp);
    
    Temp = SPI1_ReadWriteByte(0xFF);  // Read memory type
    printf("Memory Type: 0x%02X\n", Temp);
    
    Temp = SPI1_ReadWriteByte(0xFF);  // Read capacity
    printf("Capacity: 0x%02X\n", Temp);
    
    SPI_CS_High();  // Pull high chip select, release Flash chip
}

This process is like asking the Flash chip, “Who are you, where are you from, and where are you going?” We first send a specific command (0x9F), and then the Flash chip obediently tells us its identity information.

6. Common Problems and Solutions

  1. 1. Communication Failure
  • • Check if the hardware connections are correct
  1. 2. Data Errors
  • • Ensure that the SPI parameters (such as CPOL, CPHA) of the master and slave match
  • • Use an oscilloscope to observe if the SCLK and MOSI signals are normal
  • • Check if the data bit order (MSB/LSB) is consistent
    1. 3. Multiple Slaves Confusion
    • • Ensure that the data length settings are correct (8-bit/16-bit)
    • • Consider adding delays to give the slave enough response time
  • • Ensure that only one slave’s CS is low at a time
    • • Consider using GPIO to simulate NSS for more flexible control of multiple slaves

    Note: When debugging SPI communication, do not forget to check the power and ground connections. Many times, seemingly complex problems arise from the most basic connection issues.

    Practical Suggestions

    1. 1. Start with simple SPI devices, such as EEPROM or Flash chips.
    2. 2. Use a logic analyzer to observe SPI signals and understand the communication process.
    3. 3. Try different SPI modes (combinations of CPOL and CPHA) to understand their differences.
    4. 4. Implement an SPI-based multi-slave system, such as a temperature sensor + OLED display.
    5. 5. Explore the SPI DMA functionality of STM32 to improve data transfer efficiency.

    Through the above learning and practice, I believe you have gained a deep understanding of STM32 SPI communication. Remember, what you learn from books is always superficial; true understanding comes from practice. The more hands-on experience you have, the better you can master this skill.

    Leave a Comment