数码小叶 发表于 2020-6-18 11:01:42

关于HAL库外部中断进两次中断服务的问题

最近一个应用里用到了STM32F4的两个外部中断,但是最终结果一直不对,发现仿真是正确的,单独运行就不正确,多次调试后发现问题出现在中断上,中断服务函数进了两次,但是这个应用只允许进一次中断
在网上搜索到问题的原因

Q: When I cleared the interrupt as the last instruction in the ISR,
the ISR code is called immediately upon exit half the time. Is there a
possibility of race condition ?

Answer:
The core (Cortex-M3) generates bufferable write transfer. This mean
that the CPU consider that the data is written from an AHB point of
view while the APB write transfer is managed by the AHB2APB bridge and
could be written later. In this case the CPU left the interrupt
routine while the interrupt is not yet cleared the CPU will re-enter
again on the interrupt handler. To avoid this race condition :

1) ISR routine has to clear the interruptperipheral flag when just
entering in the routine to avoid interrupt missing.

2)ISR routine has to Implement a write to the APBperipheral register
( to clear the peripheral flag) then followed by a readaccess to the
same register/flag. This operation will force the write buffer to
complete the effective write and will stall the CPU until the
effective write of the bit in the register. Thereforeit is
independent from the AHB/APB ratio prescaler.
Here an example :

STR R1, ; Store R1 registerperipheral   register( or
using bit-banding peripheral address)

LDR R2, ; Load the peipheral register; This willhold the
CPU until the effective write of R1.

Use Cortex-M3 Bit-banding feature for interrupt clearing since it is
an atomic operation and NVIC pending interrupts will be ignored during
this operation, however Read-Modify-Write is not.


知道了问题出现的原因是AHB2APB桥延迟,其中看到几条建议:
1)进入中断后,判断了相应标志位,就clear之,在作后续的处理
3、解决方法:清中断标志,只要不是中断函数的最后一条语句就没问题了。
当前这个情况下把程序下载到板子上运行的时候,按下按键,LED的状态会翻转两次,后来尝试改了一下软件生成的代码,将清中断标志位那条语句放到调用中断回调函数之后就可以了



程序原本的代码:


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
      if(GPIO_Pin == GPIO_PIN_8)
      {
                xxxxxxxxxxxxxxxxxxxxxxxxx;

      }
      else if(GPIO_Pin == GPIO_PIN_9)
      {
                xxxxxxxxxxxxxxxxxxxxxxxxx;
      }
}


原本的清标志是自动生成的


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);
}
}



按照建议,改成如下依旧无效果


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
       __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
      if(GPIO_Pin == GPIO_PIN_8)
      {
                xxxxxxxxxxxxxxxxxxxxxxxxx;

      }
      else if(GPIO_Pin == GPIO_PIN_9)
      {
                xxxxxxxxxxxxxxxxxxxxxxxxx;
      }
}

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);
             __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
   }
}

lebment 发表于 2020-6-18 11:38:26

这时候示波器应该掏出来看看了。

数码小叶 发表于 2020-6-19 09:03:50

lebment 发表于 2020-6-18 11:38
这时候示波器应该掏出来看看了。

示波器干嘛。。。??
页: [1]
查看完整版本: 关于HAL库外部中断进两次中断服务的问题