Skip to main content
Vlad2022
Associate
April 23, 2022
Question

DMA interrupts don't work

  • April 23, 2022
  • 8 replies
  • 4857 views

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) {
 
 RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; 
 
 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 |
 DMA_SxCR_CHSEL_0;
 DMA2_Stream5->CR |= DMA_SxCR_DIR_0;
 
 DMA2_Stream5->CR |= DMA_SxCR_TCIE;
 DMA2_Stream5->CR |= DMA_SxCR_HTIE;
 NVIC_EnableIRQ(DMA2_Stream5_IRQn);
 
 DMA2_Stream5->CR |= DMA_SxCR_EN;
}

Interrupt Handler:

void DMA2_Stream5_IRQHandler(void) {
...
}

This topic has been closed for replies.

8 replies

waclawek.jan
Super User
April 24, 2022

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.

JW

Piranha
Principal III
April 24, 2022

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

RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;

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.
April 24, 2022

> 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?

waclawek.jan
Super User
April 24, 2022

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

Look into the respective erratas.

JW

Piranha
Principal III
April 24, 2022

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.

https://www.st.com/resource/en/errata_sheet/es0222-stm32f401xb-and-stm32f401xc-device-limitations-stmicroelectronics.pdf

"2.1.6 Delay after an RCC peripheral clock enabling"

Workarounds

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:

RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
RCC->AHB1ENR;
// Add code, which waits for 2 peripheral clock cycles, here.

Vlad2022
Vlad2022Author
Associate
April 24, 2022

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.

RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
delay(50);

Vlad2022
Vlad2022Author
Associate
April 24, 2022

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.

Pavel A.
April 24, 2022

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

Vlad2022
Vlad2022Author
Associate
April 24, 2022

The program enters the interrupt and works endlessly in it, the working code stops executing. At the same time, neither the DMA2_Stream5 interrupt handler is started, nor the program does not get into HardFault or other errors.

My programmer does not support debugging.

waclawek.jan
Super User
April 24, 2022

> nothing happens on half of the transmission,

How do you know?

JW

Vlad2022
Vlad2022Author
Associate
April 25, 2022

I assume that when the HTIE bit is enabled, the program should enter the interrupt and, if not reset the flag, stay in it. Through DMA over SPI, I paint over the display with color. If you put the interrupt handler empty, then the program on half of the display should enter an infinite interrupt. I have a full filling of the display and only then enters the interrupt.

TDK
April 24, 2022

> But after enabling interrupts, the program stops running.

Possibly (probably) the MCU is jumping to the IRQ handler and either because you're failing to clear flags, or because it's being triggered too often, the MCU fails to make progress in the main loop.

Posting the complete IRQ handler code would help.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Vlad2022
Vlad2022Author
Associate
April 25, 2022
void DMA2_Stream5_IRQHandler(void) {
	GPIOC->BSRR |= GPIO_BSRR_BR_13;
 
	DMA2->HIFCR |= DMA_HIFCR_CTCIF5;
	DMA2->HIFCR |= DMA_HIFCR_CHTIF5;
}

At the very beginning of the interrupt, I give the command to turn on the standard LED. However, my LED does not light up when interrupts are turned on.

Piranha
Principal III
April 25, 2022
  1. You are resetting the pin with BR bit, not setting with BS bit.
  2. None of those lines need a read-modify-write operation.
  3. Both interrupt flags can be cleared with a single operation.
void DMA2_Stream5_IRQHandler(void) {
	GPIOC->BSRR = GPIO_BSRR_BS_13;
 
	DMA2->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5;
}

waclawek.jan
Super User
April 25, 2022

> I assume that when the HTIE bit is enabled, the program should enter the interrupt and, if not reset the

> flag, stay in it. Through DMA over SPI, I paint over the display with color. If you put the interrupt handler

> empty, then the program on half of the display should enter an infinite interrupt. I have a full filling of the

> display and only then enters the interrupt.

DMA continues to work regardless of whether you are in interrupt or not. So, the half-transfer interrupt fires, processor gets stuck in the interrupt, but DMA continues to fill SPI thus draw on your display.

JW

Vlad2022
Vlad2022Author
Associate
April 26, 2022

Thank you, so my assumption is wrong and the HTIE interrupt works.