Skip to main content
ZJing
Associate III
October 21, 2022
Question

Interrupt double firing can't be fixed

  • October 21, 2022
  • 1 reply
  • 921 views

Hello all,

I am using the ADC on my STM32L431 with both DMA and interruption. Everything works fine, except that the ISR is often entered with none of the enabled interrupt flag being set.​

Initial code:

void ADC1_IRQHandler() 
{
	
	if(LL_ADC_IsActiveFlag_JEOC(ADC1))
	{
		inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
	}
	else if(LL_ADC_IsActiveFlag_OVR(ADC1))
	{
		LL_ADC_ClearFlag_OVR(ADC1);
	}
	else
	{
		__NOP(); //A breakpoint is set here and it is reached quite often
	}
}

-Last post-

In the last post, @Community member​ suggested that this is caused by the program exiting ISR too soon, therefore the interrupt flag is not yet cleared, then the program would enter ISR again.

Since then, I tried to fixed it by doing the following:

1.

void ADC1_IRQHandler() 
{
	
	if(LL_ADC_IsActiveFlag_JEOC(ADC1))
	{
		inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
 __DSB();
	}
	else if(LL_ADC_IsActiveFlag_OVR(ADC1))
	{
		LL_ADC_ClearFlag_OVR(ADC1);
 __DSB();
	}
	else
	{
		__NOP();
	}
}

2.

void ADC1_IRQHandler() 
{
	if(LL_ADC_IsActiveFlag_JEOC(ADC1))
	{
		inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
		loop_cnt++; //Read - Modify - Write
		if(loop_cnt >= 1024) loop_cnt = 0;
	}
	else if(LL_ADC_IsActiveFlag_OVR(ADC1))
	{
		LL_ADC_ClearFlag_OVR(ADC1);
		loop_cnt++;
		loop_cnt--;
	}
	else
	{
		__NOP();
	}
}

According to this article by ARM

3.

void ADC1_IRQHandler() 
{
	if(LL_ADC_IsActiveFlag_JEOC(ADC1))
	{
		inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
		temp_isr = ADC1->ISR & 0x7FF; //Read immediately after write
	}
	else if(LL_ADC_IsActiveFlag_OVR(ADC1))
	{
		LL_ADC_ClearFlag_OVR(ADC1);
 temp_isr = ADC1->ISR & 0x7FF;
	}
	else
	{
		__NOP();
	}
}

According to this post on a different forum

But none of them solved the issue.

Please help! Thank you in advance!

This topic has been closed for replies.

1 reply

Tesla DeLorean
Guru
October 21, 2022

Ok, but what's signalling?

You show your attempts to fix the problem, you don't really describe the actual problem.

Read the register, don't use the peripheral viewer in the debugger. Is nothing signalling?

The if/else tree here doesn't account for situations where more than one interrupt source may be signalling.

How frequently is this occurring? For every expected interrupt, you get a second unexpected one?

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
ZJing
ZJingAuthor
Associate III
October 21, 2022

Hello Tesla,

Yes, I should've showed that too. But I have been reading the actual ISR register:

void ADC1_IRQHandler() 
{
	temp_isr = ADC1->ISR & 0x7FF;		
	if(LL_ADC_IsActiveFlag_JEOC(ADC1))
	{
		inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
		temp_isr = ADC1->ISR & 0x7FF;		
		loop_cnt++;
		if(loop_cnt >= 1024) loop_cnt = 0;
	}
	else if(LL_ADC_IsActiveFlag_OVR(ADC1))
	{
		LL_ADC_ClearFlag_OVR(ADC1);
		loop_cnt++;
		loop_cnt--;
	}
	else
	{
		__NOP();
	}
}

temp_isr always reads 0x4B when the breakpoint is reached, which means that JEOC is not set.

0693W00000UoXleQAF.png(I'm only using this for reference, so you can see that 0x4B means JEOC not set)

This happens once in a while, ~ once per 120 seconds.