cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Interrupt Driven Slave Receive Error

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 1,2,3,4,5,6,7,8 but the slave is receiving random numbers

I am sending one byte at a time and receiving one byte then adding it to a buffer. I want to avoid HAL overhead as much as possible as the data needs to be close to real time. 

The Master seems to send quickly enough using HAL_SPI_Transmit; however, the slave would only receive every other byte, hence the avoidance of HAL on the Slave side.

The master is properly sending data, as checked by oscilloscope. 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:

 

  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 0x0;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
  hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }

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

		}
		HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_SET);    // Pull CS high
		HAL_Delay(100);
    }

 

 

Here is the relevant Slave code:

 

  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.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x0;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

[...]

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_ENABLE(&hspi1);
        	__HAL_SPI_DISABLE_IT(&hspi1, (SPI_IT_TXP | SPI_IT_DXP | SPI_IT_EOT | SPI_IT_TXTF | SPI_IT_UDR | SPI_IT_OVR | SPI_IT_CRCERR | SPI_IT_FRE | SPI_IT_MODF | SPI_IT_TSERF | SPI_IT_ERR));
        	__HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);
        }
    }
}


void spiISR(SPI_HandleTypeDef *hspi){
	if (hspi1.Instance->SR & SPI_FLAG_RXP) {

		rxBuffer[rxIndex] = SPI1->RXDR;
		// Increment index and wrap around if necessary
		rxIndex = (rxIndex + 1) % RX_BUFFER_SIZE;
		__HAL_SPI_CLEAR_EOTFLAG(hspi);
		__HAL_SPI_CLEAR_OVRFLAG(hspi);
		__HAL_SPI_CLEAR_FREFLAG(hspi);
	}
}

 

In stm32h7xx_it.c I do the following in the SPI_IRQHandler to avoid calling the large HAL_SPI_IRQHandler :

 

void SPI1_IRQHandler(void)
{
  /* USER CODE BEGIN SPI1_IRQn 0 */
	spiISR(&hspi1);
	return;
  /* USER CODE END SPI1_IRQn 0 */
  HAL_SPI_IRQHandler(&hspi1);
  /* USER CODE BEGIN SPI1_IRQn 1 */

  /* USER CODE END SPI1_IRQn 1 */
}

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

The issue was likely because of noise. 

FIX: Twisted all com wires tightly: GND SCK MOSI MISO NSS 

View solution in original post

7 REPLIES 7
Pavel A.
Evangelist III

Have you seen the examples for slave mode in the STM32H7Cube library package? (under Projects dir.)

@Pavel A. 

I have only seen "SPI_FullDuplex_ComIT" which uses the HAL library calls to transmit and receive. I believe I have taken the necessary parts of the HAL functions, Enable() and flag clearing. However, it seems there may be more that I am missing to implement a very basic and quick version of the HAL functions... 

Hi,

Your code would indicate that the NSS timing is not right. I don't know what you have been looking at on your oscilloscope...

Kind regards
Pedro

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.

Look for examples for similar H7 boards, not just for the Nucleo-H743ZI. IIRC there is an example of two SPIs on same board, one acting as master another as slave. The latter can be useful.

I recently got it working yesterday by making sure my buffer was volatile. I tested multiple times and it worked great; however, this morning I tried again now it is showing random numbers again... I did not change anything. The NSS is getting pulled low 6us before the data is sent. I believe that should be enough time

@Pavel A. @PGump.1 

I have just found that it seems the code is actually fine, and that it is something hardware related. When I measure SCK with an oscilloscope everything works perfect, but as soon as the probe is removed from SCK random numbers appear. This is true whenever the probe is attached to sck even when it is not connected to the scope. Any Ideas?

The issue was likely because of noise. 

FIX: Twisted all com wires tightly: GND SCK MOSI MISO NSS