Skip to main content
Visitor II
August 15, 2025
Solved

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

  • August 15, 2025
  • 3 replies
  • 730 views

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.

    This topic has been closed for replies.
    Best answer by HSagh.1

    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.

    3 replies

    Technical Moderator
    August 15, 2025

    Hello @HSagh.1 

    Could you please precise which MCU product you are working on

    HSagh.1Author
    Visitor II
    August 18, 2025

    It's L496

    Graduate
    August 15, 2025

    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

    HSagh.1Author
    Visitor II
    August 18, 2025

    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

     

     

    Technical Moderator
    August 18, 2025

    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. 

    HSagh.1AuthorAnswer
    Visitor II
    August 20, 2025

    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.