STM32: Unexpected interrupts - Page 1
Forum section: electronics / general

author: AJ528
author_rank: Regular Contributor
timestamp: July 26, 2024, 05:22:18 pm
content: I am programming on an Arm M4 microcontroller, and using a timer module and DMA to generate 6 pulses with different periods (between 0.5 and 1 second). The DMA reloads the timer every time it overflows, and raises an interrupt when there is no more data to transfer. In the DMA interrupt, I clear the timer's overflow interrupt flag, enable the NVIC timer interrupt, and expect to get an interrupt the next time it overflows. Instead, I get an interrupt immediately upon exiting the DMA interrupt. Does anyone know why this is happening?This situation only occurs if the timer's overflow interrupt flag is enabled during setup. If the overflow interrupt flag and NVIC timer interrupt are both enabled within the DMA interrupt, there is no immediate timer interrupt. But in both situations I clear the overflow interrupt flag immediately before enabling the NVIC interrupt, so I don't understand the difference.I am happy to provide my code and more technical information, but I wanted to start with a simple version of my question in case I'm just not understanding something about interrupts on this microcontroller.

author: ajb
author_rank: Super Contributor
timestamp: July 26, 2024, 06:04:13 pm
content: Quote from: AJ528 on July 26, 2024, 05:22:18 pmClearing the interrupt enable bit in a peripheral doesn't clear an interrupt that is already pending for that peripheral in the NVIC. So if the NVIC has already registered the interrupt request for the timer and set that to pending when the DMA ISR is entered, then you're getting exactly the expected behavior. You can either enable the timer overflow interrupt in the DMA ISR as you mention, or you can clear the pending timer interrupt in the NVIC before exiting the DMA ISR. (The latter has a possible secondary trap in that if the timer hardware is slower to respond to the OVIE bit being cleared than the NVIC is to the pending interrupt being cleared, the timer may requestanotherinterrupt after the NVIC is cleared.)

author: AJ528
author_rank: Regular Contributor
timestamp: July 26, 2024, 07:17:09 pm
content: I believe I am already clearing the pending timer interrupt in the NVIC before exiting the DMA ISR. The last two lines in my DMA isr areCode:LL_TIM_ClearFlag_UPDATE(TIM17);NVIC_EnableIRQ(TIM17_IRQn);Does that not clear the pending timer interrupt in the NVIC?

author: voltsandjolts
author_rank: Unknown
timestamp: July 26, 2024, 08:08:19 pm
content: Maybe this?Code:LL_TIM_ClearFlag_UPDATE(TIM17);NVIC_ClearPendingIRQ(TIM17_IRQn);NVIC_EnableIRQ(TIM17_IRQn);

author: ajb
author_rank: Super Contributor
timestamp: July 26, 2024, 08:22:32 pm
content: Quote from: AJ528 on July 26, 2024, 07:17:09 pmIf you look at the definition of `LL_TIM_ClearFlag()` you'll see it's defined as (something like) the following:Code:__STATIC_INLINE void LL_TIM_ClearFlag_UPDATE(TIM_TypeDef *TIMx){WRITE_REG(TIMx->SR, ~(TIM_SR_UIF));}So that's only clearing the flag in the timer status register, and doesn't do anything about the IRQ in the NVIC. `NVIC_ClearPendingIRQ` is the function that would would do that, as voltsandjolts shows.

author: AJ528
author_rank: Regular Contributor
timestamp: July 26, 2024, 08:37:49 pm
content: oh, so the timer IRQ can be set as pending in the NVIC even before the NVIC timer IRQ is enabled? That is not what I was expecting. So the "NVIC_EnableIRQ" command isn't enabling the IRQ as much as it's unmasking the IRQ signal. The NVIC was listening the whole time.What would happen if I ran "NVIC_ClearPendingIRQ(TIM17_IRQn)" in the DMA isr, but didn't run "LL_TIM_ClearFlag_UPDATE(TIM17)"? At that point the pending IRQ is cleared, but there is still an interrupt flag in TIM17's status register. Would another interrupt get triggered immediately? Or is the IRQ only set to pending on the rising edge of that interrupt flag?

author: ajb
author_rank: Super Contributor
timestamp: July 26, 2024, 09:41:38 pm
content: Quote from: AJ528 on July 26, 2024, 08:37:49 pmIt would be a bit more accurate to say that NVIC_EnableIRQ enables the interrupt to become active (ie, jump to the ISR and execute it). This allows you to prevent entry into an ISR while still allowing the corresponding interrupt to become pending so that it can be handled later. This also ties in with the way that preemption and priority masking are handled, which also affect when a particular interrupt is taken.QuoteThe NVIC is part of the ARM core, so if you want to get into all of the gritty details for the M4/M7, you want the ARMv7-M Architecture Reference Manual, specifically (since I happen to have that open here) sections B1.5 and B3.4. B3.4.1 explains how the NVIC handles external interrupt lines:QuoteSo, it's up to the implementer (meaning the MCU manufacturer) whether the peripheral issues a pulse on the rising edge of an interrupt flag, or simply holds the interrupt line active as long as there's an active and enabled interrupt flag. In general, I would assume the latter, since each interrupt flag can just be ANDed with its enable bit, and then the results for all interrupt flags ORed together into the NVIC interrupt line. So in that case, yes, if you do NVIC_ClearPendingIRQ before clearing the overflow flag, you would immediately get another IRQ pending.

author: WatchfulEye
author_rank: Regular Contributor
timestamp: July 31, 2024, 04:58:21 pm
content: Quote from: AJ528 on July 26, 2024, 07:17:09 pmThere may be a bus-architecture timing issue here. This is MCU specific and dependent on clock configuration (but for faster cores, such as M4, it is common for the peripherals to be on an APB bus which is clocked slower than the AHB system bus). Careful reading of the datasheet is required.This issue can cause interrupt handlers to trigger twice if clearing of interrupt flag on the peripheral is left to the last instruction (the APB does not have time to complete the bus transaction before the interrupt handler completes, at which point the NVIC sees the interrupt still pending, and so restarts the handler).A solution is to move the act of clearing the interrupt flag to earlier in the handler, or add a dummy transaction (e.g. just run the clear operation twice) on the same APB (a second APB transaction will block while the first is still pending).If this is the problem, I would expect the following code to fix it:Code:LL_TIM_ClearFlag_UPDATE(TIM17);LL_TIM_ClearFlag_UPDATE(TIM17);NVIC_EnableIRQ(TIM17_IRQn);

author: AJ528
author_rank: Regular Contributor
timestamp: August 01, 2024, 07:25:45 pm
content: In this situation it appears that ajb hit the nail on the head. Using voltsandjolts's suggestion of NVIC_ClearPendingIRQ(TIM17_IRQn); cleared the interrupt exactly as I was expecting. I also realized that LL_TIM_ClearFlag_UPDATE() and LL_TIM_EnableIT_UPDATE() have the same relationship as LL_TIM_ClearFlag_UPDATE() and NVIC_EnableIRQ(): even if the interrupt is disabled in the Timer Module and NVIC, the UIF flag in TIMx_SR is always watching for an interrupt condition. If UIF is set when you run LL_TIM_EnableIT_UPDATE(), an interrupt will immediately happen, so if you don't want that be sure to clear the flag before enabling.