cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Slave Receiving Every Other Byte

EthanMankins
Senior

I am using STM32H7B3I-DK running a touchgfx application and acting as SPI Master, and Nucleo-H743ZI as SPI Slave. Both are configured in interrupt mode not using HWNSS. 

The Master is sending 0,1,2,3,4,5,6,7, but the slave is only receiving 0,2,4,6,0,2,4,6.

I am sending one byte at a time and receiving one byte then adding it to a buffer. 

The master is properly sending data, as checked by oscilloscope. I have tried introducing a HAL-Delay(1) between transmissions and the data is then received perfectly fine; however, that is way to slow for proper communication. I have double checked the compatible settings for Master-Slave communication in the .ioc files such as Data Size, First Bit, etc...
Here is my following relevant code for the master:

	for(;;)
	{
		HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_RESET);  // Pull CS low
		for (int i = 0; i < 8; i++) {
			data[i] =i;
		    HAL_SPI_Transmit(&hspi2, &data[i], 1, HAL_MAX_DELAY);  // Transmit one byte
		    HAL_UART_Transmit(&huart1, &data[i], 1, 0);

		}
    }

  

Here is the slave code:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_14) {
        if (HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_14) == GPIO_PIN_RESET) {
            HAL_SPI_Receive_IT(&hspi1, &rxBuffer[rxIndex], 1);  		// Start receiving
        }
    }
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
    if ((hspi->Instance == SPI1) && (HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_14) == GPIO_PIN_RESET)) {
        // Process received data
        rxIndex = (rxIndex + 1) % RX_BUFFER_SIZE;
        // Re-enable SPI interrupt for the next byte
        HAL_SPI_Receive_IT(&hspi1, &rxBuffer[rxIndex], 1);
    }
}

[...]

while (1)
  {
	  for (int i = 0; i < 8; i++) {
		  printf("%u ", rxBuffer[i]);
	  }
	  printf("\n\r");
	  HAL_Delay(1000);
  }

 

1 ACCEPTED SOLUTION

Accepted Solutions
gbm
Lead III

Close to impossible with HAL, still hard without.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

View solution in original post

6 REPLIES 6
gbm
Lead III

Typical problem with SPI slave implementation. Either put come delay on master side between NSS low and transmit or call receive on slave side in advance, before NSS is detected active.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

@gbm ,

Thank you for the suggestion, but I have already tried this. And I don't believe this to be the issue because the first byte is received fine. I just tried the following adding in a 1, 10, 100, and 1000ms delay before transmitting after nss low:

		HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_RESET);  // Pull CS low
		HAL_Delay(1000);
		for (int i = 0; i < 8; i++) {
			data[i] =i;
		    HAL_SPI_Transmit(&hspi2, &data[i], 1, HAL_MAX_DELAY);  // Transmit one byte
		    HAL_UART_Transmit(&huart1, &data[i], 1, 0);

		}
		HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_SET);    // Pull CS high
gbm
Lead III

That's really basic - it's not that easy to do SPI slave in an MCU. Call Receive for the whole packet once, not byte by byte. Otherwise you must introduce significant delays between bytes on master side. Also, make sure that you have the same SPI frame size set on both sides.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

@gbm ,
I was hoping to avoid that, as we are trying to use variable packet length. Is there not a way to receive just one byte at a time without the large delay? 

gbm
Lead III

Close to impossible with HAL, still hard without.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Saket_Om
ST Employee

Hello @EthanMankins 

To synchronize SPI communication, you can use a GPIO pin to ensure that the slave receive function is called before the master transmit function, you can follow these steps:

  1. Slave Side:

    • Set the GPIO pin high before calling the receive function.
    • Reset the GPIO pin in the receive complete callback and set a flag rxDataReady.
    • In the main function, check the flag, set the GPIO pin high, reset the flag rxDataReady and call the HAL_SPI_Receive_IT function.
  2. Master Side:

    • Check the GPIO pin state before calling the transmit function.
    • Use a small delay before or after transmitting to ensure proper synchronization.
If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar