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

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

[复制链接]
STMCU小助手 发布时间:2022-2-26 16:02
前言
- x9 t( F9 m! `3 h8 p' p有些工程师非常的小心,小心到甚至在程序中对一个外设配置完一次还不放心,还要再配置一次。这本身看起来没有什么问题,但是在特定的外设中,反而会不小心造成一些小问题,比如这里所要说的 EXTI。( U! g7 |1 w* y- {5 z) P5 }* c+ l

" u: ~5 A; y2 S1 Z7 T' k) d9 ?0 F问题
0 I0 I! b  }9 P某客户在其产品的设计中,使用了 STM32F302CCT6。客户在开发过程中,其所配置的 EXTI 外部中断,在外部没有中断信号的情况下,上电后运行程序,总是会进入 EXTI 中断程序一次。4 Y1 p: u% }/ l3 d+ L. E$ f7 M

$ R1 a" ^" p. V调研: v2 D) i/ f1 A+ a: J
1.了解问题1 ]. e3 [! Q/ _  i
客户在开发中使用了 STM32F30x 的标准外设库 STM32F30x_DSP_StdPeriph_Lib_V1.2.3,在其程序设计中,参考了EXTI_Example 例程的代码,一开始在初始化过程中先执行了一次 EXTI15_10_Config()将 PC13 设置为外部中断口,设置为下降沿触发中断(PC13 外部有上拉电阻)。EXTI15_10_Config()函数原型如下:
+ U% _7 y5 c& n
  1. /**
    / G$ U1 l* i( a
  2. ; ~/ f9 r2 {0 s% J% {( \3 D0 s
  3. * @brief Configure PC13 in interrupt mode  j- l# @& _$ C& f
  4. * @param None
    2 \8 q# @( D( s
  5. * @retval None
    # v  z( n) g# u. n
  6.   */+ C; k4 w! a9 p4 q
  7.   static void EXTI15_10_Config(void)
    ! }8 `% Q1 j% W4 [" i, {1 }9 W
  8.   {+ Y7 K3 X4 b& d
  9.   /* Enable GPIOC clock */& d& Z8 {0 ]: c$ O7 ^3 c
  10.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);: M  c- h" Q2 X+ d/ L9 I! v$ C

  11. * t/ e' N, n. c
  12. /* Enable SYSCFG clock */. w0 m! q3 o1 W: S
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);2 y# p4 b# `* i1 h* h# y* F

  14. ) t) Y! w) D, z2 @) E( G
  15. /* Configure PC13 pin in input pull-down mode */
    3 z0 G( J9 x) P/ j8 S: }7 C
  16. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    7 S+ ]8 `' y  e
  17. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    % F1 [5 J$ T0 c* ]2 |
  18. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    $ N& J) P: X. u2 e& W
  19. GPIO_Init(GPIOC, &GPIO_InitStructure);
    8 H5 {' Y1 }, U5 Z" V

  20. % U" f/ }" R9 y' L1 S: o& q
  21. /* Connect EXTI13 Line to PC13 pin */$ c/ P; z" u1 G- E& R% j4 h
  22. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
    # d3 a* P, A. V9 g7 `
  23. 1 W# r( D, F  l7 t, D. _
  24. /* Configure EXTI13 line */
    ; a& l- Y0 D5 M
  25. EXTI_InitStructure.EXTI_Line = EXTI_Line13;+ W* o! t; N5 z" R, @- z% a/ s
  26. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    , e' z1 z9 h& ]( V- e8 O
  27. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    ' @: @0 W# \( G+ V% z) A: ~
  28. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    . k0 M& A: T5 |0 o
  29. EXTI_Init(&EXTI_InitStructure);8 f7 t* W6 Q- M3 d
  30. ( {& R/ S. ^, G0 _
  31. /* Enable and set EXTI15_10 Interrupt to the lowest priority */3 o  y6 {+ Y% l7 ?
  32. NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;- r; ]7 Z; n+ m! p5 s
  33. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    - R  f! R. j! {; v, b
  34. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    3 h, _) y. Y! w% U) I
  35. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ! @- R) V# y5 f! b  X. w% A# u
  36. NVIC_Init(&NVIC_InitStructure);) u7 e0 Q" F. t! q7 b  \& b
  37. }
复制代码
; F. r8 x, `  t0 x8 ]
客户在后面的程序中,在使用 EXTI 之前再调用了一次 EXTI15_10_Config()将 PC13 设置为外部中断口。
6 t: R1 l1 Q* a9 w* C; l调试运行的时候,发现 PC13 在没有外部触发下降沿信号的时候(经示波器确认),上电时总会进入外部中断服务程序EXTI15_10_IRQHandler 中。
  Q$ |+ x4 x/ A" z
9 v+ P1 j0 P! i8 v# p, Z% ^- ]+ C- X0 D2.问题分析& T* X% Z4 g4 T$ I
如果仔细研究过程序,其实这个问题并不难知道。在执行第一次的 EXTI15_10_Config()之后,PC13 作为 EXTI13 外部中断已经开启。在这种情况下,如果再执行一次 EXTI15_10_Config(),我们来看看这里边究竟有什么情况?
# C9 I) u+ J5 \2 v, M! l0 f3 ~仔细查看 EXTI15_10_Config()的程序内容,注意到这一句:
1 l" U' z0 X$ d) m% B
  1. /* Connect EXTI13 Line to PC13 pin */2 b, d& S$ t# L' [! \
  2. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
复制代码

2 }. r5 y. ]5 I$ s* C  o9 Y% b" T也就是说,EXTI15_10_Config()调用了 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13)来将 PC13配置为 EXTI13 中断源。来看一下 SYSCFG_EXTILineConfig 这个函数的原型,它存在于 stm32f30x_syscfg.c 文件中。
3 N% u) S5 e* S  H/ f! |- b! |" H
1 }. Y# i+ o& J) R) s" s* H
  1. /**
    3 t! C* r, `1 j/ Y; H  W
  2. * @brief Selects the GPIO pin used as EXTI Line./ @5 s4 \6 m% A
  3. * @param EXTI_PortSourceGPIOx : selects the GPIO port to be used as source6 V/ g/ v' ?+ }( G# b3 X, O4 d
  4. * for EXTI lines where x can be (A, B, C, D, E, F, G,) c8 ]; M- U( R
  5. H).! l0 I. d& q# S# o
  6. * @param EXTI_PinSourcex: specifies the EXTI line to be configured.
    6 a: @3 r- d& N5 a- H/ u+ y1 }+ u% L
  7. * This parameter can be EXTI_PinSourcex where x can be (0..15), [! _: I6 g. {/ Y
  8. * @retval None
    $ P5 y' A; C. P& ^  W+ S, w
  9. */! H# t& X% j4 d
  10. void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)! T8 M- M4 P0 y7 d$ a9 ?6 G/ _
  11. {1 a) y, ?% W% d/ A/ P4 e$ Y" d
  12. uint32_t tmp = 0x00;2 i4 m; K/ W! N8 K
  13. /* Check the parameters */
    + F* u. W! N% T* G3 k/ T& V7 @9 n, P
  14. assert_param(IS_EXTI_PORT_SOURCE(EXTI_PortSourceGPIOx));/ z$ q2 G* w9 c7 D' G3 @
  15. assert_param(IS_EXTI_PIN_SOURCE(EXTI_PinSourcex));
    # q8 ~& \9 P3 F  T- X
  16. + j5 s! U2 {" U& f
  17. tmp = ((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
    3 T3 X, _& m$ F/ l9 @
  18. SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp;
    * k3 J! o( a0 ], n7 u
  19. SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 *' F) R0 s# i7 a  P& H5 s+ G
  20. (EXTI_PinSourcex & (uint8_t)0x03)));
    * f$ a/ a+ M5 D, e; D
  21. }
复制代码
SYSCFG_EXTILineConfig 这个函数的执行流程是这样的:先将 SYSCFG_EXTICR 外部中断配置寄存器中相对应的位清零,然后再写入新值。
6 D* }4 B5 G+ \! S, |
6 ]" {1 i8 \5 i) r6 a) }( ?7 b也就是说,在此 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。: w+ K- @8 }6 \0 g' H

2 S6 Y( x& @, A8 e8 x! o" h# d1 w& }; B$ ^4 j
由此,产生中断的原因很清楚:3 t) Z- {* N0 D" X, r
1. 第一次执行 EXTI15_10_Config(),使能了 EXTI13 的中断,中断源来自 PC13;
: t$ `8 J  B* e' L( }% V2. 第二次执行 EXTI15_10_Config(),在调用 SYSCFG_EXTILineConfig 配置 EXTI13 中断源时,先将中断源切回至PA13;由于失去了 PC13 引脚上的高电平,在内部产生了一个下降沿,因此触发了 EXTI13 中断(之前已被使能),进入中断服务程序执行代码;2 J" q+ G3 |3 A* j& b+ {$ {) V8 a
3. 从中断服务程序返回,再将 EXTI13 中断源重新配置到 PC13。1 c0 B. E1 p9 K! B$ N7 o5 s
, X7 T- f4 p/ E/ j4 E" L+ j) s
所以,误触发而进入中断服务程序的原因就是这样。
+ g5 n2 A7 d; |$ _
+ x( A  ^- K, W8 X+ u3 [1 L3.问题解决. L2 i3 z( x+ ?0 W3 m. K) Y
问题解决很简单,EXTI13 既然已经配置好了,就不要再去重复进行配置了,没有必要,浪费效率且造成小问题。要使用和不要使用只要通过操作 EXTI_IMR 寄存器使能或禁用相应的中断就可以了。如果在特殊情况下非要重新配置的话,也要注意一下这个问题,先禁用中断。
: q: r1 M& h8 r   
) r% ]/ r" V9 E- p结论2 b2 M5 [, z% b4 C, E# U
由于 SYSCFG_EXTILineConfig()函数在配置 EXTI 中断源时,会先将中断源配置到默认中断源后再配置到实际要使用的中断源,这样重复执行 EXTI15_10_Config()就存在着误触发中断的风险,需加以注意。
6 w1 O& t, ~8 n$ [% Q' y   6 h& ~3 O( u3 d
处理
0 X' O! u9 e2 _3 H. S去掉重复配置的代码即可
+ D4 Y. D2 o$ Y+ I6 X
* V, ^' Q" b% m3 i' x; l& q4 f2 d  |+ `# \3 B- p. Y0 t
收藏 评论0 发布时间:2022-2-26 16:02

举报

0个回答

所属标签

相似分享

官网相关资源

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