cancel
Showing results for 
Search instead for 
Did you mean: 

Level sensitive interrupts with EXTI

Pavel A.
Evangelist II

I need to achieve level sensitive interrupt behavior with EXTI, similar to shared PCI interrupts on other architectures.

Have several OR'ed interrupt requests wired together to a EXTI input;

all requests are active low.

All requests can be masked or dismissed outside of STM32.

(Actually this is a device with several interrupt reason bits in a memory mapped register; the common request pin is active low; each interrupt reason bit can be masked via another memory mapped register. Like a "classic" PCI thing).

Several threads in this forum and SO (links below) suggested that this is not possible, at least not trivial.

The following trick nevertheless seems to work for me, and looks simple.

extern void exti0_handler();
 
void EXTI0_IRQHandler(void)
{
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
        do {
            exti0_handler();
        } while (HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_0) == GPIO_PIN_RESET); /* active LOW */
        __DSB();
}

Explanation:

* The EXTI0 interrupt is triggered by falling edge. GPIOx is some GPIO port (A,B...)

* exti0_handler() will check each of interrupts source on the shared EXTI pin and either masks it or dismisses

* If the pin still is low (request active) after exti0_handler(), repeat.

  • If the interrupt pin goes down between check of the pin and return, then the falling edge detector will activate EXTI again and it won't be lost.

Can anyone spot a bug?

Of course if the EXTI pin remains low for too long time the interrupt latency would be indefinite. If this is important, number of loops can be limited (and some action taken, like masking the whole EXTI input).

Regards,

-- pa

References:

Level triggered interrupts on STM32L series

exception - Clarify interrupt mechanism on STM32H7 - Stack Overflow

level sensitive IRQ on GPIO (st.com)

9 REPLIES 9

Looks good, IMO. Just minor things:

  • What's the point of __DSB?
  • One primary source gets active and ISR is entered, HAL incantation is invoked to clear the EXTI latch, then your handler is called which clears the primary source, thus pin goes low. While still in your handler, a new primary interrupt happens, setting the pin high, which sets also the EXTI latch, which never gets cleared. This new interrupt is resolved in the loop and ISR is exit, but the EXTI latch remains set thus this ISR gets reentered without reason. If your handler is written so that it qualifies every source and is not surprised by being called with no source, it's OK just a nuissance and probably not worth trying to solve, as placing the latch clear nearer the ISR exit (aftr call of exti0_handler() but before reading the pin) might result in "redundant ISR call" anyway.

JW

MM..1
Chief

I mean not next clear but break yu miss

void EXTI0_IRQHandler(void)
{
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
        do {
            exti0_handler();
            if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) break;
        } while (HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_0) == GPIO_PIN_RESET); /* active LOW */
        __DSB();
}

Pavel A.
Evangelist II

Thank you Jan. Yes, handler() is ok when no source bit is set. DSB is left there perhaps just for luck 😉

MM..1
Chief

This your code is totaly miss , when no next interrupt edge you stay in while neverending.

My first code is ok, when new IRQ flag raised while is break, and NVIC controll start new EXTI0_IRQHandler ...

You're right. I'll remove my wrong 'guess'. -- pa

Piranha
Chief II

Pavel's code is perfectly fine if the rest of the code and hardware functions as described. EXTI clear can even be put inside the while loop before exti0_handler(), potentially decreasing the chance of interrupt reentering.

@MM..1​, you should stop writing misinformation with such high confidence. Your code is exactly like ST's HAL - hacked something together without real understanding. And the language skill also should be at least at a level understandable by others.

@Piranha​ Pavel removes wrong code from message, and yes my eng isnt native

OK, then it's clear about Pavel's code. But this particular line is still a nonsense:

if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) break;

Most of the users here aren't native English speakers. It's not so much about grammar, but more about expressing the ideas in a clear and structured way - so that others can understand and use that information.

Why nonsense explain...