列表 上一篇 下一篇

STM32:STM32中断系统

中断控制器:

从80X86CPU获取中断类型号说起,整体过程:外设控制器产生的中断,由CPU的引脚INTR引入,采用电平触发,INTR信号的高电平必须维持到CPU响应中断才结束。CPU查询标志寄存器的IF位,如果置位,则响应中断,并从数据线接收外部中断号。
这里就可以看出,单CPU本身对中断的控制也就是全局中断的禁止、使能,是通过标志寄存器的IF位实现的。
那么CPU如何从数据线获取中断号呢?

  1. 硬件电路设计产生中断类型号。如通用并行接口芯片8212,具体8212怎么使用不太了解
  2. 使用可编程中断控制器获取中断号,比如8259A芯片。

另一方面,关于中断优先级的设定

  1. 软件查询
  2. 硬件查询优先方式,比如菊花链法
  3. 矢量控制优先级,比如8259A控制器实现

可以看出来8259A完全可以完成中断优先级、中断号产生这两个功能。

关于8259A具体的工作原理不说,大概介绍一下。

输入管脚:IR0~IR7,接收外设控制器产生的中断
输出管脚:INT,连接CPU的INTR管脚
输入管脚:~INTA,接收CPU的中断响应
双向:D0~D7,用于传输中断号
内部寄存器:ISR、IRR、IMR——中断屏蔽寄存器

功能描述:根据IMR(中断屏蔽寄存器)屏蔽或者使能IR0~IR7子中断。

所以这是中断控制器对控制的控制(相对于CPU标志寄存器IF位对中断的控制),一个小问题是:8259A是否也有类似于IF位的全局位呢?
设备控制器的中断线是连接到中断控制器的IR0~IR7上的,那么设备控制器本身的中断也是可以设置的,其作用和设置8259A的IMR相应位的作用一样。
这就是80X86的整个中断系统,可见对中断的控制三个位置:CPU标志寄存器IF位、中断控制器的设置、外设控制器本身的设置。

现在拿STM32的中断系统与80X86的中断系统做一下大概的比较:

80X86标志寄存器IF位与cortex m3中断控制寄存器比较
8259A控制器对应于NVIC控制器,不做具体的比较了,暂时也不太想了解太清楚。

外设控制器与STM32外设的对比

在后面将举三个例子:EXTI、USART、SDIO

可以看出来STM32的中断编程大概的步骤:

  1. 由于cortex m3内部的cpu一般按初始化设置,在操作系统移植的时候需要编程。
  2. NVIC中断控制器的编程,最开始玩stm32的时候,对usart的中断设置相当不舒服,一直认为,设置usart开启中断不就完了吗,为什么还要对NVIC编程呢。
  3. 外设控制器的中断编程

先来看看EXTI的编程。

  1. 设置GPIO要用到的所有时钟
  2. 设置NVIC
  3. GPIO初始化
  4. 设置EXTI
  5. 中断例程编写

EXTI又是什么呢?GPIO的中断为什么不直接连接到NVIC呢?本人的理解是把GPIO看成80X86中的外设,EXTI就相当于外设的控制器,用于控制GPIO等中断,这样符合起名字——外部中断/事件控制器,还需要GPIO_EXTILineConfig这样的函数来连接管脚与EXTI控制器。

三个问题:如何使能外部中断、如何禁止外部中断、如何清除中断位
外部中断的使能:设置NVIC控制器、设置EXTI控制器,相当于设置中断控制器、设置外设控制器
如何禁止外部中断:有串联的性质可知,要么在NVIC中屏蔽、要么禁止EXTI控制器的中断(或者说屏蔽EXTI线上的中断)、要么两者
清除中断位:为什么会有这个问题呢?可以说源于51单片机,对挂起寄存器(EXTI_PR)设置即可

另外需要注意的是:

  1. stm32f10x的外设库中并没有像使能、中断其他外设那样的USART_ITConfig();,可以用到的固件库也就是void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)

  2. 固件库中的void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)可以产生软件外部中断(操作软件中断事件寄存器(EXTI_SWIER))。

USART的中断控制

  1. 设置USART用到的时钟(GPIO时钟、复用时钟、USART时钟)
  2. 设置usart用到的GPIO初始化
  3. USART模块的设置初始化
  4. NVIC控制器的设置
  5. USART中断例程的编写

三个问题:如何使能USART中断、如何禁止USART中断、如何清除中断位
使能USART中断:设置NVIC控制器、设置USART模块的中断控制,相当于设置中断控制器、设置外设控制器
禁止USART中断:同样根据串联的性质,要么设置NVIC、要么设置USART、要么两者
清除中断位:同样为什么有这个问题呢?源于51单片机,但是开一下参考手册,并没有中断位概念,再看看固件库,对中断标志位的清除,只是操作了状态寄存器(USART_SR),而在USART_GetITStatus的时候需要检查控制寄存器1(USART_CR1) 、控制寄存器2(USART_CR2)、控制寄存器3(USART_CR3) ,可以看出来并没有中断位,而中断位是由其他位来表示的

需要注意的是:

  1. 并不用显式的清除中断位,而通过读写数据寄存器即可完成中断位的清除(实际上只是清楚了状态位)。
  2. 相比外部中断,多了void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)来禁止、使能USART中断,但是该函数并没有操作NVIC

SDIO的中断控制

由于对SDIO的中断控制没有做过实验,所以不是太了解,只是同样的三个问题与USART中断控制做一下比较
使能SDIO中断:设置NVIC控制器、设置SDIO模块的中断控制,相当于设置中断控制器、设置外设控制器
禁止SDIO中断:同样根据串联的性质,要么设置NVIC、要么设置SDIO、要么两者
清除中断位:同样没有中断位的概念,中断位的获取跟USART原理差不多。而且固件库也有void SDIO_ITConfig(uint32_t SDIO_IT, FunctionalState NewState)函数来禁止、使能SDIO中断。

需要注意的是:
关于SDIO模块中断的使能、禁止采用的是SDIO中断屏蔽寄存器(SDIO_MASK),虽然跟USART模块中的TXEIE、RXNEIE性质是一样的,但是采用MSAK更专业。
而且清除中断位的操作并没有直接操作SDIO状态寄存器(SDIO_STA),而是操作的SDIO清除中断寄存器(SDIO_ICR),硬件实现这样的操作的好处参见“Cortex-M3权威指南”的“NVIC与中断控制”一章。

最后说一下中断位

在8259中断控制器内部有一个中断请求寄存器IRR,存放外部输入的中断请求信号IR0~IR7,当某个IR端有中断请求时,IRR相应的位置1。可以允许8个中断请求信号同时进入,此时IRR寄存器被置成全1,当中断请求响应时,IRR的相应位复位。
想强调的是“当中断请求响应时,IRR的相应位复位。”,这个中断位与外设中断控制位的作用很相似,只不过中断控制器中的中断位在中断相应之后会自动复位,而外设控制器的中断位是给软件作参考的需要软件编程的,所以在写外设中断例程的时候清除中断位是指的外设模块中的中断位(实际上并不像51单片机、EXTI模块中那样很直接的中断位),中断控制器中的中断位不用管的。中断控制器中的中断位代表某外设的全局中断,外设的具体中断是由外设的控制器中中断位表示的,所以模块的具体中断位不止1位,有可能很多位表示不同的中断原因。另外想说的是不要误以为中断号的获取是通过软件读外设模块的中断位获得的。另外需要注意的是STM32固件库中除了开启模块中断来设置NVIC,而禁止中断是不操作NVIC的而是操作外设模块的(串联行)。不知道这方面80x86怎么做的,是操作中断控制器的屏蔽位吗?