Skip to main content
Nickelgrass
Senior
February 4, 2026
Solved

SPI DMA transmit complete interrupt to early

  • February 4, 2026
  • 4 replies
  • 308 views

Hello,

I have an STM32G441 and using DMA to transmit some SPI data. All works so far. The problem is the chipselect. I am using the software chipselect. So before I start the DMA I pull CS low. Then when the DMA complete interrupt fires I pull it high again. The problem is, it cuts off about 3 or 4 bytes. This is obvious because the DMA is done while there is still SPI data in the buffer. 

What is the go-to solution for this? How can I reliably get an interrupt when the DMA is done and the SPI is done transmitting all data? At the moment I simply start a timer when the DMA is done that triggers a second interrupt after a certain time that I measure with a logic analyzer. Seems a bit makeshift and has to be adjusted each time the baudrate is changed. I also noticed that all the SPI interrupts fire premature. So is it the only solution to waste a timer on the SPI?

Best answer by waclawek.jan

Handle the CS in the Rx DMA interrupt. That won't happen before all data are shifted out, too (there's a marginal hazard with certain CPOL/CPHA combinations but that often can be solved by relatively simple delays; or use other CPOL/CPHA combination).

It doesn't matter that you don't need Rx. You can DMA into a "dummy" single memory address (i.e. no memory increment), and you don't need to assign any pin in GPIO to it. This is just to provide the timing.

JW

4 replies

TDK
Super User
February 4, 2026

You could use the HAL library which handles this correctly. Set CS high in the transmit complete callback.

If you want to do it yourself, you will need to poll the BSY flag to determine when the transfer is complete. The reference manual discusses this in some detail.

TDK_0-1770227148567.png

It's not an elegant or efficient solution, but that is what is available on this chip. Later families have better handling of the CS line and better ways to do this without polling.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Andrei Chichak
Lead
February 4, 2026

Assume that the DMA complete interrupt happens when the DMA is complete. The SPI device transmit register got loaded and is in the process of shifting out the data, but the DMA is done, and DMA likely deposited a 32-bit pile of data, say, 3 or 4 bytes. DMA done, SPI busy.

You'll have to query the SPI device to determine when it is finished shifting out/in the data.

waclawek.jan
waclawek.janBest answer
Super User
February 5, 2026

Handle the CS in the Rx DMA interrupt. That won't happen before all data are shifted out, too (there's a marginal hazard with certain CPOL/CPHA combinations but that often can be solved by relatively simple delays; or use other CPOL/CPHA combination).

It doesn't matter that you don't need Rx. You can DMA into a "dummy" single memory address (i.e. no memory increment), and you don't need to assign any pin in GPIO to it. This is just to provide the timing.

JW

Nickelgrass
Senior
February 5, 2026

Thanks, that's a nifty solution. Although it does sacrifice a DMA channel. But that is not so expensive as a timer as I don't need many DMAs. I will check it out and report the result. 

waclawek.jan
Super User
February 7, 2026

Try to use the other CPHA setting, i.e. if you've used mode 0 (CPOL=0, CPHA=0), try mode 3 (CPOL=1, CPHA=1).

This may or may not suit your slaves' requirements, though.

JW