Cortex‐M3异常类型,NVIC与中断控制

时间:2024-03-22 18:35:22

异常类型分为:系统异常和外部中断
系统异常:编号为 1-15
外部中断;编号大于等于16
Cortex‐M3异常类型,NVIC与中断控制
Cortex‐M3异常类型,NVIC与中断控制

优先级的定义

原则上, CM3 支持 3 个固定的高优先级和多达 256 级的可编程优先级,并且支持 128
级抢占
(128 的来历请见下文分解——译注)。但是,绝大多数 CM3 芯片都会精简设计,以致实际上支持的优先级数会更少,如 8 级, 16 级, 32 级等。它们在设计时会裁掉表达优先级的几个低端有效位,

如何理解多达 256 级?
由上面的外部中断清单IRQ #0—IRQ #239,可知共支持240个外部中断源,每个中断的开与关(即使能与失能)由某个位控制,那240个中断就需要240个位,若使用32位的寄存器,32位*8=256位,即8个32位寄存器就足以控制240个中断的开,对应中断的关也需要8个32位寄存器,分别为SETENAx,CLRENA,如图:
Cortex‐M3异常类型,NVIC与中断控制

如何理解支持 128级抢占?

Cortex‐M3异常类型,NVIC与中断控制
7位用来设置抢占优先级,1位用来设置子优先级

控制开关的寄存器有了,那么优先级大小写在哪个寄存器呢?
如下图所示:每个中断配备一个8位的寄存器(或者说是8个位)来设定优先级,一共配备了240个这样的8位寄存器,对于二进制来说8位能表达的数字有2的8次方即256个数(0—255),足以表示240个优先级了。
Cortex‐M3异常类型,NVIC与中断控制
设置好的优先级放入结构体(写入寄存器),如下图箭头
Cortex‐M3异常类型,NVIC与中断控制
理解代码:
#define SCS_BASE (0xE000E000)
#define NVIC_BASE (SCS_BASE + 0x0100)
可知NVIC基地址:NVIC_BASE=SCS_BASE + 0x0100=0xE000E000+0x0100=0xE000E100
将基地址强制转化为NVIC_Type结构体指针 ,用宏定义取别名为NVIC ,NVIC就是指向该类型结构体指针了
#define NVIC ((NVIC_Type *) NVIC_BASE)
如下图,在NVIC_Init 函数中通过
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;来设置优先级。
(tmppriority为PreemptionPriority和SubPriority的结合,具体看代码。)
Cortex‐M3异常类型,NVIC与中断控制
绿色箭头所指左移4位,是由于stm32用高四位来表达优先级,如下图所示,需要将低四位数据移过去,具体看下面的优先级分组。(因为一般数据都是从低位表达,不够表示再加几个高位,每加一个高位,范围扩大2倍)
Cortex‐M3异常类型,NVIC与中断控制
接下来谈谈怎么分组,分组的结果如何写入寄存器?
如何分组:
如下图所示,权威指南的一个例子,只用高三位来表示优先级
Cortex‐M3异常类型,NVIC与中断控制
在图中, [4:0]没有被实现,所以读它们总是返回零,写它们则忽略写入的值。能够使用的 8 个优先级为: 0x00(最高), 0x20, 0x40, 0x60, 0x80,0xA0, 0xC0 以及 0xE0。
为什么是这写数呢?用二进制分析一波就知道了
0x00 0000 0000
0x20 0010 0000
0x40 0100 0000
0x60 0110 0000
0x80 1000 0000
0xA0 1010 0000
0xC0 1110 0000
看高三个位其实是0-7的二进制,高四位为0,相当于0—7左移了一位,大小相对于乘以2。
其他分组情况:Cortex‐M3异常类型,NVIC与中断控制

那如果用高四个位表示:
Cortex‐M3异常类型,NVIC与中断控制
就有16个优先级了,将该16个优先级分组,有5组分法:
Cortex‐M3异常类型,NVIC与中断控制
用FreeRTOS操作系统,stm32f1x,官方建议设置为NVIC_PriorityGroup_4,即4个位都用来表示强占优先级,范围为:0-15,0个位表示子优先级,即都为0;只用了高四位,第四位默认只读,读回0。
Cortex‐M3异常类型,NVIC与中断控制

Cortex‐M3异常类型,NVIC与中断控制
Cortex‐M3异常类型,NVIC与中断控制

Cortex‐M3异常类型,NVIC与中断控制

那么优先级分组的结果写在哪个寄存器呢?
Cortex‐M3异常类型,NVIC与中断控制
应用程序中断及复位控制寄存器(AIRCR)的10:8位,即10,9,8,三位控制优先级分组,2的3次方为8,刚好能把下表的0—7种分组方式表示。
CM3 还把 256 级优先级按位分成高低两段,分别是抢占优先级和亚优先级,
Cortex‐M3异常类型,NVIC与中断控制
而对于stm32f1x只用高4位产生5种分组方式,后5种:
0位抢占优先级,4位子优先级
1位抢占优先级,3位子优先级
2位抢占优先级,2位子优先级
3位抢占优先级,1位子优先级
4位抢占优先级,0位子优先级
低四位空白默认为0,如图
Cortex‐M3异常类型,NVIC与中断控制
代码中这样宏定义,然后根据这个分组位置
Cortex‐M3异常类型,NVIC与中断控制

注意到Group数和地址是相反的,0组对应0x700,4组对应0x300
Cortex‐M3异常类型,NVIC与中断控制
传入函数,初始化。
Cortex‐M3异常类型,NVIC与中断控制
接下来分析一下是怎么样是一个过程,即看懂这个语句:
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
右键,Go To Definition of “”后就明白了,和上面NVIC一样
Cortex‐M3异常类型,NVIC与中断控制
SCB_Type是结构体别名
SCB_Type *就是指向该种结构体的指针
Cortex‐M3异常类型,NVIC与中断控制

#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)

知道地址
SCB_BASE=0xE000E000+0x0D00=0xE000ED000
再将SCB_BASE地址转化为指向该结构体指针,用宏定义别名为SCB,也就是说SCB是结构体指针,指向了该结构体(寄存器)
#define SCB ((SCB_Type *) SCB_BASE)
通过指针访问成员函数SCB->AIRCR
给它赋值AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
AIRCR_VECTKEY_MASK是什么呢?
Cortex‐M3异常类型,NVIC与中断控制
也是个宏定义,#define AIRCR_VECTKEY_MASK((uint32_t)0x05FA0000),是一个置为初始化的数据,低3位都为0,刚好NVIC_PriorityGroup;只用了3位,相或后就相当于相加,得到新数据,再初始化AIRCR这个32位的寄存器,如图

Cortex‐M3异常类型,NVIC与中断控制
Cortex‐M3异常类型,NVIC与中断控制
AIRCR地址:0xE000_ED0C。
SCB指针指向的地址:0xE000E D000

前面说过AIRCR的10:8位,即10,9,8,三位控制优先级分组,2的3次方为8,刚好能把下表的0—7种分组方式表示,所以刚才
AIRCR_VECTKEY_MASK |NVIC_PriorityGroup;
改变的就是这3位。
举个例子:
NVIC_PriorityGroup_4 ((uint32_t)0x300
IRCR_VECTKEY_MASK((uint32_t)0x05FA000
AIRCR_VECTKEY_MASK |NVIC_PriorityGroup就是0x05FA300,分组位置是3
Cortex‐M3异常类型,NVIC与中断控制

如图
Cortex‐M3异常类型,NVIC与中断控制
刚好下面的数据成员偏移地址就是 0x10 ,也就是0xE000E D010Cortex‐M3异常类型,NVIC与中断控制

以上是个人理解,欢迎大神指导!