Skip to main content
Graduate II
November 20, 2024
Solved

Interrupt SPI Slave Transmit Delayed

  • November 20, 2024
  • 1 reply
  • 1366 views

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.
    Best answer by EthanMankins

    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;
    	}

    1 reply

    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...
    }
    Graduate II
    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?