Showing results for 
Search instead for 
Did you mean: 

DMA interrupts don't work

Associate II

Microcontroller STM32F401. The DMA controller transfers data from memory to the DR register of the SPI interface. With the HTIE and TCIE bits set, DMA is not included in the interrupt handler. At the end of the data array transfer, the program freezes, there is no interruption in half of the packet, and DMA is not included in the void DMA2_Stream5_IRQHandler(void) function.

Initializing DMA:

void DMA2_Init(void) {
   DMA2_Stream5->M0AR |= (uint32_t)(&data);
   DMA2_Stream5->PAR |= (uint32_t)(&SPI1->DR); 
   DMA2_Stream5->NDTR = 57600;
   DMA2_Stream5->CR |= DMA_SxCR_MSIZE_0;
   DMA2_Stream5->CR |= DMA_SxCR_PSIZE_0; 
   DMA2_Stream5->CR |= DMA_SxCR_CHSEL_1 |
   DMA2_Stream5->CR |= DMA_SxCR_DIR_0;
   DMA2_Stream5->CR |= DMA_SxCR_TCIE;
   DMA2_Stream5->CR |= DMA_SxCR_HTIE;
   DMA2_Stream5->CR |= DMA_SxCR_EN;

Interrupt Handler:

void DMA2_Stream5_IRQHandler(void) {


Read out and check content of the DMA2_Stream5 registers, and mainly the respective status bits in the DMA2_HISR registers.

Other than that, debug as usually with interrupts, some hints are here.


Chief II

For posting code use "Code Snippet" button...


You are not waiting the required peripheral clock cycles after enabling it's clock. Read the RM0410 section "5.2.12 Peripheral clock enable register (RCC_AHBxENR, RCC_APBxENRy)".

But here the fun starts... I looked at F4, F2 and F1 reference manuals and none of them have such a section. On the other hand F7 and L4 has such sections. I doubt the internal design differs...

@Community member​, @Community member​, can you comment?

@Amel NASRI​, if my guess is true, the reference manuals should be checked and updated for all STM32 series.

Pavel A.
Evangelist III

> At the end of the data array transfer, the program freezes

When it freezes: can you break in the debugger? Is it spinning in exception or interrupt handler?

> I looked at F4, F2 and F1 reference manuals and none of them have such a section.

Look into the respective erratas.


Indeed they are in errata. ST should decide if it's a bug or a design peculiarity and move them all either to the reference manual or errata.

"2.1.6 Delay after an RCC peripheral clock enabling"


1. Use the DSB instruction to stall the Cortex®-M4 CPU pipeline until the instruction is completed.

2. Insert “n�? NOPs between the RCC enable bit write and the peripheral register writes (n = 2 for AHB peripherals, n = 1 + AHB/APB prescaler in case of APB peripherals).

3. Or simply insert a dummy read operation from the corresponding register just after enabling the peripheral clock.

The workarounds also seem suspicious. A single DSB with a single CPU clock cycle is definitely not enough for slower APB peripherals and probably even for AHB ones. NOPs without RCC register read-back before them? A dummy read of the "corresponding" register - do they mean RCC register or a register of the peripheral for which one is enabling the clock? And a single read, not two reads?

To me this seems to be the minimal fully correct solution:

// Add code, which waits for 2 peripheral clock cycles, here.

Even if I add a delay, it doesn't change anything. When the TCIE flag is set, the program stops and stops working. I think an interrupt is triggered, but the program is not included in the interrupt handler. I see this because I'm trying to turn on the LED in the interrupt handler. He's not responding. I also observe that there is a full packet of transmission over SPI.


Associate II

I checked, the HTIF and TCIF flags are set. But after enabling interrupts, the program stops running. I noticed that if you enable only the HTIF interrupt and allow global interrupts, then nothing happens on half of the transmission, that is, the interrupt is triggered only after the complete transmission of the data packet. It looks like a microcontroller bug.

Again: what means stops running? Try to break in with the debugger.

As for your code, maybe. I am not interested in rigorous solution, that's just an academic curiosity. I enable clocks early in the code - I don't subscribe to the "separately working device drivers" notion, i.e. I don't leave clocks/GPIO setup to the last moment before the peripheral is enabled.


PS. In your snippet, I'd cast the dummy read to RCC->AHB1ENR to (void), that should prevent compilers from complaining about unused expression result (C99