cancel
Showing results for 
Search instead for 
Did you mean: 

Why to enable tx dma when only rx dma is needed?

HSagh.1
Associate II

Having faced the same problem, ended up in this thread. This is the same for HAL_SPI_Receive_DMA() as well, because it internally calls the transmitReceive function. So, it made me enable tx dma interrupt as well rx. Why on earth I have to enable tx dma when I just need rx dma? It does not even call the tx complete callback.

My workaround was to:

1-make tx dma interrupt priority higher than rx dma interrupt.

2-poll for tx dma complete in rx interrupt routine before proceeding to next transaction.

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
  handleXferCplt(hspi);
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
  handleXferCplt(hspi);
}

bool handleXferCplt(SPI_HandleTypeDef *hspi)
{
  // stm hal forces to use both tx and rx dma becasue it calls tranmitReceive() internally for receive.
  // however, dma tx transfer complete interrupt comes after rx complete. So, tx dma busy flag is still set and queued
  // sessions cannot proceed. so wait for it to finish. this implies that tx dma priority must be higer than rx dma
  // priority.
  if (HAL_DMA_PollForTransfer(hspi->hdmatx, HAL_DMA_FULL_TRANSFER, 1) != HAL_OK)
  {
    HAL_DMA_Abort(hspi->hdmatx); // Abort the DMA transfer
  }
  ...
  

Edit: moved from the old thread HAL_SPI_TransmitReceive_DMA() transmit interrupt always triggered after receive interrupt. This gives more chance for review and answering.

1 ACCEPTED SOLUTION

Accepted Solutions
HSagh.1
Associate II

Ok. But I went through it again. Still the same. The only way to solve this is to increase tx dma priority, so it can be triggered while in rx dma interrupt routine. ¯\_(ツ)_/¯

Anyway, this solves the problem for me. I just commented it because others have seen the same thing (in the old thread), so I provided my solution.

View solution in original post

6 REPLIES 6
Saket_Om
ST Employee

Hello @HSagh.1 

Could you please precise which MCU product you are working on

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
Danish1
Lead III

The way the SPI peripheral works is that it waits for a byte to be written to the transmit register, then the peripheral clocks it out of the MOSI pin while at the same time clocking data in from the MISO pin. Only once that has completed is the RX byte available to be collected by the RX DMA.

To receive the next byte, again you have to write *something* to the SPI TX register. So to automate SPI RX DMA you have to set up TX DMA as well, even if it is just pumping out the same byte repeatedly.

See the Reference Manual for your stm32 for a more detailed explanation.

And why do you need the TX DMA interrupt? That’s because that’s how the HAL software can know that the TX DMA has completed, so HAL can mark TX DMA as free and available for next time

It's L496

I need to start another spi transation as soon as the current dma rx transaction finishes, from whithin the "HAL_SPI_RxCpltCallback()" interrupt callback. If I do that, it fails with spi busy error, because tx dma always completes after this callback is called. I have to wait untill tx dma finishes, then I can proceed.

Based on your comment, if tx dma is neccessary, then I believe "SPI_DMAReceiveCplt()" or "SPI_DMATransmitReceiveCplt()" must be called on tx dma completion not rx dma completion. So the HAL callback assignments in below are wrong. they must be "hspi->hdmatx->...".

HSagh1_0-1755476622537.png

 

 

Hello @HSagh.1 

I tried to reproduce your issue by calling HAL_SPI_Transmit_DMA() in HAL_SPI_RxCpltCallback() And I cannot reproduce your issue. 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
HSagh.1
Associate II

Ok. But I went through it again. Still the same. The only way to solve this is to increase tx dma priority, so it can be triggered while in rx dma interrupt routine. ¯\_(ツ)_/¯

Anyway, this solves the problem for me. I just commented it because others have seen the same thing (in the old thread), so I provided my solution.