第三篇文章——STM32中断系统
异常类型
编号0 ~ 15中,除去编号为0和7 ~ 10这5个未用的异常编号,共10个系统异常。
编号16 ~ 255,共240个外部中断,简称IRQ。外部中断的编号为IRQ#0 ~ IRQ#239。
由于CM3的硬件描述代码(HDL)是可以被修改的,使用CM3核的芯片厂商可以精简外部中断的数量,如STM32 F10x根据芯片类型支持的外部中断数为60/68。
NMI
NonMaskable Interrupt,不可屏蔽中断,通过NVIC连接一条NMI输入信号线,用于紧急事件的触发,其优先级在最高优先级(-3)之后,系统启动后的任何时间都可触发。
异常向量表
异常向量表是一个WORD数组,数组编号为异常编号,WORD元素的值为对应的异常服务例程(ESR)的入口地址。
当一个异常发生后,硬件会根据异常编号计算出在向量表中的偏移量,然后取出ESR的入口地址,并跳转执行。
向量表在地址空间中的位置是可以设置的(0xE000ED08 向量表偏移量寄存器VTOR),如果向量表保存在ROM/Flash中,通常是在ROM/Flash的起始处保存。如果在RAM中调试系统,向量表一般保存在RAM中,VTOR要保存向量表在RAM中的起始地址。
向量表的起始地址是有对齐限制的,具体见《cortex-M3权威指南 Chapter7.3》。
TBLOFF设置异常向量表(0号异常:MSP初始值)相对起始地址(FLASH or SRAM的起始地址)的偏移。
如果需要动态的更改向量表,则对于任何器件来说,向量表的起始初都包含一下向量:
- 主堆栈指针(MSP)的初始值;
- 复位向量;
- NMI;
- 硬Fault服务例程。
MSP的初始值会在可执行文件链接时由链接文件指定并设置在烧写地址的起始初,TBLOFF和TBLBASE必须在系统启动之后(Reset_Handle中或之后)设置好。
复位序列
当发生复位异常后,CM3执行下面两个操作:
- 从地址0x0000 0000处取出MSP的初始值;
- 从地址0x0000 0000处取出PC的初始值,这个值是复位向量的入口地址,然后从这个值所对应的地址处取指。
(STM32可以配置喂从User FLASH、SYSTEM FLASH或者Sram启动。congUser Flash启动时,从User Flash对应的起始地址0x0800 0000处取出MSP,0x08000 0004取出PC的初始值,指向Reset_handler的第一条指令所在地址,然后指向Reset_Handler。从Sram启动时,也是从其对应处取MSP和PC的初始值)。
为什么在运行复位ESR之前要初始化MSP呢?
因为可能第一条指令还没来得及执行,就发生了NMI或其他fault。MSP初始化好后就以及为它们的服务例程准备好了堆栈。
NVIC
Nested Vectored Interrupt Controller,嵌套向量中断控制器。有其名可知,NVIC支持优先级、中断抢占(中断嵌套),还可在中断服务程序运行时动态更改中断的优先级而不必担心重入。
由CM3核内外设和核外外设产生的中断,除SysTick之外,全部连接到NVIC的中断输入信号线,包括NMI。
优先级
CM3中,优先级的数值越小,则优先级越高。高优先级的异常会抢占低优先级异常,即中断会发生嵌套。
有3个系统异常:复位、NMI和硬件fault的优先级是固定的,且为负值,高于其他所有异常。其他所有异常的优先级都可以设置。
每个异常的优先级都可以通过其优先级配置寄存器来设置。CM3的优先级配置寄存器有8位,也即可以支持256级优先级。但实际上芯片厂商只会使用高几位,如STM32 F10xx的异常优先级寄存器只使用了高4位,如此只能支持16种优先级。CM3允许的最少使用位数为3个位,亦即至少要支持8级优先级。如下: