STM32F0 HAL Pending Interrupt Issue

Thread Starter

Stuntman

Joined Mar 28, 2011
222
Curious if there are any STM32 guys using the CubeMX HAL. I'm having an issue that I can work around, but want to know the details of this issue. The part is an STM32F042, using CubeMX ver 4.23, GNU compiler and CooCox IDE.

The problem is this, I have PA4 setup as external interrupt for a falling edge detection (only external interrupt):
Code:
  /*Configure GPIO pin : PA4 */
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/snip

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI4_15_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
I do not have this signal debounced in hardware (for a reason). Therefore, in the ISR I disable the interrupt immediately, then re-enable later in the the code:

ISR:

Code:
void EXTI4_15_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI4_15_IRQn 0 */
    HAL_NVIC_DisableIRQ(EXTI4_15_IRQn);//Disable external IRQs
SenseTime[EventSlot]=__HAL_TIM_GET_COUNTER(&htim2); //Get sense time from timer 2   
        if(TriggerTime<9) //index where the time even happened.
            TriggerTime++;
        else
            TriggerTime=0;

  /* USER CODE END EXTI4_15_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
  /* USER CODE BEGIN EXTI4_15_IRQn 1 */

  /* USER CODE END EXTI4_15_IRQn 1 */
}
You'll notice the handler calls HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4) which resides in hal_gpio.c:

Code:
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);
  }
}
Now, I thought that __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin) clears the interrupt pending bit. With the external interrupts disabled (beginning of ISR), I should be free to activate the IRQ at a later time. However, when I do this, the interrupt routine executes again immediately (once, like it was previously triggered). So I tried calling HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4) , right before re-enabling the interrupt:


Code:
            HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
            HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);//Enable IRQ for sensing next pulse
No Difference. So I dug deeper. What I found was that the interrupt is able to be triggered when the IRQ is disabled (makes sense given no debounce), and the HAL routine for clearing the pending interrupt does not seem to work. I also found, during debugging, after the initial run through the ISR, that ICPR and ISPR are triggered, which seems to cause the second (erroneous) run through the ISR. These seem to be the "interrupt clear pending register" and "interrupt set pending registers" although I do not find these in the Reference Manual for this chip. The documentation I happened to find on Keil seemed inconsistent with my debugger findings.

Reading through the reference manual, it seems that writing a 1 to the EXT1_PR is the way to clear a pending register, and I see this actually happening while debugging, but does not prevent the double fire of my ISR. I see no mention of the ICPR and ISPR in the reference manual which seem to be the registers allowing this double fire to happen. Is this a peripheral vs NVIC issue? Does the HAL support a solution? This would seem like a fairly common problem to want to overcome.

Thanks
 

MrChips

Joined Oct 2, 2009
30,823
I am an STM32F programmer but not currently using CubeMX or HAL (for legacy reasons).
I would be rather reluctant to turn off interrupts and back on again. I leave interrupts on all the time. If you anticipate switch bounce on an interrupt pin I would choose to design around it rather than messing about with disable/enable interrupts.
 

miniwinwm

Joined Feb 2, 2018
68
Have you tried calling NVIC_ClearPendingIRQ() before re-enabling your interrupt? I don't know if enabling an interrupt in the NVIC clears any pending interrupt if one is waiting there.
 

Thread Starter

Stuntman

Joined Mar 28, 2011
222
MrChips - I understand your method. This situation is tricky as the device can be triggered by a variety of signals, some with more integrity than others, so I want to be able to tune this "filter" in software.

miniwinwm - I did not know there was this function in the HAL. I did some looking and found that it does indeed reside in the cortex.c :

Code:
void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
  /* Check the parameters */
  assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
 
  /* Clear pending interrupt */
  NVIC_ClearPendingIRQ(IRQn);
}
Located in core_cm0.h
Code:
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
  NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); 
}
I called the function and it stops the double-trigger! So am I correct in assuming that I was clearing the interrupt bit at the peripheral (ext interrupt), but not clearing the bit in the NVIC for that channel (IRQ 4_15)?

Thank you for your help! I'm baffled why I find no reference to the use of this function anywhere in the HAL inc & src comments.
 

miniwinwm

Joined Feb 2, 2018
68
MrChips - I understand your method. This situation is tricky as the device can be triggered by a variety of signals, some with more integrity than others, so I want to be able to tune this "filter" in software.

miniwinwm - I did not know there was this function in the HAL. I did some looking and found that it does indeed reside in the cortex.c :

Code:
void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
  /* Check the parameters */
  assert_param(IS_NVIC_DEVICE_IRQ(IRQn));

  /* Clear pending interrupt */
  NVIC_ClearPendingIRQ(IRQn);
}
Located in core_cm0.h
Code:
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
  NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
I called the function and it stops the double-trigger! So am I correct in assuming that I was clearing the interrupt bit at the peripheral (ext interrupt), but not clearing the bit in the NVIC for that channel (IRQ 4_15)?

Thank you for your help! I'm baffled why I find no reference to the use of this function anywhere in the HAL inc & src comments.
Yes, your assumption is correct. A possible reason you have not found much documentation on this NVIC feature could be that the NVIC is an ARM Cortex feature, not an ST specific one. Documentation will be found for it in ARM docs rather than ST ones. This is a not uncommon bugbear of programming ARM devices - where to find the information!
 
Top