AnsweredAssumed Answered

Explanation/Problem with HAL_SPI_Receive_DMA() for half duplex.

Question asked by Salieri on Apr 21, 2016
IC: STM32F072CBT6
RTOS: FreeRTOS V8.2.1
IDE: Visual Studio 2015 (Visual GDB)
ST-Link v 2.0

DMA Settings:
hdma_spi1_rx.Instance = DMA1_Channel2;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_spi1_rx);
 
__HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
 
hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_spi1_tx);
 
__HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);

SPI Settings:
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_1LINE;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
HAL_SPI_Init(&hspi1);

I am attempting to initiate a half duplex communication with an external SPI device.

Let me preface by saying HAL_SPI_Transmit_DMA() works beautifully.

I have a problem with HAL_SPI_Receive_DMA(). When attempting to use this function in while SPI1 is configured in 

hspi1.Init.Direction = SPI_DIRECTION_2LINES;

the HAL_SPI_Receive_DMA() jumps into the HAL_SPI_TransmitReceive_DMA(). The issue is that the same buffer that is passed into the Receive only function is passed as a parameter into the TransmitReceive function both as the input and the output buffer. The data received in such a way is corrupted as I cannot receive the expected output.

If I use the  HAL_SPI_TransmitReceive_DMA() directly for receiving, and if I allocate memory for a separate transmit buffer to be passed (the contents of which I don't care for) - then the data I receive is correct. But I do not like this solution - if for nothing else, because I have limited stack memory and cannot afford to have a large memory space allocated unnecessarily.

I have attempted to clear the buffer space using
memset(pBuf, 0x00, len);
before calling the HAL_SPI_Receive_DMA() but this does not seem to have any effect.

When SPI1 is configured:
hspi1.Init.Direction = SPI_DIRECTION_1LINE;

then the next line blocks the execution of the program after a receive attempt (DMA remains forever busy):

while (HAL_DMA_GetState(&hdma_spi1_rx) == HAL_DMA_STATE_BUSY) {}

It is clear to me that I am hitting a brick wall because I seem to misunderstand the SPI peripheral. I have already spent too much time trying to get this to work and I cannot afford to stumble around in the dark.

Outcomes