Skip to main content
Explorer II
August 19, 2025
Solved

Setting IFCR does not clear ISR

  • August 19, 2025
  • 3 replies
  • 543 views

I'm using the STM32F103C8T6, and trying to blink my LED via the interrupt handler of a DMA with this code

#include <stdint.h>
// STM32F103C8 is a medium density device, hence we use the xB header
#include <stm32f103xb.h>

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning \
 "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void) {
	uint32_t blinking[2] = { GPIO_BSRR_BR8, GPIO_BSRR_BS8 };
	uint32_t dest = 0;

	RCC->CR |= RCC_CR_HSION;
	while ((RCC->CR & RCC_CR_HSIRDY) == 0)
		;

	RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable clock for DMA1
	RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // Enable clock for TIM1
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable IO port A

	NVIC_EnableIRQ(DMA1_Channel2_IRQn);

	DMA1_Channel2->CCR |= DMA_CCR_MSIZE_1 // 32-bits memory size
	| DMA_CCR_PSIZE_1 // 32-bits peripheral size
			| DMA_CCR_MINC // Memory increment
			| DMA_CCR_CIRC // Circular mode
			| DMA_CCR_DIR // Read from memory
			| DMA_CCR_HTIE // Enable half transfer interrupt
			| DMA_CCR_TCIE // Enable complete interrupt
			| DMA_CCR_MEM2MEM
	;

	DMA1_Channel2->CNDTR = 2;
// DMA1_Channel2->CPAR = (uint32_t)&GPIOA->BSRR;
	DMA1_Channel2->CPAR = (uint32_t) &dest;
	DMA1_Channel2->CMAR = (uint32_t) blinking;

	TIM1->CCMR1 |= TIM_CCMR1_OC1M_0;
	TIM1->DIER |= TIM_DIER_CC1DE;
	TIM1->CCER |= TIM_CCER_CC1E; // Enable OC1 output
	TIM1->BDTR |= TIM_BDTR_MOE;

	TIM1->PSC = 512 - 1;
	TIM1->ARR = (15625 * 2) - 1;

	GPIOA->CRH &= ~(GPIO_CRH_CNF8 | GPIO_CRH_MODE8); // GPIO A: Clear pin 8 configuanaration
	GPIOA->CRH |=
	GPIO_CRH_MODE8; // GPIO A: Set pin 8 to output with 50 MHz and push-pull

	DMA1_Channel2->CCR |= DMA_CCR_EN;
	TIM1->CR1 |= TIM_CR1_CEN;

	/* Loop forever */
	for (;;) {
	}
}

void DMA1_Channel2_IRQHandler() {
	if ((DMA1->ISR & DMA_ISR_HTIF2) != 0) {
		GPIOA->BSRR = GPIO_BSRR_BR8;
	}
	if ((DMA1->ISR & DMA_ISR_TCIF2) != 0) {
		GPIOA->BSRR = GPIO_BSRR_BS8;
	}

	DMA1->IFCR = DMA_IFCR_CGIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CTCIF2;
}

However, at 67, setting the IFCR register does not seem to clear the ISR flags and the handler keeps getting called. How do I handle this?

 

    This topic has been closed for replies.
    Best answer by waclawek.jan

    How do you know?

    [EDIT]

    DMA_CCR_MEM2MEM

    Don't. This does not do what you may think it does. The M2M mode means "ignore trigger from TIM, do autotrigger the given channel so that transfers run as quick as possible".

    JW

    3 replies

    Super User
    August 19, 2025

    > DMA_CCR_CIRC // Circular mode

    > the handler keeps getting called

    Seems like correct behavior to me.

    Use normal (non-circular) mode if you only want it to happen once.

    BeartamaAuthor
    Explorer II
    August 19, 2025

    I mean the handler is called immediately without the delay expected.

    Super User
    August 19, 2025

    How do you know?

    [EDIT]

    DMA_CCR_MEM2MEM

    Don't. This does not do what you may think it does. The M2M mode means "ignore trigger from TIM, do autotrigger the given channel so that transfers run as quick as possible".

    JW

    BeartamaAuthor
    Explorer II
    August 19, 2025

    My setup has an LED connected to GPIO A8, if there’s a delay between two interruption invocations, i would see the LED blinking. However, I see the LED stays bright without being turned off.

    Super User
    August 19, 2025

    Can your eyes detect if it's blinking at 1 MHz? Unlikely.

    The flag is getting cleared here, it's just getting set again immediately afterwards because the transfer happens so fast.

    Super User
    August 19, 2025

    Yes, I repeat, don't use MEM2MEM in DMA, as it ignores the triggers from timer and autotriggers at maximum rate.

    JW

    BeartamaAuthor
    Explorer II
    August 19, 2025

    Yes, I just saw your edit, this was problem. Thank you very much.