Skip to main content
Senior
November 20, 2024
Solved

Interrupt SPI Slave Transmit Delayed

I am using a Nucleo-H743ZI as a SPI slave device for the following coms method:

 

Master Pulls SS low, Delay 1ms.
Master Transmit/Receive 1 Byte (Wait for high busy line)
Slave RXP Interrupt-> Lower Busy Line
Slave Transmit/Receive 1 Byte
Slave Process Byte, Set next transmit byte
Slave Raise Busy Line
Master Transmit/Receive 1 Byte
Repeat untilldata is done
Master Raises SS

 

The Master is acting properly and the slave receive is correct; however, the slave transmit is two bytes behind. For now I have hard coded the transmit to send 5. All the data is received correctly by the slave in this time but the slave does not transmit 5 until the third byte is received.


SLAVE SETUP:

 

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_ENABLE;
 hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
 if (HAL_SPI_Init(&hspi1) != HAL_OK)
 {
 Error_Handler();
 }

//MY INIT:
	HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET); //raise /busy line
	__HAL_SPI_DISABLE(&hspi1);
	hspi1.Instance->UDRDR = 0xA5;
	__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
	__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
	__HAL_SPI_CLEAR_FREFLAG(&hspi1);

	__HAL_SPI_DISABLE_IT(&hspi1, SPI_IT_TXP);
	__HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);

	HAL_NVIC_EnableIRQ(SPI1_IRQn);

// /CS handler
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
	if (GPIO_Pin == GPIO_PIN_14) {
		if(HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_RESET){
			__HAL_SPI_DISABLE(&hspi1);
 	__HAL_SPI_ENABLE(&hspi1);
			txBuffer = 0;		//transmit 0 for first byte
		}
	}
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}



void spiISRSTM(SPI_HandleTypeDef *hspi) {
	HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);	//Lower /Busy

	if (hspi->Instance->SR & SPI_FLAG_TXP) {
		(*(__IO uint8_t *)&hspi->Instance->TXDR) = 5;			// transmit
	}

	//Receive if ready
	if (hspi->Instance->SR & SPI_FLAG_RXP) {
 	rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
 	ProcessSPI();										//Process SPI data
	}
	__HAL_SPI_CLEAR_UDRFLAG(hspi);
	__HAL_SPI_CLEAR_OVRFLAG(hspi);
	__HAL_SPI_CLEAR_EOTFLAG(hspi);
	__HAL_SPI_CLEAR_FREFLAG(hspi);

}

 

This topic has been closed for replies.
EthanMankinsBest answer
Senior
November 25, 2024

The issue was an underrun after the first byte. Disabling and reenabling spi after read and before transmit solved the issue.

	sr = hspi->Instance->SR;

	if ((sr & (SPI_FLAG_RXP | SPI_FLAG_TXC)) == (SPI_FLAG_RXP | SPI_FLAG_TXC)) {
		HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);	//Lower nFPINT
		rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
		__HAL_SPI_DISABLE(&hspi1);
		__HAL_SPI_ENABLE(&hspi1);
		pPacketSlave->ProcessSPI();
		(*(__IO uint8_t *)&hspi->Instance->TXDR) = txBuffer;
	}

8 replies

ST Technical Moderator
November 21, 2024

Hello @EthanMankins 

To ensure efficient SPI transmit/receive, you should fill the TX FIFO before enabling TXP and RXP interrupts. Here is a code snippet to guide you:

 

// Initialization code
void SPI_Init(void) {
 // Other initialization code..

 // Fill the TX FIFO before enabling interrupts
 while (__HAL_SPI_GET_FLAG(&hspi, SPI_FLAG_TXP)) {
 // Fill the TX FIFO with data
 *((__IO uint8_t *)&hspi.Instance->TXDR) = *pTxData++;
 }
 // Enable the TXP interrupt
 __HAL_SPI_ENABLE_IT(&hspi, SPI_IT_TXP);
 // Enable the RXP interrupt
 __HAL_SPI_ENABLE_IT(&hspi, SPI_IT_RXP);
 // Enable the SPI
 __HAL_SPI_ENABLE(&hspi);
}

// Interrupt Service Routine (ISR)
void SPI_IRQHandler(void) {
 // Check the TXP flag
 if (__HAL_SPI_GET_FLAG(&hspi, SPI_FLAG_TXP)) {
 // Transmit data
 *((__IO uint8_t *)&hspi.Instance->TXDR) = *pTxData++;
 }

 // Check the RXP flag
 if (__HAL_SPI_GET_FLAG(&hspi, SPI_FLAG_RXP)) {
 // Receive data
 *pRxData++ = *((__IO uint8_t *)&hspi.Instance->RXDR);
 }

 // Other ISR code...
}
In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Senior
November 21, 2024

Hi @Saket_Om ,

I just gave this a shot, and starting with pTxData = 0, it transmits 16, 17, 18... Based on the definition of a FIFO I would have expected it to transmit 0, 1, 2, 3... Why would it start with the last in 16 instead of first in 0?