cancel
Showing results for 
Search instead for 
Did you mean: 

Interrupt SPI Slave Transmit Delayed

EthanMankins
Senior

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

}

 

1 ACCEPTED SOLUTION

Accepted Solutions

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

View solution in original post

8 REPLIES 8
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.

Hello @EthanMankins 

On the slave side in the main function, you are disabling the SPI peripheral just after setting the nFPINT_Pin to hight. 

This will notify the master device to send data when the slave still disabled until EXTIcallback be called. 

To debug more efficiently your issue, please flow try with snippet code below: 

#include "main.h"

volatile uint8_t rxBuffer;
volatile uint8_t txBuffer;

void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_SPI1_Init(void);
void Error_Handler(void);

SPI_HandleTypeDef hspi1;

void SPI_start(void) {
    // Set the value of txBuffer
    txBuffer = 2;

    // Fill the FIFO with the value of txBuffer
    for (int i = 0; i < 16; i++) { // Fill FIFO with 16 bytes of data
        *((__IO uint8_t *)&hspi1.Instance->TXDR) = txBuffer;
    }

    // Set the interrupts and start SPI process
    __HAL_SPI_ENABLE(&hspi1);
    __HAL_SPI_ENABLE_IT(&hspi1, SPI_IT_RXP);
}

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);
            SPI_start();
            HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_SET);
        } else if (HAL_GPIO_ReadPin(nCS_GPIO_Port, nCS_Pin) == GPIO_PIN_SET) {
            __HAL_SPI_DISABLE_IT(&hspi1, SPI_IT_RXP);
            __HAL_SPI_DISABLE(&hspi1);
            __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) {
    if (hspi->Instance->SR & SPI_FLAG_RXP) {
        HAL_GPIO_WritePin(nFPINT_GPIO_Port, nFPINT_Pin, GPIO_PIN_RESET);
        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_SPI1_Init();

    HAL_NVIC_EnableIRQ(SPI1_IRQn);

    while (1) {
        // Main loop
    }
}

On the master side add a while loop in the main function to wait until the nFPINT_Pin is set before starting the transmission. This ensures that the master does not start transmitting until the slave is ready.

The transmission can be triggered and stopped by pressing the EXTI button on slave side.

 

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

Thanks
Omar

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