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

异常类型分为:系统异常和外部中断
系统异常:编号为 1-15
外部中断;编号大于等于16
在这里插入图片描述
在这里插入图片描述

优先级的定义

原则上, 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,如图:
在这里插入图片描述

如何理解支持 128级抢占?

在这里插入图片描述
7位用来设置抢占优先级,1位用来设置子优先级

控制开关的寄存器有了,那么优先级大小写在哪个寄存器呢?
如下图所示:每个中断配备一个8位的寄存器(或者说是8个位)来设定优先级,一共配备了240个这样的8位寄存器,对于二进制来说8位能表达的数字有2的8次方即256个数(0—255),足以表示240个优先级了。
在这里插入图片描述
设置好的优先级放入结构体(写入寄存器),如下图箭头
在这里插入图片描述
理解代码:
#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的结合,具体看代码。)
在这里插入图片描述
绿色箭头所指左移4位,是由于stm32用高四位来表达优先级,如下图所示,需要将低四位数据移过去,具体看下面的优先级分组。(因为一般数据都是从低位表达,不够表示再加几个高位,每加一个高位,范围扩大2倍)
在这里插入图片描述
接下来谈谈怎么分组,分组的结果如何写入寄存器?
如何分组:
如下图所示,权威指南的一个例子,只用高三位来表示优先级
在这里插入图片描述
在图中, [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。
其他分组情况:在这里插入图片描述

那如果用高四个位表示:
在这里插入图片描述
就有16个优先级了,将该16个优先级分组,有5组分法:
在这里插入图片描述
用FreeRTOS操作系统,stm32f1x,官方建议设置为NVIC_PriorityGroup_4,即4个位都用来表示强占优先级,范围为:0-15,0个位表示子优先级,即都为0;只用了高四位,第四位默认只读,读回0。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

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

#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是什么呢?
在这里插入图片描述
也是个宏定义,#define AIRCR_VECTKEY_MASK((uint32_t)0x05FA0000),是一个置为初始化的数据,低3位都为0,刚好NVIC_PriorityGroup;只用了3位,相或后就相当于相加,得到新数据,再初始化AIRCR这个32位的寄存器,如图

在这里插入图片描述
在这里插入图片描述
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
在这里插入图片描述

如图
在这里插入图片描述
刚好下面的数据成员偏移地址就是 0x10 ,也就是0xE000E D010在这里插入图片描述
应该是这样:
在这里插入图片描述

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

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值