cancel
Showing results for 
Search instead for 
Did you mean: 

A problem with __HAL_GPIO_EXTI_CLEAR_IT on Nucleo-F410RB Optimization -03 (stm32cubeide)

VAX
Associate II

Hello,

I have a problem with EXTI0 after a compilation with 03 or Os.

In an ISR (EXTI0 for exemple) the place where the __HAL_GPIO_EXTI_CLEAR_IT is made seems to influence its action. If it is immediately followed by an exit from the ISR it does not work. Here is an example below

--

This is the ISR (on a Nucleo-F410RB compilation -03):

void EXTI0_IRQHandler(void)

{

             __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

             GPIOA->BSRR = GPIO_PIN_6;

             GPIOA->BSRR = GPIO_PIN_6<<16u;

}//OK 1 pulse

When i have un pulse on Line 0, I have one pulse on PA6.

(the code is intentionally minimalist, use __HAL_GPIO_EXTI_GET_IT does not change the behavior)

But if I change the code to :

void EXTI0_IRQHandler(void)

{

             GPIOA->BSRR = GPIO_PIN_6;

             GPIOA->BSRR = GPIO_PIN_6<<16u;

          __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

} // NOT OK  2 pulses !

I have 2 pulses on PA6. It’s like the flag was not yet reset to 0.

And when I try :

 void EXTI0_IRQHandler(void)

{

             GPIOA->BSRR = GPIO_PIN_6;

             GPIOA->BSRR = GPIO_PIN_6<<16u;

          __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

    __NOP();  

} //OK

Or

void EXTI0_IRQHandler(void)

{

             GPIOA->BSRR= GPIO_PIN_6;

             GPIOA->BSRR= GPIO_PIN_6<<16u;

          __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

  __ISB();

} //OK

All is correct, just one pulse on PA6.

Of course, in O0 everything is ok but in O3 or Os I have this problem on this board.

Just for information, on a nucleo-F030R8 with the same code and same optimization (Os or O3), All is correct, just one pulse on PA6.

void EXTI0_1_IRQHandler(void)

{

             GPIOA->BSRR= GPIO_PIN_6;

             GPIOA->BSRR= GPIO_PIN_6<<16u;

             __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

}  //OK 1 pulse on PA6 !!!

why (on the F410RB) is it necessary to have at least one tick between the flag reset and the exit of the ISR?

Does anyone have a explanation to help me understand?

thank you in advance

9 REPLIES 9

It takes time until the interrupt source clear propagates into NVIC.

JW

VAX
Associate II

Ha OK,

Thank you.

And is there the same phenomenon when propagating the interrupt signal?

Because in this example, it appears that the code is not immediately interrupted when the reason for the interruption appears (rising edge of the first pulse).

(The PA5 output is connected to the PC1 input).

Thanks again in advance for your help.

void EXTI1_IRQHandler(void)

{

       GPIOA->BSRR = GPIO_PIN_6;

       GPIOA->BSRR = GPIO_PIN_6<<16u;

       __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);

       __NOP();

}

//#############################################

int main() {

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();

 HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(EXTI1_IRQn);

while (1) {

GPIOA->BSRR = GPIO_PIN_5;

GPIOA->BSRR = GPIO_PIN_5 <<16u;

}

}0693W000005AgcHQAS.png

Yes that's exactly the same.

When interrupt is exit, PA5 in main() starts to pulse again, and the first active edge (depending on which edge is set in EXTI) sets the interrupt flag in EXTI; but it takes 2 more PA5 pulses (i.e. estimating pulse to be high for 1 system cycle and low for 3, it's at least 8 system cycles) until that signal propagates all the way to NVIC and starts the interrupt.

A very nice visualisation of the problem indeed, thanks.

JW

VAX
Associate II

Thank you.

Actually I am in the process of migrating from avr to arm ... so I am studying this core .

Just for information, the 3 cycles of the low state are actually 1 cycle + 2 cycles of sequence break (1 cycle of jump + 1 flush of a 1/3 of the pipeline). I had actually estimated 8 cycles but I am continuing my study to get a more deterministic answer.

Thank you again for your clarifications. I had not yet studied the bus times well.

MM..1
Chief III

Hi VAX, when you go from avr you know NAKED irq, And your problem here is i mean missusing HAL system. When you generate code from cube IRQ is defined in three function level calls, where you edit only last callback level. And difference in 030 vs 410 maybe is based on used clock config aka speed.

when IRQ occured as first it jump

EXTI15_10_IRQHandler

here call only

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13)

here check and clear flags and if this gpio have flag call

HAL_GPIO_EXTI_Callback

here your code an i mean will work with -O3 , but when you need special you can NAKED and dont use an HAL or __HAL

VAX
Associate II

Thank you MM..1 for your reply.

I'm sorry, but English is not my native language and I may have misunderstood your answer.

In my case, the ivt is initialized as follows:

g_pfnVectors:

 .word _estack

 .word Reset_Handler

 

 .word    RCC_IRQHandler                   /* RCC                                        */

 .word    EXTI0_IRQHandler                 /* EXTI Line0                                 */

 .word    EXTI1_IRQHandler                 /* EXTI Line1                                 */

...

my isr is :

//---------------------------

void EXTI0_IRQHandler(void)

{

   GPIOA->BSRR = GPIO_PIN_6;

   GPIOA->BSRR = GPIO_PIN_6<<16u;

    EXTI->PR=GPIO_PIN_0;

    // __NOP(); // Avec un NOP : comportement normal.  Sans le NOP => 2 impulsions !!!

}

My ISR is therefore immediately invoked and I do not use the 3 steps of HAL (I don’t want because I'm in the study phase of this core, I'm only using Cube to generate quickly the code for the clock configuration).

I tried to recreate these multiple calls and the result is the same. It seems necessary to leave at least one waiting cycle between the flag reset and the rti ("BX LR") for this to work.

Converting my isr to “nacked isr�? will only remove the prefix and postfix, this will save a few cycles but the problem remains the same.

I conclude that it is best to reset the EXTI flag early enough in the ISR code and the problem is then resolved.

Thank you all for your contributions.

MM..1
Chief III

Hi VAX , my native isnt english too...

You write recreate multiple calls, but i mean not right. I check it on Cube generated code seems this:

in it.c

/**

 * @brief This function handles EXTI line0 interrupt.

 */

void EXTI0_IRQHandler(void)

{

 /* USER CODE BEGIN EXTI0_IRQn 0 */

 /* USER CODE END EXTI0_IRQn 0 */

 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);

 /* USER CODE BEGIN EXTI0_IRQn 1 */

 /* USER CODE END EXTI0_IRQn 1 */

}

in hal

/**

 * @brief This function handles EXTI interrupt request.

 * @param GPIO_Pin Specifies the pins connected EXTI line

 * @retval None

 */

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)

{

 /* EXTI line interrupt detected */

 if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)

 {

  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

  HAL_GPIO_EXTI_Callback(GPIO_Pin);

 }

}

in main.c your implementation

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

GPIOA->BSRR = GPIO_PIN_6;

GPIOA->BSRR = GPIO_PIN_6<<16u;

}

And as you can see HAL define call clear before user code... Thats all

VAX
Associate II

I was not clear, I'm sorry ...

What I meant is that I am familiar with how Cube / HAL generated code works, and I am also familiar with this nested call.

It was by analyzing this code that I wanted to understand why the clear was made at the start of the HAL_GPIO_EXTI_IRQHandler function

I recreated the calls to prove that just because there is a two-level call graph, of isr, doesn't make it work better. Just because we spend a little time going up two levels doesn't mean that is enough. it is indeed a cycle problem between the reset and the break in the sequence (exit of isr). If the flag reset was done after invoking the callback (we can, just for fun, inverse the call of the callback and de clear_it() ) there could be the same problem because, my analysis is that there must be clock cycles between the write into EXTI-> PR and the “bx lr�? . When it does, all is well, but, if the compiler generates an output of isr immediately after the flag is reset, it doesn't work. if there are no OpCode between EXTI->PR= and "BX LR", it doesn't work.

Now, i must ubderstand why it's like this, i go to continue searching

I have a problem with the language barrier, I'm sorry. So we were talking about the same thing.

I started to manipulate and partly understand HAL but now I'm going down lower level to better understand how this MCU works. That's why I ask myself all these questions

Anyway, thank you for spending time answering me

Piranha
Chief II

Take a look at this:

https://developer.arm.com/documentation/dai0321/a/

Section: 4.9 Disabling interrupts at peripherals