cancel
Showing results for 
Search instead for 
Did you mean: 

Inconsistent HAL_SPI_TransmitReceive Errors

RrW1
Associate III

I am running a simple SPI transmit receive project with an STM32F411 (SPI Master) and STM32F303 (SPI Slave). Whenever I press the user push button on the STM32F4 Master, the Master will send a command byte (0xE1) through SPI and the STM32F3 Slave is expected to respond with 4 particular bytes. The snapshot of the logic analyzer below is what I expect to happen every single push button:

0693W000001tGAzQAM.png

I could probably get the accurate SPI transaction above several times. However, most of the time, the snapshot below is what occurs:

0693W000001tGB9QAM.png

0693W000001tGBJQA2.png

0693W000001tGBTQA2.png

After running through many tests, I am almost certain that the Slave is the issue because:

  • The Master almost all the time transmits the correct data observed through the Logic Analyzer
  • The STM32F3 Slave actually receives the correct data (the command byte and the 4 dummy bytes)

What is strange is that I use:

/* Exchange 4 bytes with SPI Master and store dummy bytes in pTempRxBuff */
HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)pTxBuff, (uint8_t*)pTempRxBuff, cTxLen, 10000);

and receive part is working properly but the transmit part is not working properly.

I made sure that the CPOL, CPHA, MSB bit first, Baudrate Prescaler, APB2 clock speeds (on both STM32 boards), 8 bit datasize, and SPI Direction 2 Lines are the same between both boards.

I also configured the STM32F4 Master to run at 16MHz, while the STM32F3 Slave to run at 64MHz (with PLL) in hopes that the slave can process the data faster and be ready before the Master device clocks the SPI to retrieve the 4 bytes from the slave. It did not work as expected.

My main issue:

STM32F3 Slave does not send the right data most of the time (usually of by 1 bit in some of the bytes that are transmitted).

My SPI Slave (STM32F303) code:

This is my initialization code:

static void MX_SPI1_Init(void)
{
   /* SPI1 parameter configuration*/
   hspi1.Instance = SPI1;
   hspi1.Init.Mode = SPI_MODE_SLAVE;
   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
   hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
   hspi1.Init.NSS = SPI_NSS_SOFT;
      hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;     // Recently added
   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
   hspi1.Init.CRCPolynomial = 7;
   hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
   hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
   if (HAL_SPI_Init(&hspi1) != HAL_OK)
   {
      Error_Handler();
   }
  
   /* Set spi interrupt priority and enable spi interrupts */
   HAL_NVIC_SetPriority(SPI1_IRQn, 1, 1);
   HAL_NVIC_EnableIRQ(SPI1_IRQn);
}

The data that I am sending:

#define RX_COMMAND_LENGTH		1
#define TX_LENGTH			4
 
static uint16_t cRxCmdLen = RX_COMMAND_LENGTH;
static uint16_t cTxLen = TX_LENGTH;
 
/* SPI Receive variables */
/* Command byte received to be stored in pRxBuff */
static volatile uint8_t pRxBuff[RX_COMMAND_LENGTH] = {0x00};
/* 4 dummy bytes to be stored in pTempRxBuff */
static uint8_t pTempRxBuff[TX_LENGTH] = {0x00, 0x00, 0x00, 0x00};
 
/* SPI Send variables */
/* temporary dummy value to be exchanged with the command byte */
static const uint8_t dummybyte[1] = {0x99};
/* 4 bytes to be sent to the Master */
static const uint8_t pTxBuff[TX_LENGTH] = {0xEB, 0x00, 0xCC, 0x01};
 
/* Exchange message flag for processing in main while loop */
volatile FlagStatus ExchangeMessage = RESET;

The SPI interrupt handler:

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
   /* SPI1 peripheral used to exchange data with master device */
   if(hspi->Instance == SPI1)
   {
      /* If command byte received is 0xE1 */
      if(pRxBuff[0] == 0xE1)
      {
         /* Set volatile flag to high for processing 4 byte exchange in main loop */
	 ExchangeMessage = SET;
      }
      else
      {
         /* Ignore garbage data that was received */
 
         /* Configure microcontroller to listen to other command bytes */
	 HAL_SPI_TransmitReceive_IT(&hspi1, (uint8_t*)dummybyte, (uint8_t*)pRxBuff, cRxCmdLen);
      }				
   }
}

The main while loop:

while (1) {
   if(ExchangeMessage == SET) {
      /* Exchange 4 bytes with the master device */	
      HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)pTxBuff, (uint8_t*)pTempRxBuff, cTxLen, 10000);
      
      /* Reset volatile flag - this gets activated when a correct command byte is received*/
      ExchangeMessage = RESET;
 
      /* Configure microcontroller to start listening to command bytes again */
      HAL_SPI_TransmitReceive_IT(&hspi1, (uint8_t*)dummybyte, (uint8_t*)pRxBuff, cRxCmdLen);
   }
}

My SPI Master (STM32F411) Code:

Main while loop:

while (1) {
   /* SendCmdByte is SET whenever a GPIO interrupt (push button) fires */
   if(SendCmdByte == SET) {
      /* Transmit first command byte 0xE1 */
      uint8_t garbage[1] = {0x00};       // buffer for garbage value - expected: 0x99
      HAL_SPI_Transmit(&hspi1, (uint8_t*)pTxBuff, cTxLen, spi_timeout);	
			
      /* Wait for end of spi transmission */
      while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
 
      /* use i<150 for ~100 us delay to wait for slave to fill data*/
      for(volatile uint16_t i=0; i<100; i++);
			
      /* Transmit remaining 4 bytes of dummy value */
      HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)pTempTxBuff, (uint8_t*)pRxBuff, cRxLen, spi_timeout);
			
      /* Toggle LED after successfully exchanging bytes with dongle */
      ToggleLed();
			
      /* Reset received buffer values */
      pRxBuff[0] = 0x00;
      pRxBuff[1] = 0x00;
      pRxBuff[2] = 0x00;
      pRxBuff[3] = 0x00;
			
      /* Reset volatile flag - this flag will be SET at every GPIO push button interrupt */
      SendCmdByte = RESET;
   }
}

My attempts at the problem:

  • I have tried using all the GPIO pin speeds (FREQ_HIGH, FREQ_MEDIUM, FREQ_LOW) for the associated SPI pins on both master and slave and it did not have any effect on the data
  • I have tried reducing the APB2 bus speed and increasing the SPI baudrate for even lower SPI speeds but it did not help with the inaccuracy
  • I have tried the register approach and it somehow only works on the first try but does not work on every other tries after that first test
  • I varied the spi_timeout parameter in the HAL_SPI_TransmitReceive() function and it helped with the shifted byte but the inaccurate bits still persist
  • I also tried using the finite state machine approach on the function HAL_SPI_TxRxCpltCallback() but I could not get it to execute at the second HAL_SPI_TransmitReceive_IT() but the callback does not get executed at the second interrupt (programmed for the 4 byte exchanged)

What could be the problem here? Am I missing something with the SPI transaction? How do I solve this sync issue?

Any help would be greatly appreciated. Thank you!

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

It looks like the CPHA setting on your logic analyzer doesn't match the CPHA setting on your device. The waveforms are the same.

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

View solution in original post

4 REPLIES 4
TDK
Guru

It looks like the CPHA setting on your logic analyzer doesn't match the CPHA setting on your device. The waveforms are the same.

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

I don't know how I missed this. I was too focused on the code that I forgot to consider how the logic analyzer configuration might be incorrect itself. Thank you for the solution!

Both of the code's configuration was CPOL = 0 and CPHA = 1 (2nd edge), but the logic analyzer was configured to CPOL = 0 and CPHA = 0. I am reading the correct waveforms now.

I do have a question regarding the logic analyzer's readings though. Why is it that when the logic analyzer is configured to CPOL = 0 and CPHA = 0, the readings are always different? I would imagine that if the configuration is wrong, the waveforms produced would be wrong but it would show the same incorrect data all the time.

There is always some jitter in the signal. The logic analyzer significantly simplifies the waveform. Remember there’s a finite rise time and overshoot/undershoot. If your SCK was delayed relative to the data lines, the behavior would be consistent, but if you’re right on the threshold, results will vary. It also depends how the logic analyzer treats data in which SCK transition at the exact same time as MOSI.
If you feel a post has answered your question, please click "Accept as Solution".
RrW1
Associate III

I think I have a better understanding of the issue now. Thanks for the explanation!