cancel
Showing results for 
Search instead for 
Did you mean: 

EXTI interruption flags

JNava.1
Associate II

Hi.

I am having some issues trying to use the EXTI module, to implement interruption routines associated to ports.

The problem is related to the behavior of STM32 microcontrollers with ports interruptions. In most microcontrollers (i.e. Texas Instruments MSP430), when it comes to port interruption handling, we have interruption flags (IFG) and interruption enables (IE) for each port. Then, when an event occurs on a port, for example, a pulse transition from low to high, the IFG goes to high even if the interrupt is disabled. In case the interrupt is enabled, the IFG goes to high too and the interruption service routine (ISR) is executed. In that way, when you have an interruption disabled (IE = 0) and an event happens on the port, the IFG is set to high. If in any part of your code you enable the interruption (IE = 1), the ISR is immediately called because the IFG = 1. This is a good way to store the occurrence of an event, even in the case the interrupt is disabled in the moment when the event occurs.

But STM32 looks to work in a different way. For example, when you have a port interruption disabled (EXTI IMRx disabled) if the event occurs in any moment, the corresponding flag (EXTI PRx) is not set because the IMRx was disabled. Then, the occurrence of the event is not stored if occurred when the interruption was disabled, as you can do with other microcontrollers, as in the exampled I wrote above.

Maybe, someone could say "Why don't you enable the interrupt if you don't want to lose the event?". There could be different reasons why, one of them is the following: Let's suppose that I have two different port interruptions, one for an external signal in port A1, and other coming from a button in port A2. Let's suppose that in some portions of my code, I need to wait only for the signal in port A1 and respond as soon as possible for a timing constraint that I have in my project. Let's suppose I cannot have any other interruption enabled (neither timers nor my button in port A2) in order to respond as quick as possible when the event related to the signal in port A1 occurs. But, when I go out from that portion of the code, I will go to a main loop, in where I will enable and attend the other interruptions (timers, the button in port A2, etc.). What would happen if any of those events arrived when I was in the signal wait routine described above? With timers I won't have problems because timers rise the flag event even if the interruption were disabled. But with EXTI port interruptions I will lose the event because there is not flag which "store" the occurrence of the event when the interruption was disabled.

Then, if someone have some idea about how to solve this problem, please, give me some suggestions. Maybe there are another flag or something that I am not aware of.

Thank you in advance for your help.

1 ACCEPTED SOLUTION

Accepted Solutions
Pavel A.
Evangelist III

>  the problem is that when I have a port interrupt disabled, I would want to know if the event occurred, so when I enable the interrupt again, the corresponding IRQHandler could be executed.

So the *proper* solution is NOT having to know what is pending, just to leave the [low-priority] interrupts wait and trigger when you are ready to receive them.

STM32L4 is Cortex-M4, it does support BASEPRI.

Now suppose you want to disable some interrupts (including EXTI) during some "critical section", but allow high-priority interrupts (otherwise you would simply __disable_irq).

​Assign a low priority to the former interrupts. Then call set_BASEPRI with a value less or equal to this priority, but greater than priority of allowed interrupts. (because for ARM higher priority has lower numerical value).

The low priority interrupts will be effectively masked and delayed until you restore BASEPRI at the end of the "critical section". Then pending interrupts will be handled.

As Jan wrote, timers in capture mode can be a good alternative, given the limitation of EXTI (cannot use same pins of two ports, sharing of NVIC vectors).

View solution in original post

13 REPLIES 13
Pavel A.
Evangelist III

>  Let's suppose that in some portions of my code, I need to wait only for the signal in port A1 and respond as soon as possible

Why this cannot be solved using the interrupt priorities and BASEPRI to delay interrupts of lower priorities?

To be specific, which STM32 do you have?

S.Ma
Principal

EXTI (version existing in F4 and L4) have edge detection on selectable or fixed edge of a set of input signals, which 16 of them are coming from the 16 GPIO pins which for each one of them you define which port name you use. (PB0, PC1, PA2, PH3, etc... until Px15) You can't select PA0 and PB0 for example. Then the PR bit are set by edge and cleared by SW. You can use the debugger and breakpoint the code, and manually play with these registers without rebuilding test code over and over to get a feel for the EXTI block.

Now there is indeed an interrupt enable bitmask for all these EXTI input source signals, post PR bit stage. To reduce the number of interrupt vectors, some signals are ored, for example you may have EXTI0 vector (so you know it's Px0 that was generating an interrupt), or EXTI12-15 (a group of pins and in the interrupt you'll need to browse PR bit 12,13,14,15 and switch case them (a bit slower latency)

Clearing the PR bit will be needed to clear the pending interrupt.

Maybe the reference manual EXTI description need to be touched up to make it more understandable to audience used to other vendors way of implementing similar function?

Thank you for your answer. The problem is that we have a firmware architecture in which we need to activate some interrupts in some portions of our code and enable others in other parts. This is not the problem, the problem is that when I have a port interrupt disabled, I would want to know if the event occurred, so when I enable the interrupt again, the corresponding IRQHandler could be executed.

For example, compare this situation with the timers module. In timers, when you configure it in compare mode, you have flags (CCxIF) which goes high when the timer counter reach the value set to compare. This happens independently of the state of the interrupt enable bit (CCxIE). Then, if you have the interruption enabled, the flag CCxIF goes to high an the IRQHandler is executed. But if you have the interruption disabled, the flag CCxIF goes to high too, but the IRQHandler is not executed. If some time after, I enable the interruption, the IRQHandler is immediately executed because the CCxIF flag was previously set to one. In that way, I never lose an event, independently of the state of the interrupt enable bit, because if I have it disabled in the moment the event occurred, I know that when I enabled it, the IRQHandler will be executed.

This is the kind of behaviour that I would want to have with ports. In most microcontrollers, all the peripherals (timers, ports, USCI, ADC, etc.) work in that way. Even in the STM32, most peripherals, as timers, work in that way.

By the way, the microcontroller I am using is a STM32L443.

JNava.1
Associate II

Thank you for your answer. I understand how ports and EXTI interruptions related to them works. The problem is the following: the PRx bit is set when an event happens in the corresponding port (falling, raising, both, whatever option that you have configured). The problem is that PR bits are set by the hardware only if the IE bit is set. If you have the IE disabled, the PRx bit don't do anything.

The problem is that we have a firmware architecture in which we need to activate some interrupts in some portions of our code and enable others in other parts. So, when I have a port interrupt disabled, I would want to know if the event occurred, so when I enable the interrupt again, the corresponding IRQHandler could be executed.

For example, compare this situation with the timers module. In timers, when you configure it in compare mode, you have flags (CCxIF) which goes high when the timer counter reach the value set to compare. This happens independently of the state of the interrupt enable bit (CCxIE). Then, if you have the interruption enabled, the flag CCxIF goes to high an the IRQHandler is executed. But if you have the interruption disabled, the flag CCxIF goes to high too, but the IRQHandler is not executed. If some time after, I enable the interruption, the IRQHandler is immediately executed because the CCxIF flag was previously set to one. In that way, I never lose an event, independently of the state of the interrupt enable bit, because if I have it disabled in the moment the event occurred, I know that when I enabled it, the IRQHandler will be executed.

This is the kind of behavior that I would want to have with ports. In most microcontrollers, all the peripherals (timers, ports, USCI, ADC, etc.) work in that way. Even in the STM32, most peripherals, as timers, work in that way.

This is how EXTI works and you cannot change that, just accept it.

You can disable the subsequent interrupt at NVIC level. You did not tell us which STM32 are you using, but in some of them around 5 EXTI have individual vectors.

If TIM capture interrupts suit your application better, then simply use those.

JW

S.Ma
Principal

" we need to activate some interrupts in some portions of our code and enable others in other parts. So, when I have a port interrupt disabled, I would want to know if the event occurred, so when I enable the interrupt again, the corresponding IRQHandler could be executed."

PR is equivalent to CCxIF

Now depending on the desired code behaviour, you may clear by SW the PR bit before enabling interrupts. Maybe express the application need instead of focusing on EXTI.

Which STM32?

How many input pins?

Frequency of the inputs for each pin?

Thank you for your answer. It is like you said, I have to accept the weird design of the EXTI respect to those topic. I think I have to work enabling/disabling the interrupt at NVIC level. I am using the STM32L443. I know I have individual vectors for 5 EXTI, but we have to design a different approach for the others where we have shared vectors.

Respect to TIM capture interrupts, I will use them (for timers), but we also need to use ports interruptions. TIM interruption has nothing to do with ports. In our projects, we need to use different kind of interruptions from different sources (timers, ports, ADC, RTC, USCI among other peripherals interrupts). It is a shame that EXTI works in a different way to other peripherals when it comes to interruption behavior.

JNava.1
Associate II

S.Ma, thank you for your answer. Respect to that: "PR is equivalent to CCxIF", I am afraid that those flags works in a different way. Timers flags, as CCxIF, are set by hardware when the timer event is triggered, independently of the state of the interrupt enable bit. In the EXTI peripheral, the PR flag are set by hardware when the event in the corresponding port is triggered only if the interruption is enabled (IMx bit set to one). When the interruption is disabled, the PR bit remains in zero even if the event in the port is triggered.

We are using STM32L443, but for other projects we are going to use other families. The number of input pins depends on the project. Basically, we have different projects in other microcontrollers (most of them using TI MSP430). Now, we are migrating our platform to STM32 microcontrollers. In the current project we are using about 6 ports IO with desired interrupt capability, but it could change in other projects.

Pavel A.
Evangelist III

>  the problem is that when I have a port interrupt disabled, I would want to know if the event occurred, so when I enable the interrupt again, the corresponding IRQHandler could be executed.

So the *proper* solution is NOT having to know what is pending, just to leave the [low-priority] interrupts wait and trigger when you are ready to receive them.

STM32L4 is Cortex-M4, it does support BASEPRI.

Now suppose you want to disable some interrupts (including EXTI) during some "critical section", but allow high-priority interrupts (otherwise you would simply __disable_irq).

​Assign a low priority to the former interrupts. Then call set_BASEPRI with a value less or equal to this priority, but greater than priority of allowed interrupts. (because for ARM higher priority has lower numerical value).

The low priority interrupts will be effectively masked and delayed until you restore BASEPRI at the end of the "critical section". Then pending interrupts will be handled.

As Jan wrote, timers in capture mode can be a good alternative, given the limitation of EXTI (cannot use same pins of two ports, sharing of NVIC vectors).