2025-08-14 9:23 PM - last edited on 2025-08-15 6:18 AM by Amel NASRI
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.
Solved! Go to Solution.
2025-08-20 4:33 AM
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.
2025-08-15 6:57 AM
Hello @HSagh.1
Could you please precise which MCU product you are working on
2025-08-15 4:34 PM
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
2025-08-17 5:08 PM
It's L496
2025-08-17 5:36 PM
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->...".
2025-08-18 3:58 AM
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.
2025-08-20 4:33 AM
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.