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

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

[复制链接]
STMCU小助手 发布时间:2022-2-26 16:02
前言# I$ x* T  q1 Z! l8 q* D
有些工程师非常的小心,小心到甚至在程序中对一个外设配置完一次还不放心,还要再配置一次。这本身看起来没有什么问题,但是在特定的外设中,反而会不小心造成一些小问题,比如这里所要说的 EXTI。
- z6 A+ A, J+ N: h
$ }) g3 s6 }$ {& M3 x3 n  W: m问题
& {% f8 y8 c6 c& o, H) a某客户在其产品的设计中,使用了 STM32F302CCT6。客户在开发过程中,其所配置的 EXTI 外部中断,在外部没有中断信号的情况下,上电后运行程序,总是会进入 EXTI 中断程序一次。
) L/ `2 ~% m2 [, O9 @" R! D# h# f" s* j5 z6 h8 f+ \
调研
2 c* j: I3 e0 i# j& D2 m1.了解问题1 g+ W; O; `! y- Y
客户在开发中使用了 STM32F30x 的标准外设库 STM32F30x_DSP_StdPeriph_Lib_V1.2.3,在其程序设计中,参考了EXTI_Example 例程的代码,一开始在初始化过程中先执行了一次 EXTI15_10_Config()将 PC13 设置为外部中断口,设置为下降沿触发中断(PC13 外部有上拉电阻)。EXTI15_10_Config()函数原型如下:
: Y: U( G* T8 r( r2 Y' w# E
  1. /**
    ; v& q0 I! p" H; f8 q

  2. 7 N. w& L4 _% L9 q+ [
  3. * @brief Configure PC13 in interrupt mode
    5 ?  s4 A5 F, m, J$ Z# B2 R
  4. * @param None
    / x' ^! y3 n) F; i8 |
  5. * @retval None/ V$ c& w' h- o! w- Z
  6.   */
    ' `: F$ I; R2 q3 D; y* s
  7.   static void EXTI15_10_Config(void)3 ~" g& f/ c: m: B3 n
  8.   {8 A  I# l; N, a/ N( D) W, E
  9.   /* Enable GPIOC clock */
    - y6 N* f( G( r' {1 L, Q# I
  10.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);6 p- G& l$ p1 G9 ^) f2 a; z7 v
  11. 2 Z6 i9 C# y. u4 B# k
  12. /* Enable SYSCFG clock */
    / l2 K. `' |& k! J1 N5 H+ {7 @
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);- Q8 Y5 t3 G; o/ u  e9 t

  14. 7 L1 U! Z) r7 L9 w3 m3 f9 E( f
  15. /* Configure PC13 pin in input pull-down mode */
    . d7 p% Z, o8 Y% z) E
  16. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;: d2 h' D6 h7 @0 V+ C
  17. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    2 l* a- Q' k+ P) y5 W5 k& C) Y
  18. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;) c  I) \  N7 `' a2 q8 Y& g, [
  19. GPIO_Init(GPIOC, &GPIO_InitStructure);1 n0 [7 R3 F, e" B$ m( L& S

  20. # V$ p) I3 t( ~0 e4 I
  21. /* Connect EXTI13 Line to PC13 pin */' G* R" G9 v* R$ d
  22. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);( ?6 p) f( _6 n. o7 r2 j

  23. 0 C8 _6 `2 c, x2 h8 [
  24. /* Configure EXTI13 line */
    8 a/ W8 k: T# x5 F; Z6 n
  25. EXTI_InitStructure.EXTI_Line = EXTI_Line13;
    8 o# A' ?" W5 ^1 D! b, b4 C
  26. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    # R/ g; @, `  e& J6 X" l$ T/ ^/ `
  27. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;0 O9 l. w& A9 V, X$ P
  28. EXTI_InitStructure.EXTI_LineCmd = ENABLE;% i. d- ^: d9 H1 a3 F. g
  29. EXTI_Init(&EXTI_InitStructure);
    % ^1 J" X# s1 j
  30. 5 E- P; I4 U0 b2 c  b
  31. /* Enable and set EXTI15_10 Interrupt to the lowest priority */
    ; {; Z3 R9 J3 ~) X4 J
  32. NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
    / R7 B5 z( A4 \- o
  33. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    6 a3 t5 p7 n2 D( @, p
  34. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    * I6 B3 a0 Y5 F
  35. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;8 B" ~9 j5 M$ t8 D6 ~' a
  36. NVIC_Init(&NVIC_InitStructure);
    3 w+ Q" m: e, G6 f# P
  37. }
复制代码

! P* d5 q; y  I客户在后面的程序中,在使用 EXTI 之前再调用了一次 EXTI15_10_Config()将 PC13 设置为外部中断口。. H* m" A6 g- z
调试运行的时候,发现 PC13 在没有外部触发下降沿信号的时候(经示波器确认),上电时总会进入外部中断服务程序EXTI15_10_IRQHandler 中。% T! n* `* b' J% j  @) }. `0 g8 Q

( t& \! Q' ^- H$ L% [' @- @2.问题分析/ q5 l4 k3 T  v* G" d6 b3 o3 X
如果仔细研究过程序,其实这个问题并不难知道。在执行第一次的 EXTI15_10_Config()之后,PC13 作为 EXTI13 外部中断已经开启。在这种情况下,如果再执行一次 EXTI15_10_Config(),我们来看看这里边究竟有什么情况?: S; O% x8 q- I
仔细查看 EXTI15_10_Config()的程序内容,注意到这一句:
& c2 T- d% A1 d# d  q4 ]2 \
  1. /* Connect EXTI13 Line to PC13 pin */
    , p5 [+ s' L1 }" [  ]
  2. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
复制代码
% T  D. t  p. H8 D7 v; l: }$ _; _
也就是说,EXTI15_10_Config()调用了 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13)来将 PC13配置为 EXTI13 中断源。来看一下 SYSCFG_EXTILineConfig 这个函数的原型,它存在于 stm32f30x_syscfg.c 文件中。5 ]0 ~7 y- S- l# E0 G; X

) l7 \# y1 I3 p7 w9 I
  1. /**
    & q3 {2 x4 x1 m9 ?! U2 E* N
  2. * @brief Selects the GPIO pin used as EXTI Line.
    + y  G' ~7 G+ N3 U+ B/ o
  3. * @param EXTI_PortSourceGPIOx : selects the GPIO port to be used as source
    2 w' ^7 ?$ s, v  v0 W4 E/ P# `
  4. * for EXTI lines where x can be (A, B, C, D, E, F, G,7 s; X) P* {! R6 B: m* e
  5. H).
    " o; k& w" H5 |- n
  6. * @param EXTI_PinSourcex: specifies the EXTI line to be configured.
    3 v! g# G  j- d3 L7 Z. y
  7. * This parameter can be EXTI_PinSourcex where x can be (0..15)# ^, q+ D9 n3 {
  8. * @retval None& V3 L' v6 _( w4 c/ b& W- q
  9. */
    % Z; H+ a" N6 }$ g& z5 C/ D
  10. void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex)
    ! b: Z, G) Z9 q
  11. {
    8 J( [1 |; ~5 b% C1 Q3 A
  12. uint32_t tmp = 0x00;
    7 p* z" ~0 n  I) J, W4 i: W5 w
  13. /* Check the parameters */
    + p. S7 G& e1 k/ Z( E; w
  14. assert_param(IS_EXTI_PORT_SOURCE(EXTI_PortSourceGPIOx));
    # h1 r" v" i( J
  15. assert_param(IS_EXTI_PIN_SOURCE(EXTI_PinSourcex));. C! m/ X6 a- w4 e8 K& f; {

  16. ' f9 X/ |; Q8 X+ b1 w! G
  17. tmp = ((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03));
    : u( _" `8 e8 a, w, e: g8 `% l
  18. SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp;' F! F4 n) o6 D
  19. SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 *
    0 R4 e- Z2 ^0 e* |6 {
  20. (EXTI_PinSourcex & (uint8_t)0x03)));
    2 N" D* P/ U. j5 |
  21. }
复制代码
SYSCFG_EXTILineConfig 这个函数的执行流程是这样的:先将 SYSCFG_EXTICR 外部中断配置寄存器中相对应的位清零,然后再写入新值。
  r& s0 U- W  k- p! [4 k5 b7 D3 ^: ?/ a8 v7 {
也就是说,在此 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。
) [( @7 ?1 G/ }) k) R
" |- j/ i5 r' A8 O1 D
* q9 D& L, b) H2 \) G9 ]4 k* C由此,产生中断的原因很清楚:2 h) W5 i8 z3 m6 [' Z& h
1. 第一次执行 EXTI15_10_Config(),使能了 EXTI13 的中断,中断源来自 PC13;
( [1 L. n, q0 n2. 第二次执行 EXTI15_10_Config(),在调用 SYSCFG_EXTILineConfig 配置 EXTI13 中断源时,先将中断源切回至PA13;由于失去了 PC13 引脚上的高电平,在内部产生了一个下降沿,因此触发了 EXTI13 中断(之前已被使能),进入中断服务程序执行代码;
. d4 h. l( H! b1 p  f3. 从中断服务程序返回,再将 EXTI13 中断源重新配置到 PC13。: G/ j. r2 d7 j1 s; o* ~4 W
2 M9 @  _0 ~3 \9 t) Y& q
所以,误触发而进入中断服务程序的原因就是这样。$ |- ~; X4 `$ Z, F: p
) N- r) G0 F' m. C6 M" S( V
3.问题解决
$ q7 t3 n+ g0 W# w* @9 h& V问题解决很简单,EXTI13 既然已经配置好了,就不要再去重复进行配置了,没有必要,浪费效率且造成小问题。要使用和不要使用只要通过操作 EXTI_IMR 寄存器使能或禁用相应的中断就可以了。如果在特殊情况下非要重新配置的话,也要注意一下这个问题,先禁用中断。
3 x9 d' R+ i  L   ) Y% B& B  C! g5 r+ J
结论+ i- F/ {7 b2 H! A& v: ~3 \1 i- A" m
由于 SYSCFG_EXTILineConfig()函数在配置 EXTI 中断源时,会先将中断源配置到默认中断源后再配置到实际要使用的中断源,这样重复执行 EXTI15_10_Config()就存在着误触发中断的风险,需加以注意。. \5 A$ I" K) b" g' A
   3 @" _/ b) M/ ~! ^" s
处理% ^, z8 X8 Z' F
去掉重复配置的代码即可
( L3 W- W* \% x$ p  q7 P- r: a" o1 @# W. Z; w/ A" |8 }8 D

/ T# a4 D% X, s& o( E
赞 收藏 评论0 发布时间:2022-2-26 16:02

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版