你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】EXTI 重复配置两次导致误触发中断的问题

[复制链接]
STMCU小助手 发布时间:2022-2-26 16:02
前言
有些工程师非常的小心,小心到甚至在程序中对一个外设配置完一次还不放心,还要再配置一次。这本身看起来没有什么问题,但是在特定的外设中,反而会不小心造成一些小问题,比如这里所要说的 EXTI。

问题
某客户在其产品的设计中,使用了 STM32F302CCT6。客户在开发过程中,其所配置的 EXTI 外部中断,在外部没有中断信号的情况下,上电后运行程序,总是会进入 EXTI 中断程序一次。

调研
1.了解问题
客户在开发中使用了 STM32F30x 的标准外设库 STM32F30x_DSP_StdPeriph_Lib_V1.2.3,在其程序设计中,参考了EXTI_Example 例程的代码,一开始在初始化过程中先执行了一次 EXTI15_10_Config()将 PC13 设置为外部中断口,设置为下降沿触发中断(PC13 外部有上拉电阻)。EXTI15_10_Config()函数原型如下:
  1. /**

  2. * @brief Configure PC13 in interrupt mode
  3. * @param None
  4. * @retval None
  5.   */
  6.   static void EXTI15_10_Config(void)
  7.   {
  8.   /* Enable GPIOC clock */
  9.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

  10. /* Enable SYSCFG clock */
  11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

  12. /* Configure PC13 pin in input pull-down mode */
  13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  14. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  15. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  16. GPIO_Init(GPIOC, &GPIO_InitStructure);

  17. /* Connect EXTI13 Line to PC13 pin */
  18. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);

  19. /* Configure EXTI13 line */
  20. EXTI_InitStructure.EXTI_Line = EXTI_Line13;
  21. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  22. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  23. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  24. EXTI_Init(&EXTI_InitStructure);

  25. /* Enable and set EXTI15_10 Interrupt to the lowest priority */
  26. NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
  27. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
  28. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  29. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  30. NVIC_Init(&NVIC_InitStructure);
  31. }
复制代码

客户在后面的程序中,在使用 EXTI 之前再调用了一次 EXTI15_10_Config()将 PC13 设置为外部中断口。
调试运行的时候,发现 PC13 在没有外部触发下降沿信号的时候(经示波器确认),上电时总会进入外部中断服务程序EXTI15_10_IRQHandler 中。

2.问题分析
如果仔细研究过程序,其实这个问题并不难知道。在执行第一次的 EXTI15_10_Config()之后,PC13 作为 EXTI13 外部中断已经开启。在这种情况下,如果再执行一次 EXTI15_10_Config(),我们来看看这里边究竟有什么情况?
仔细查看 EXTI15_10_Config()的程序内容,注意到这一句:
  1. /* Connect EXTI13 Line to PC13 pin */
  2. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
复制代码

也就是说,EXTI15_10_Config()调用了 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13)来将 PC13配置为 EXTI13 中断源。来看一下 SYSCFG_EXTILineConfig 这个函数的原型,它存在于 stm32f30x_syscfg.c 文件中。

  1. /**
  2. * @brief Selects the GPIO pin used as EXTI Line.
  3. * @param EXTI_PortSourceGPIOx : selects the GPIO port to be used as source
  4. * for EXTI lines where x can be (A, B, C, D, E, F, G,
  5. H).
  6. * @param EXTI_PinSourcex: specifies the EXTI line to be configured.
  7. * This parameter can be EXTI_PinSourcex where x can be (0..15)
  8. * @retval None
  9. */
  10. void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)
  11. {
  12. uint32_t tmp = 0x00;
  13. /* Check the parameters */
  14. assert_param(IS_EXTI_PORT_SOURCE(EXTI_PortSourceGPIOx));
  15. assert_param(IS_EXTI_PIN_SOURCE(EXTI_PinSourcex));

  16. tmp = ((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
  17. SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp;
  18. SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 *
  19. (EXTI_PinSourcex & (uint8_t)0x03)));
  20. }
复制代码
SYSCFG_EXTILineConfig 这个函数的执行流程是这样的:先将 SYSCFG_EXTICR 外部中断配置寄存器中相对应的位清零,然后再写入新值。

也就是说,在此 PC13 作为 EXTI13 中断的例子中,当执行“SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp;”时,SYSCFG_EXTICR4 的 EXTI13[3:0]清零,将 EXTI13 外部中断的输入源设置为 PA13(默认);再执行“SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 * (EXTI_PinSourcex &(uint8_t)0x03)));”时,SYSCFG_EXTICR4 的 EXTI13[3:0]写入值 0x02,将 EXTI13 外部中断的输入源选择为 PC13。


由此,产生中断的原因很清楚:
1. 第一次执行 EXTI15_10_Config(),使能了 EXTI13 的中断,中断源来自 PC13;
2. 第二次执行 EXTI15_10_Config(),在调用 SYSCFG_EXTILineConfig 配置 EXTI13 中断源时,先将中断源切回至PA13;由于失去了 PC13 引脚上的高电平,在内部产生了一个下降沿,因此触发了 EXTI13 中断(之前已被使能),进入中断服务程序执行代码;
3. 从中断服务程序返回,再将 EXTI13 中断源重新配置到 PC13。

所以,误触发而进入中断服务程序的原因就是这样。

3.问题解决
问题解决很简单,EXTI13 既然已经配置好了,就不要再去重复进行配置了,没有必要,浪费效率且造成小问题。要使用和不要使用只要通过操作 EXTI_IMR 寄存器使能或禁用相应的中断就可以了。如果在特殊情况下非要重新配置的话,也要注意一下这个问题,先禁用中断。
   
结论
由于 SYSCFG_EXTILineConfig()函数在配置 EXTI 中断源时,会先将中断源配置到默认中断源后再配置到实际要使用的中断源,这样重复执行 EXTI15_10_Config()就存在着误触发中断的风险,需加以注意。
   
处理
去掉重复配置的代码即可


收藏 评论0 发布时间:2022-2-26 16:02

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版