重温STM32基础:外部中断(1)
文章目录
中断和NVIC
中断系统
是管理和执行中断的逻辑结构
- 对于外部中断来说可以是引脚发生了跳变,
- 对于定时器来说,可以是定时时间到了,
- 对于串口通信来说,可以是接收到了数据。
嵌套向量中断控制器NVIC
NVIC(Nested Vector Interrupt Controller)是内核外设。
- “嵌套”和优先级机制有关,后面会说。
- “向量”:这里理解为“一个中断号指向处理函数入口”;而“向量表”就是所有处理函数的表,也就是我们在startup code中会看到的。
一个芯片上可能有很多外设,每个外设可能都有中断。这里会有很多要解决的问题:
- 当一个中断来了之后,CPU需要知道这谁发来的,然后才能知道它要干什么。
- 而且,当中断多的时候,甚至“同时”来的时候,先处理哪个
- 或者CPU当前正在处理,来了个中断,是直接忽略它么?忽略了之后当前的处理完了,如果还要处理这个“新的”,那就需要把它先保存起来,不然就只能直接忽略。这似乎不是一个好的机制。
- 而有的时候我们就是需要在某些特定场景忽略某些中断,这应该如何处理?
- …
可以想象,如果没有NVIC(也就是说没有中断向量表),那中断处理入口可能就一个(或者几个),单靠CPU,如何解决上面的问题?
- 就需要CPU自己在这个公共入口里查询标志位来判断到底是谁发来的中断,然后再找到对应的处理函数中去处理->费时,消耗资源
- . 可能需要软件的逻辑来判断,当然最后的重担还是在CPU头上
- 软件逻辑判断,重担在CPU
- 软件逻辑判断,重担在CPU
可以发现,没有NVIC,很多事情会非常复杂,甚至做不了。
NVIC的主要功能就是一个硬件的解决方案:汇集所有中断,
- 通过向量表机制,每个外设都有专属号,直达中断处理函数,不需要轮询标志位寻找
- . 优先级机制,裁决哪个先处理
- 如果有在处理的中断就把当前的挂起(记录),还有嵌套机制
- (屏蔽机制应该是在MCU里的)检查看是不是被屏蔽
NVIC通过2,3,4把所有的东西整理一遍,然后统一通过一根线送给老板CPU。

从上图中可以看出,一个外设可能会同时占用多个中断通道,所以这里有N条线,但NVIC只有一个输出口。结合上面的解释也可以发现,中断优先顺序由开发人员指定,NVIC来实行,不需要CPU知道(CPU只要拿NVIC送来的东西就可以了)
中断源
能向 NVIC 发出 IRQ 请求的模块,叫中断源。
- 对于GPIO,EXTI依赖于它产生中断,但是GPIO不是中断源,EXTI才是中断源。因为GPIO没有直接像NVIC发出IRQ请求。
- 其他外设比如TIM, UART等,是中断源。
当中断产生时发生了什么
当中断发生的时候,会进行现场保护。老师说”这个保护工作不用我们做,由编译器完成“。这个和我之前的理解不太一致。稍微查了一下。发现自己之前的理解也不太充分。当中断发生时,Cortex-M3硬件和编译器都做了工作
- Cortex-M3硬件 做了一些关键寄存器的压栈xPSR, PC, LR, R12, R3~R0(共 8 个寄存器,约 12 个时钟周期)
- 当调用到ISR时,编译器在编译时也会在ISR中加入相应的压栈指令(序言):把R4~R11压栈(硬件没有压的);如果ISR里调用了其他函数,还会保存LR。当然,在ISR结束的时候,还有把这些内容POP的指令。
- ISR完成后硬件把报错的8个寄存器都给POP(编译器加的尾声代码)
所以中断发生的时候做的事情,是硬件和编译器共同的努力。
中断数量的支持
在课程的PPT里的“STM32中断”这一页上写了:68个可屏蔽中断通道… 这个中断通道的数量是谁决定的呢?STM32还是Cortex-M3?查了一下,这个数量是STM32决定的。
Cortex-M3本身支持240个中断通道(如下图Cortex-M3 Technical Reference Manual的截图,NVIC章节),Cortex-M3规定了NVIC 最多支持 240 个外部中断请求线(IRQ0 ~ IRQ239),以及 16 个内核异常。

顺便又再追溯了一下:Cortex-M3是基于ARMv7-M架构的,这个架构总共支持496个中断

上面这三层是“逐层收紧”:
- 496是ARMv7-M这个架构决定的内核外中断的理论上限
- Cortex-M3是架构的落地实现,也是Arm公司做的,决定了整个IP核能够最多提供多少中断线。
- 而MCU厂商(如ST公司)在购买了整个IP核之后,还会根据芯片用了多少外设、外设需要多少中断源等来决定实际用多少中断线。比如STM32F103系列,不同的型号可能支持60,68等数量的中断。
注:
- “可屏蔽中断”和“不可屏蔽中断”:可屏蔽中断指的是软件可以通过NVIC_EnableIRQ() / NVIC_DisableIRQ() 随时打开或关闭,或者说收到全局中断开关__disable_irq()的影响。而不可屏蔽中断其实只有一个,就是-14的NMI,通常连在看门狗等上面,软件不能够关掉它。
- “支持68个中断通道”,这个数目和芯片支持的外设无关:多个外设可以使用一个中断通道,也可能一个外设用一个(即使这个外设有多个中断源)
NVIC优先级分组
- 抢占优先级:与中断嵌套有关。如果中断A的优先级高于(数字更小)当前正在执行的中断B,A可以打断B,这就是中断嵌套。
- 响应优先级:如果两个中断同时被挂起等待处理,而且它们的抢占优先级相同,则响应优先级数字小的先执行;如果两个中断的抢占优先级相同,响应优先级低的正在执行,这个时候即使响应优先级高的中断来了,也不能打断正在执行的中断。所以,响应优先级是决定了“排队顺序”。不涉及打断当前正在执行的中断。
- “中断号优先级”:打个引号,因为不知道官方是不是这么叫的,反正当抢占优先级和响应优先级都一样的时候,按照中断号来排队,中断号越小,优先级越高。
STM32的中断执行不是按照“先来后到”的方式,都是按照优先级来的。
为什么折腾两种优先级分组?各有优缺点,基于应用来做取舍
- 抢占优先级会涉及中断嵌套,这会带来额外开销:压栈保存现场,层次越多风险越大(栈溢出和实时性抖动)
- 响应优先级也是表达“我很急”的意思,但不需要付出嵌套的额外开销,缺点是不能立刻马上被执行,也是一种取舍。
AI说,一般来说,会给产生真正事故的中断给与分配比较高的抢占优先级,而对于其他中断,比如外设中断,抢占优先级都是一样的,只用响应优先级来排序。这样程序行为更荣誉确定,方便调试。
外部中断 EXTI (External Interrupt)
这里的“外部”是相对于STM32芯片的“外部”。
EXTI主要指的是芯片物理引脚(Pin)上的电平变化引发的中断。
(外部中断是众多能产生中断的外设之一:为什么是“之一”?因为STM32有一大堆其他外设,很多外设都能产生中断,不需要外部引脚触发,比如定时器TIM、USART、ADC等,不需要外部引脚触发也能产生中断。)
支持的触发EXTI的方式方式:
- 上升沿
- 下降沿
- 双边沿(检测到上升或者下降的时候都触发)
- 软件触发:GPIO并没有电平变化,程序里执行一段代码就能触发中断
EXTI中断触发源
EXTI可以检测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化,EXTI会立即像NVIC发出中断申请,经过NVIC裁决后可以中断MCU当前程序,使MCU执行EXTI对于的中断程序。(来源:PPT)
但是我们不能说是”GPIO输入“引发的中断。因为它也有可能是其他外设的状态信号,比如RTC Alarm event,USB wakeup event等,通过EXTI连到NVIC,也就是这个顺序:pin/RTC/USB/… -> EXTI -> NVIC
可以发现,EXTI有多种“触发源”。可能的触发源可以在RM的Figure 21. External interrupt/event GPIO mapping 和它下面的对额外3~4根EXTI的介绍中可以看到。


引脚配置注意点
任意GPIO口都能当作外部引脚,但相同的Pin不能同时触发中断。(pin数值一样的不能作为中断)比如PA0和PB0/PA1,PB1和PC1/…不能同时用。为什么?从上面从RM中截取的“Figure21”(“EXTI和GPIO port的对应”)可以看出,所有相同Port号的GPIO引脚都连载一个数据选择器上:AFIO中断选择器。这个选择器只能从GPIOA1,GPIOB1,… GPIOG1中选择一个作为相应EXTI线。
所以,如果我们的程序需要多个中断引脚,需要选择不同号的pin脚。这里会用到AFIO。在STM32中,它主要有两个作用:
- 复用功能引脚重映射
- 中断引脚选择
PPT中的EXTI基本结构分析
课程PPT里面“EXTI基本结构”的图片画得很好

从左到右:
- 每个GPIO都有16个引脚(16根线)
- 所有引脚都接到AFIO上被选择
- AFIO选出16根线,以及PVD,RTC等其他外部中断源送入EXTI边沿检测和控制
- 最后从“EXTI边沿检测和控制”到内核NVIC。不过这里有两个注意得地方
- EXTI一共16个,但是输入NVIC时,5-9,10-15是在一根中断线上的。从程序上来看,EXTI5-9和EXTI10~15会触发同一个回调函数。如果要区分它们,还需要根据标志位来区分到底是哪个中断进来的。


- 最底下的绿框中标明了“20”,连到了“其他外设”,这里指示的是触发其他外设操作,也就是事件响应(下一章会说)。
- EXTI一共16个,但是输入NVIC时,5-9,10-15是在一根中断线上的。从程序上来看,EXTI5-9和EXTI10~15会触发同一个回调函数。如果要区分它们,还需要根据标志位来区分到底是哪个中断进来的。
RM中的EXTI结构图分析
RM中的结构框图和上面的图类似,不过这个图要从右往左看,而且体现了更多电路的细节和逻辑,所以再可以再看一下。
在RM中这个章节开始就有这个描述:The external interrupt/event controller consists of up to 20 edge detectors in connectivity line devices, or 19 edge detectors in other devices for generating event/interrupt requests.
首先两个概念:
- Interrupt(中断):要唤醒 CPU,让 CPU 执行中断服务函数(ISR)。
- Event(事件):不唤醒 CPU,直接触发另一个外设干活。

(上面是RM中的截图,在课程提供的资料中有中英文版,对应图片内容不太一样:挂起请求和中断屏蔽寄存器位置反了一下。不过仔细看了一下,它们的版本不同:中文版本是根据"参照2009年12月 RM0008 Reference Manual 英文第10版",而英语版地资料是2017年地Rev17.)
框图最上方:
- AMBA APB bus:CPU 读写 EXTI 寄存器的总线
- Peripheral interface:EXTI 的寄存器接口
- PCLK2:APB2 总线时钟,EXTI 挂在 APB2 上
- 下面挂的 5 个方块就是 EXTI 的 5 个寄存器,CPU 通过 APB 总线来配置它们。
几乎所有的线上都标着“19”,表示"这个信号总线有 19 根线宽",对应 19 条 EXTI 线并行工作(前面提到“19 edge detector in other device")
这个图应该从右往左看,它表达的是某个中断源产生中断(GPIO或者内部其他外设产生的中断),如何到达NVIC或者发送event左边两个箭头:
- 右边的 “Input Line” 对应Figure21和下面的其他EXTI Line(不仅仅是GPIO输入)。
- OR 门之后分成了两路完全独立的并行路径。 同一次跳变,既可以产生中断,也可以产生事件,或者只产生其中一个,取决于你配置了哪个 mask。
- 最左边的结果:
- to NVIC interrupt controller就是产生中断
- pulse generator(脉冲发生器)产生的是一个事件脉冲,
- 可以触发其他外设干活
- 也可以送到 Cortex-M3 内核的 Event 接口 → 用于 WFE(Wait For Event)指令唤醒 CPU
- 也可以送到电源管理单元(PWR) → 用于从 Sleep/Stop/Standby 低功耗模式唤醒
在STM32F103的RM中找到一个可以被EXTI事件触发的外设:ADC

更多推荐



所有评论(0)