cancel
Showing results for 
Search instead for 
Did you mean: 

Interrupt double firing can't be fixed

ZJing
Associate III

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!

3 REPLIES 3

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 Venmo
Up vote any posts that you find helpful, it shows what's working..

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.

Is loop count volatile? What does the generated assembly code look like?

What's the audit trail look like here? ie perhaps have a table with the DWT CYCCNT and ADC1->ISR recorded so you can unpack the timing and sequence of events here.

You need to do this in a hands-off fashion, stopping in the debugger, touching all the registers, is too invasive for time dependent/critical functionality.

How frequently is the Injection request made? Is the Injection request involving multiple sources?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..