2025-07-03 8:45 AM - edited 2025-07-03 8:46 AM
I've got some code running on the C4 in an STM32H747IGT6, it's just waiting for the ADC to have data and then reading it:
while (!LL_ADC_IsActiveFlag_EOC(ADC1)) {}
__disable_irq();
start_timer = TIM5->CNT;
LL_ADC_ClearFlag_EOC(ADC1);
adc_data = LL_ADC_REG_ReadConversionData32(ADC1);
data = ((float)adc_data) / 65536.0f; // Normalize from 0..0xFFFF (-4 to 4V) to 0..1
end_timer = TIM5->CNT;
uint32_t icsr = SCB->ICSR;
__enable_irq();
With IRQs disabled (as shown here), TIM5->CNT shows the code takes 6-8 ticks but if I comment out the calls to __disable_irq() and __enable_irq(), the code takes as many as 146 ticks and I'm trying to figure out why. TIM5 has no interrupts enabled and is running at full speed (240 MHz) so ticking once every 4.1666 ns.
If I look at the value of SCB->ICSR it's almost always 0x400000 which means ISRPENDING but VECTPENDING is zero.
In my code I'm only enabling 3 interrupts and I've verified none of them are firing.
How can I figure out which interrupts are firing and slowing me down so much?
2025-07-03 8:59 AM
See what interrupts are pending just before you __enable_irq() by looking at VECTPENDING in the SCB registers.
> almost always 0x400000
So when it's not that, what is it?
Put a delay(1) in there to wait until one fires.
2025-07-03 9:09 AM
When ICSR is not 0x400000 it's always 0x422000 which is the ADC1 overrunning because the loop takes too long. That's a well-understood situation and I don't think it is related to these other delays.
You can see my code:
uint32_t icsr = SCB->ICSR;
I'm looking (and storing) the value of ICSR just before calling __enable_irq(). When you say "See what interrupts are pending just before you __enable_irq() by looking at VECTPENDING in the SCB registers." isn't that exactly what I'm doing?
When you say "Put a delay(1) in there to wait until one fires." what do you mean? I can certainly put a delay in there, but after the interrupt fires how can I tell which interrupt it was? I haven't had any luck setting breakpoints on the CM4 so I can't just put a breakpoint on every single system-level IRQ (or if I can, I'm not familiar enough with gdb to know how)
2025-07-03 9:26 AM
> When ICSR is not 0x400000 it's always 0x422000 which is the ADC1 overrunning because the loop takes too long.
You have some ADC interrupts enabled, but not others? Which ones?
It sounds like the EOC interrupt is firing. Sometimes before start_timer is taken and sometimes after, hence the difference in ticks. That would explain the symptoms.
If you are polling for ADC data, perhaps disable interrupts for it. The EOC flag still gets set.