cancel
Showing results for 
Search instead for 
Did you mean: 

Byte loss in DMA based SPI slave implementation

gota
Associate II

We are using STM32L475RE as SPI slave and TI based DSP as master. We are operating the SPI at 1Mhz clock frequency.

We are seeing intermittent data loss in the transmission when data size is high. We observed that the HAL_SPI_TransmitReceive_DMA call is intermittently being stopped in SPI_WaitFlagStateUntilTimeout function checking BUSY flag and we assume this might be a possible reason for data loss.

The reference manual suggests that using BSY flag to find receive/transfer complete is not a reliable method for slave implementation. We have tried comparing RXNE and TXE in place of BSY flag but the data was getting corrupted.

Are we missing something or using HAL in the way it is not intended to be used.

Could you please suggest a better method for using HAL or a workaround for high speed SPI slave implementation? 

Thanks in advance.

Addition details related to implementation:

We are configuring DMA1 channel 4 and 5 to fill SPI Rx and Tx FIFO respectively and reading SPI data from master 4 bytes at a time.

The data is sent from slave to master by adding data to the Tx buffer and then passing interrupt to master to fetch the data.

#define SPI_MIN_RX_TX_DATA_SIZE 4
 
uint8_t g_DSPTXDataBuffer[SPI_TX_DATA_QUEUE_SIZE] = {0x00};
uint8_t g_DSPRXDataBuffer[SPI_RX_DATA_QUEUE_SIZE] = {0x00};
uint32_t g_DSPRXDataBufferStartIndex = 0;
uint32_t g_DSPRXDataBufferEndIndex = 0;
 
SPI_HandleTypeDef g_SpiHandler;
 
bool SPIInit()
{
	g_SpiHandler.Instance = SP2;
	g_SpiHandler.Init.Mode = SPI_MODE_SLAVE;
	g_SpiHandler.Init.Direction = SPI_DIRECTION_2LINES;
	g_SpiHandler.Init.CLKPhase = SPI_PHASE_2EDGE;
	g_SpiHandler.Init.CLKPolarity = SPI_POLARITY_LOW;
	g_SpiHandler.Init.DataSize = SPI_DATASIZE_8BIT;
	g_SpiHandler.Init.FirstBit = SPI_FIRSTBIT_MSB;
	g_SpiHandler.Init.TIMode = SPI_TIMODE_DISABLE;
 
	g_SpiHandler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
	g_SpiHandler.Init.CRCPolynomial = 7;
	g_SpiHandler.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
	g_SpiHandler.Init.NSS = SPI_NSS_HARD_INPUT;
	g_SpiHandler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
 
	if (HAL_SPI_Init(&g_SpiHandler) != HAL_OK)
	{
		return false;
	}
 
	if(HAL_SPI_TransmitReceive_DMA(&g_SpiHandler, g_DSPTXDataBuffer, &g_DSPRXDataBuffer[g_DSPRXDataBufferStartIndex], SPI_MIN_RX_TX_DATA_SIZE) != HAL_OK)
	{
		return false;
	}
return true;
}
 
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
 
	if(hspi->Instance == SPI2)
	{
		/* Peripheral clock enable */
		__HAL_RCC_SPI2_CLK_ENABLE();
		__HAL_RCC_GPIOB_CLK_ENABLE();
	        __HAL_RCC_DMA1_CLK_ENABLE();
 
		GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
		/*DMA initialization.....................................................*/
		/*Rx initialization*/
		g_DspSpiRxDma.Instance = DMA1_Channel4;
		g_DspSpiRxDma.Init.Request = DMA_REQUEST_1;
		g_DspSpiRxDma.Init.Direction = DMA_PERIPH_TO_MEMORY;
		g_DspSpiRxDma.Init.PeriphInc = DMA_PINC_DISABLE;
		g_DspSpiRxDma.Init.MemInc = DMA_MINC_ENABLE;
		g_DspSpiRxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
		g_DspSpiRxDma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
		g_DspSpiRxDma.Init.Mode = DMA_NORMAL;
		g_DspSpiRxDma.Init.Priority = DMA_PRIORITY_LOW;
		if (HAL_DMA_Init(&g_DspSpiRxDma) != HAL_OK)
		{
			Error_Handler();
		}
	    __HAL_LINKDMA(hspi,hdmarx,g_DspSpiRxDma);
		/*Tx initialization*/
	    g_DspSpiTxDma.Instance = DMA1_Channel5;
	    g_DspSpiTxDma.Init.Request = DMA_REQUEST_1;
	    g_DspSpiTxDma.Init.Direction = DMA_MEMORY_TO_PERIPH;
	    g_DspSpiTxDma.Init.PeriphInc = DMA_PINC_DISABLE;
	    g_DspSpiTxDma.Init.MemInc = DMA_MINC_ENABLE;
	    g_DspSpiTxDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	    g_DspSpiTxDma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	    g_DspSpiTxDma.Init.Mode = DMA_NORMAL;
	    g_DspSpiTxDma.Init.Priority = DMA_PRIORITY_LOW;
	    if (HAL_DMA_Init(&g_DspSpiTxDma) != HAL_OK)
	    {
	      Error_Handler();
	    }
	    __HAL_LINKDMA(hspi,hdmatx,g_DspSpiTxDma);
 
	    /* DMA interrupt init */
	    /* DMA1_Channel4_IRQn interrupt configuration */
	    HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 6, 0);
	    HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
	    /* DMA1_Channel5_IRQn interrupt configuration */
	    HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 6, 1);
	    HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
	}
}
 
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if(hspi->Instance == g_SpiHandler.Instance)
	{
		g_DSPRXDataBufferStartIndex += SPI_MIN_RX_TX_DATA_SIZE;
		g_BytesReceived_1 +=SPI_MIN_RX_TX_DATA_SIZE;
		if(g_DSPRXDataBufferStartIndex >= SPI_RECEIVED_DATA_QUEUE_SIZE)
		{
			g_DSPRXDataBufferStartIndex = g_DSPRXDataBufferStartIndex - SPI_RECEIVED_DATA_QUEUE_SIZE;
		}
 
		HAL_StatusTypeDef res = HAL_SPI_TransmitReceive_DMA(&g_SpiHandler[DSP_SPI], g_DSPTXDataBuffer, &g_DSPRXDataBuffer[g_DSPRXDataBufferStartIndex], SPI_MIN_RX_TX_DATA_SIZE);
	}
}
 
bool SPIWrite(uint8_t* a_data, uint32_t a_size)
{
	for(uint32_t i = 0; i < a_size ; i++)
	{
		g_DSPTXDataBuffer[i] = a_data[i];
	}
	return true;
}

0 REPLIES 0