cancel
Showing results for 
Search instead for 
Did you mean: 

Interrupt SPI Slave Transmit Delayed

EthanMankins
Associate III

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

}

 

6 REPLIES 6
Saket_Om
ST Employee

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...
}
If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

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?

@Saket_Om I have found that filling the buffer does not effect the operation. The same issue persists

Hello @EthanMankins 

Could you please share the complete code for both the master and slave devices, including the main function, so that we can assist you more efficiently?

Could you please check with the HAL API to see if it works fine for your application? If it does, you can use it as inspiration to customize your SPI functions.

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

SLAVE:

  /* 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.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();
  }
HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
__HAL_SPI_DISABLE(&hspi1);
hspi1.Instance->UDRDR = 0xA5;
__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
__HAL_SPI_CLEAR_FREFLAG(&hspi1);

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_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);
			txBuffer = 2;
		    *((__IO uint8_t *)&hspi1.Instance->TXDR) = txBuffer;
		    __HAL_SPI_ENABLE(&hspi1);
			__HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);

			HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
		}


		if(HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_SET){
			__HAL_SPI_DISABLE_IT(&hspi1, SPI_IT_RXP);
			__HAL_SPI_DISABLE(&hspi1);
			hspi1.Instance->UDRDR = 0xA5;
			__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
			__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
			__HAL_SPI_CLEAR_FREFLAG(&hspi1);
		}
	}
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}

void spiISRSTM(SPI_HandleTypeDef *hspi) {
	//Receive if ready
	if (hspi->Instance->SR & SPI_FLAG_RXP) {
		HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);	//Lower nFPINT
    	rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);

    	(*(__IO uint8_t *)&hspi->Instance->TXDR) = 1;
    	HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
	}
	__HAL_SPI_CLEAR_UDRFLAG(hspi);
	__HAL_SPI_CLEAR_OVRFLAG(hspi);
	__HAL_SPI_CLEAR_EOTFLAG(hspi);
	__HAL_SPI_CLEAR_FREFLAG(hspi);

}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_USART2_UART_Init();
  MX_SPI1_Init();
  MX_TIM2_Init();
	HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
	__HAL_SPI_DISABLE(&hspi1);
	hspi1.Instance->UDRDR = 0xA5;
	__HAL_SPI_CLEAR_OVRFLAG(&hspi1);
	__HAL_SPI_CLEAR_EOTFLAG(&hspi1);
	__HAL_SPI_CLEAR_FREFLAG(&hspi1);

	HAL_NVIC_EnableIRQ(SPI1_IRQn);

  while (1)
  {

  }

}

 

 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();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
	__HAL_SPI_ENABLE(&hspi2);


	HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_RESET);  			// Pull CS low
	HAL_Delay(1);

    while(nOutputByte != -1)
    {
    	int nReceiveByte = STM_SPI_Xmit(&hspi2, nOutputByte);
    	nOutputByte = SpiISR_Packet(NULL, (DWORD)this, nReceiveByte);           //delay untilnFPINT line is high
    }
	HAL_GPIO_WritePin(GPIOI, GPIO_PIN_0, GPIO_PIN_SET);   	 		// Pull CS high

volatile uint8_t rxBuffer;
volatile uint8_t txBuffer;

volatile uint8_t byteRd = 0;
volatile uint8_t byteXd = 0;

int STM_SPI_Xmit(SPI_HandleTypeDef *hspi, int nOutputByte){
	txBuffer = (uint8_t) nOutputByte;
	__HAL_SPI_ENABLE(hspi);
	__HAL_SPI_ENABLE_IT(hspi, SPI_IT_TXP);		// Enable TXP untill byte is sent


	while(!byteXd){}
	byteXd = 0;											// Clear byte is sent flag

	while (!byteRd){}									// Poll while no byte is Received
	byteRd = 0;

	return (int) rxBuffer;
}

void spiISRSTM(SPI_HandleTypeDef *hspi) {

	if (hspi->Instance->SR & SPI_FLAG_TXP) {
		SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);					// start SPI master
		(*(__IO uint8_t *)&hspi->Instance->TXDR) = txBuffer;			// transmit
		__HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXP);							// disable TXP
		while(!__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXC)){}
//		printf("|%u ", (uint8_t)txBuffer);
		byteXd = 1;
	}

	//Receive if ready
	if (hspi->Instance->SR & SPI_FLAG_RXP) {
    	rxBuffer = (*(__IO uint8_t *)&hspi->Instance->RXDR);
//    	printf("%u|", (uint8_t)rxBuffer);
    	byteRd = 1;
    	__HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXP);
	}

	__HAL_SPI_DISABLE(hspi);
	__HAL_SPI_CLEAR_UDRFLAG(hspi);
	__HAL_SPI_CLEAR_OVRFLAG(hspi);
	__HAL_SPI_CLEAR_EOTFLAG(hspi);
	__HAL_SPI_CLEAR_FREFLAG(hspi);
}

I have tire the HALAPI however, I could not get it to work with transferring one byte at a time and was told it would likely not work with HALAPI.