Coming soon |
This article explains what SPI is and how to use it through examples.
1. What is a serial peripheral interface (SPI)?
The Serial Peripheral Interface (SPI) is a synchronous serial communication interface specification used for short-distance communication, primarily in embedded systems. The interface was developed by Motorola in the mid-1980s and has become a de facto standard. SPI devices can communicate in full duplex mode using a master-slave architecture, with most often a single master. The master (controller) device originates the frame for reading and writing. Multiple slave-devices may be supported through selection with individual chip select (CS), sometimes called slave select (SS) lines.
In full duplex mode with multi-slaves, 4 buses are used:
- SCK (Serial Clock) bus, controlled by master.
- MISO (Master Input Slave Output) bus.
- MOSI (Master Output Slave Input) bus.
- SS (Slave Select) bus, useful in case of multiple slave configuration.
// ADD SPI BUS IMAGE
1.1. SPI Frame
// ADD SPI FRAME IMAGE
1.2. STM32 SPI Modes
The SPI interface is highly configurable to support many standard protocols and can operate in various modes.
- Full-Duplex
- Half-Duplex
- Receive Only
- Transmit Only
1.3. STM32 SPI Parameters
Basic parameters:
- Frame format: Motorola or TI
- Data size: 8 to 16 bits depending on STM32
- First bit: MSB or LSB
Clock parameters:
- Prescaler: from 2 to 256. Note that SPI clock speed cannot exceed half of the internal bus frequency.
- Clock polarity (CPOL): Low or high
- Clock Phase (CPHA): 1 or 2 Edge
1.4. Main SPI HAL functions
Based on STM32Cube HAL functions, SPI data transfer can be performed in 3 modes: Blocking Mode, Interrupt Mode or DMA Mode
- Blocking Mode:
- The communication is performed in polling mode. The status of all data processing is returned by the same function after finishing transfer.
- HAL_SPI_Transmit()
- HAL_SPI_Receive()
- HAL_SPI_TransmitReceive()
- HAL_SPI_Transmit()
- Non-blocking modes
- The communication is performed using Interrupts or DMA. These functions return the status of the transfer startup.
- The end of the data processing will be indicated through the dedicated SPI IRQ when using Interrupt mode or the DMA IRQ when using DMA mode.
- Interrupt Mode:
- HAL_SPI_Transmit_IT()
- HAL_SPI_Receive_IT()
- HAL_SPI_TransmitReceive_IT()
- HAL_SPI_Transmit_IT()
- DMA Mode:
- HAL_SPI_Transmit_DMA()
- HAL_SPI_Receive_DMA()
- HAL_SPI_TransmitReceive_DMA()
- HAL_SPI_Transmit_DMA()
2. Configure the SPI to communicate between 2 boards
2.1. Objective
In this example, the objective is to set up communication through SPI between two NUCLEO-L476RG. Here data is transmitted by master and received by slave.
2.2. Create project in STM32CubeIDE
- The NUCLEO-L476RG pinout is helpful to set the wiring between the boards in the project.
- File>New>STM32 Project in main panel.
In this example the NUCLEO-L476RG board is used to test SPI.
- Select NUCLEO-L476RG board using Board Selector as shown in the below figure.
In case you haven't downloaded the STM32L476 Cube library, it will be downloaded automatically, it may take some time.
- Save the project.
2.3. Configure SPI on master board
- Open the STM32CubeMX project from the workspace.
2.3.1. SPI settings
- Under Connectivity, select SPI1.
- Select Full-Duplex Master mode:
- Pin PA5 as SCK
- Pin PA6 as MISO
- Pin PA7 as MOSI
- Pin PA5 as SCK
- //ADD IMAGE SPI parameters
2.3.2. GIPO settings
- Leave GPIO in default configuration.
- //ADD IMAGE GIPO
2.3.3. NVIC and DMA settings
- Interrupt Mode only
- In the NVIC settings tab
- Enable interrupt
- In the NVIC settings tab
- DMA Mode only
- In the DMA settings tab
- In the DMA settings tab
- Add SPI1_TX for Master
- //ADD IMAGE SPI TX
2.4. Generate source code and edit main.c
- Click "Ctrl+S" to generate the project.
2.4.1. On MASTER Board
- Open main.c in Project Explorer / myproject / Src / main.c.
/* USER CODE BEGIN PV */
/* Private variables */
uint8_t TX_Buffer [] = "A" ; // DATA to send
/* USER CODE END PV */
- Blocking Mode
/* USER CODE BEGIN 2 */
HAL_SPI_Transmit(&hspi1, TX_Buffer, 1, 1000); //Sending in Blocking mode
HAL_Delay(100);
/* USER CODE END 2 */
- Interrupt Mode
/* USER CODE BEGIN 2 */
HAL_SPI_Transmit_IT(&hspi1, TX_Buffer, 1); //Sending in Interrupt mode
HAL_Delay(100);
/* USER CODE END 2 */
- DMA Mode
/* USER CODE BEGIN 2 */
HAL_SPI_Transmit_DMA(&hspi1, TX_Buffer, 1);; //Sending in DMA mode
HAL_Delay(100);
/* USER CODE END 2 */
2.4.2. On SLAVE Board
- Open main.c in Project Explorer / myproject / Src / main.c.
/* USER CODE BEGIN PV */
/* Private variables */
uint8_t RX_Buffer [1] ; // DATA to receive
/* USER CODE END PV */
- Blocking Mode
/* USER CODE BEGIN 2 */
HAL_SPI_Receive(&hspi1, RX_Buffer, 1, 1000); //Receiving in Blocking mode
HAL_Delay(100);
/* USER CODE END 2 */
- Interrupt Mode
/* USER CODE BEGIN 2 */
HAL_SPI_Receive_IT(&hspi1, RX_Buffer, 1); //Receiving in Interrupt mode
HAL_Delay(100);
/* USER CODE END 2 */
- DMA Mode
/* USER CODE BEGIN 2 */
HAL_SPI_Receive_DMA(&hspi1, RX_Buffer, 1); //Receiving in DMA mode
HAL_Delay(100);
/* USER CODE END 2 */
2.5. Compile and flash
2.6. Project workspace
[[category:Getting_started_with_STM32_system_peripherals | 40]]