cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Between Two STM32 Boards - Data Not Received

Brian_Azzopardi
Associate III

Hello ST Community,

 

I am trying to set up SPI communication between two STM32 microcontrollers (two NUCLEO-F401RE boards); one as an SPI master and the other as an SPI slave. For now, I am only trying to transmit only one byte (0x61). For this I am using STM32’s HAL Library, and its functions HAL_SPI_Transmit_IT() and HAL_SPI_Receive_IT.

On the slave, the HAL_SPI_RxCpltCallback() and the code inside it (setting a flag) are being executed, meaning that the slave is attempting to receive data sent by the master. However, the data in the SPI receive buffer is always 0x00 (serial terminal shown below; displaying "0" for every SPI receive interrupt occurrence).

 

Termite serial terminal outputting "0" upon every occurance of SPI receive interruptTermite serial terminal outputting "0" upon every occurance of SPI receive interrupt

 

I need to have the master and the slave operating in Full-Duplex Master and Full-Duplex Slave modes respectively (both with interrupts), however, when setting them in Transmit Only Master and Receive Only Slave, and disabling interrupts, for debugging purposes, the same issue persisted.

 

Below are the hardware connections (short wires from one NUCLEO board to another):

 

  • SPI2_SCK on PB10 of NUCLEO-F401RE Board 1 (MASTER) -> SPI2_SCK on PB10 of NUCLEO-F401RE Board 2 (SLAVE)
  • SPI2_MISO on PC2 of NUCLEO-F401RE Board 1 (MASTER) -> SPI2_MISO on PC2 of NUCLEO-F401RE Board 2 (SLAVE)
  • SPI2_MOSI on PC3 of NUCLEO-F401RE Board 1 (MASTER) -> SPI2_MOSI on PC3 of NUCLEO-F401RE Board 2 (SLAVE)
  • GPIO_Output on PA10 of NUCLEO-F401RE Board 1 (MASTER) (controlled through software) -> SPI2_NSS on PB12 of NUCLEO-F401RE Board 2 (SLAVE) – I need this because when I get this to work with one slave, I will move on to a multi-slave system
  • GND of NUCLEO-F401RE Board 1 (MASTER) -> GND of NUCLEO-F401RE Board 2 (SLAVE)

 

Connection diagram of the two NUCLEO-F401RE boardsConnection diagram of the two NUCLEO-F401RE boards

 

Other information related to hardware:

  • NUCLEO-F401RE boards have a Green LED on PA5 which I am using for debugging purposes

 

Code snippets below. I am only showing the user-inputted code, not the auto-generated code.

 

Attached are the Master and Slave configuration settings in STM32CubeIDE Code Configurator.

 

NUCLEO-F401RE Board 1 (MASTER) Code:

 

/* USER CODE BEGIN PV */

/* Private variables */

uint8_t spi_tx_buf[] = "a";	// Data to send... 0x61 or Decimal 97

/* USER CODE END PV */

 

 

In main():

 /* USER CODE BEGIN 2 */

  // Start with green LED OFF
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

  // Slave NSS (PA10) normally high
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);

  HAL_Delay(2000); // Give slave time to prepare...

  /* USER CODE END 2 */

 

In while(1):

  /* USER CODE BEGIN WHILE */
  while (1)
  {

	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);	// Pull slave NSS (PA10) low
//	  HAL_Delay(100);		// No effect
	  HAL_Delay(500);		// No effect
	  HAL_SPI_Transmit_IT(&hspi2, spi_tx_buf, 1); //Sending in Interrupt mode
	  HAL_Delay(100);		// No effect
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);	// Slave NSS (PA10) back high

	  // Blink green LED
	  // LED ON
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
	  HAL_Delay(100);
	  // LED OFF
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

	  HAL_Delay(5000);		// 5s delay before next transmit

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

(In the above code snippet, adding delays right after setting the NSS line low and before setting it bac high, had not effect on the data received by the slave.)

 

NUCLEO-F401RE Board 2 (SLAVE) Code:

 

/* USER CODE BEGIN PV */

/* Private variables */

volatile uint8_t spi_rx_buf[1]; // Data to receive
volatile uint8_t spi_rx_flag = 0;

uint8_t uart_tx_buf[20];

/* USER CODE END PV */

 

In main():

  /* USER CODE BEGIN 2 */

  // Start with green LED off
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

  HAL_SPI_Receive_IT(&hspi2, spi_rx_buf, 1); //Receive in Interrupt mode

  /* USER CODE END 2 */

 

In while(1):

  /* USER CODE BEGIN WHILE */
  while (1)
  {

	  if (spi_rx_flag==1){

		  spi_rx_flag=0;	// Reset flag immediately

		  sprintf((char*)uart_tx_buf, "%u\r\n", spi_rx_buf[0]);
		  HAL_UART_Transmit(&huart2, uart_tx_buf, strlen((char*)uart_tx_buf), 50);

		  // Blink the green LED
		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
		  HAL_Delay(100);
		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

		  HAL_SPI_Receive_IT(&hspi2, spi_rx_buf, 1); // Receive again in interrupt mode

	  }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

SPI ISR:

/* USER CODE BEGIN 4 */

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef * hspi)
{
    // RX Done
	spi_rx_flag = 1;
}

/* USER CODE END 4 */

 

I checked the SCK, MOSI and NSS signals using an oscilloscope, and nothing looks wrong there, so I believe the problem lies within the slave's receiving data code... MOSI and SCK signals shown below and are in synch, with MOSI showing bits for 0x61 one-byte message transmitted by the Master (apologies for the bad image quality, I'll try to update the picture ASAP)... NSS signal has also been verified.

 

Photo of scope showing SCK signal (blue) and MOSI signal (yellow) during transmission of 0x61 single-byte messagePhoto of scope showing SCK signal (blue) and MOSI signal (yellow) during transmission of 0x61 single-byte message

 

I really appreciate your help in getting this very basic code to work. I have been trying various code examples, including from ST WIKI (https://wiki.st.com/stm32mcu/wiki/Getting_started_with_SPI) and still cannot get this board-to-board SPI communication working. I have also tried changing the NUCLEO boards to exclude hardware malfunctions, and switching from SPI2 to SPI3 peripherals.

 

Thanks!

 

Brian

Brian

RSO (RDI) at the University of Malta Department of Electronic Systems Engineering
8 REPLIES 8

Never a great idea to try to do both ends of a link at the same time.

https://community.st.com/t5/stm32-mcus-products/two-nucleo-boards-stm32f446re-and-stm32h723zg-communicate/m-p/737695/highlight/true#M264992

 

Have you looked at the SPI lines using a scope and/or logic analyser to see what (if anything) is happening?

 


@Brian_Azzopardi wrote:

Below are the hardware connections (short wires from one NUCLEO board to another):


It's a lot easier to show connections as a diagram, rather than text.

Hand-drawn or ASCII-art is fine ...

 

PS:

 


@Brian_Azzopardi wrote:

NUCLEO-F401RE boards


Have you checked that the pins you're using are not occupied by anything else on the boards?

TDK
Guru

You should make spi_rx_buf and spi_rx_flag volatile as they are modified within an interrupt and read by the main thread. Perhaps also initialize spi_rx_buf with nonzero data so you know if something got written. 0xAA is a good initial value to use.

I doubt that fixes it but I can't see anything else that might be wrong, given that you've verified the signals.

If you feel a post has answered your question, please click "Accept as Solution".

Hi @Andrew Neil, thanks for your comments.

 


@Andrew Neil wrote:

Never a great idea to try to do both ends of a link at the same time.

https://community.st.com/t5/stm32-mcus-products/two-nucleo-boards-stm32f446re-and-stm32h723zg-communicate/m-p/737695/highlight/true#M264992


You're right. But given that I had previously used the functions HAL_SPI_Transmit_IT() and HAL_SPI_Receive_IT on an identical NUCLEO-F401RE board without any problems, I thought that implementing them to communicate with another STM32 board instead of SPI device such as an IMU, would be straight-forward. Moreover, scope shows correct bits for the single-byte message 0x61 the Master is transmitting (and is correctly synched with SCK), so master appears to be transmitting fine.

I'll have a look at the link you shared; thanks.

 

 

 

 


@Brian_Azzopardi wrote:

Below are the hardware connections (short wires from one NUCLEO board to another):


It's a lot easier to show connections as a diagram, rather than text.

Hand-drawn or ASCII-art is fine ...

I have drawn a diagram and included it in my original post... Thanks for suggesting!

 

 

PS:

 


@Brian_Azzopardi wrote:

NUCLEO-F401RE boards


Have you checked that the pins you're using are not occupied by anything else on the boards?


Will re-check this to make sure.

 

Thanks again @Andrew Neil . Will check the above and post an update.

Brian

RSO (RDI) at the University of Malta Department of Electronic Systems Engineering

Hi @TDK , thanks for your reply.

 


@TDK wrote:

You should make spi_rx_buf and spi_rx_flag volatile as they are modified within an interrupt and read by the main thread.


Will do, thanks for pointing out. 

 


@TDK wrote:

Perhaps also initialize spi_rx_buf with nonzero data so you know if something got written. 0xAA is a good initial value to use.


Good idea, will try this out too.

 

Thanks again!

Brian

RSO (RDI) at the University of Malta Department of Electronic Systems Engineering

PS:

 


@Brian_Azzopardi wrote:

NUCLEO-F401RE boards


Have you checked that the pins you're using are not occupied by anything else on the boards?


Will re-check this to make sure.


Update: This has been checked. Pins being used are not occupied by anything else.

Brian

RSO (RDI) at the University of Malta Department of Electronic Systems Engineering

Hi @TDK ,

 

I have initialized spi_rx_buf with the value 0xAA and placed a breakpoint in while(1), within the if (spi_rx_flag==1) statement. Recall that spi_rx_flag is set to 1 in the SPI RX callback.

 

The value of spi_rx_buf is changing to 0x00, confirming that the SPI RX callback is being executed, and that 0x00 is being written to the buffer spi_rx_buf.

 

Breakpoint debugging and spi_rx_buf whose value is changing from 0xAA to 0x00Breakpoint debugging and spi_rx_buf whose value is changing from 0xAA to 0x00

 

Could it be that the MOSI signal is not being sampled right, i.e. it is being sampled when the line is low, and thus resulting in a 0x00 value?

 

Brian

 

Brian

RSO (RDI) at the University of Malta Department of Electronic Systems Engineering

> Could it be that the MOSI signal is not being sampled right, i.e. it is being sampled when the line is low, and thus resulting in a 0x00 value?

Unlikely. You'd still see 1's in there somewhere.

 

You're missing a ground connection between the two boards.

 

You could connect MOSI on the slave board to MISO on the master slave board and ensure it receives what it sends. Will require some minor code changes.

If you feel a post has answered your question, please click "Accept as Solution".

Thanks for your reply @TDK 

 


You're missing a ground connection between the two boards.


The grounds of the two boards were actually connected but left out from the connections description / diagram by mistake. Connections diagram updated.

 


You could connect MOSI on the slave board to MISO on the master slave board and ensure it receives what it sends. Will require some minor code changes.


I did a simple loopback test. Slave board set at Master, with MISO directly connected to MOSI of same board. Once again, content of spi_rx_buf being set to 0x00. Both when using and not using interrupts for receiving. Scope showed that signal on MOSI (and thus MISO) pins was present. Tried doing this with both SPI2 and SPI3 modules. On the NUCLEO-F401RE board, SPI2 and SPI3 are connected to the APB1 peripheral clock (42 MHz). Prescaler was set to 256.

 

I am now thinking of implementing SPI without the HAL Libraries, at least for the slave for now.

Brian

RSO (RDI) at the University of Malta Department of Electronic Systems Engineering