8.4 中断的悬起与解悬

  • 首页
  • 演化计算
  • 程序设计基础
  • 现代优化计算方法
  • 《Borland传奇》在线阅读。作者:李维
  • VC++程序设计基础
  • 用于最优化的计算智能
  • Windows API 编程
  • 操作系统教程
  • VBScript语言
  • VB开发工具
  • VB参考
  • VB语法
  • 计算机网络
  • 嵌入式系统
  • Cortex M3开发
  • ARM开发详解
  • IBM S390 系统管理
  • 电子计算机组成原理
  • Oracle编程艺术
  • 计算机代数系统
  • VFP语法、实例、函数和类库参考手册
  • Windows 2003服务器网络管理与故障解决手册
  • /a/
  • IT名企
  • 开发工具史
  • 教育
  • 英文文档
  • 程序设计经验
  • 计算机硬件发展史
  • IT名人堂
  • 编程库
  • linux 技巧
  • 计算机网络历史
  • 散论
  • 操作系统开发
  • 操作系统历史
  • 编程语言历史
  • 编程技巧
  • 网站运营
  • 智能手机
  • 网页设计
  • windows 技巧

再上一篇: 8.2 中断配置基础
上一篇: 8.3 中断的使能与除能
主页
下一篇: 8.5 中断系统设置全过程的演示
再下一篇: 8.6 软件中断
文章列表

8.4 中断的悬起与解悬

《Cortex-M3 权威指南》,嵌入式处理器开发教程。

如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响应。此 时中断被悬起。中断的悬起状态可以通过“中断设置悬起寄存器(SETPEND)”和“中断悬起清除寄 存器(CLRPEND)”来读取,还可以写它们来手工悬起中断。
悬起寄存器和“解悬”寄存器也可以有 8 对,其用法和用量都与前面介绍的使能/除能寄存器
完全相同,见表 8.2。
表 8.2 SETPEND/CLRPEND 寄存器族 (此表参考官方技术参考手册作了些改编——译者注)

SETPENDs:0xE000_E200 – 0xE000_E21C ; CLRPENDs:0xE000E280 - 0xE000_E29C

名称

类型

地址

复位值

描述

SETPEND0

R/W

0xE000_E200

0

中断 0-31的悬起寄存器,共 32个悬起位

位[n],中断#n悬起(异常号 16+n)

SETPEND1

R/W

0xE000_E204

0

中断 32-63的悬起寄存器,共 32个悬起位

SETPEND7

R/W

0xE000_E21C

0

中断 224-239的悬起寄存器,共 16个悬起位

         
         

CLRPEND0

R/W

0xE000_E280

0

中断 0-31的解悬寄存器,共 32个解悬位

位[n],中断#n解悬(异常号 16+n)

CLRPEND1

R/W

0xE000_E284

0

中断 32-63的解悬寄存器,共 32个解悬位

CLRPEND7

R/W

0xE000_E29C

0

中断 224-239的解悬寄存器,共 16个解悬位

8.4.1 优先级

每个外部中断都有一个对应的优先级寄存器,每个寄存器占用 8位,但是 CM3允许在最“粗线 条”的情况下,只使用最高 3位。4个相临的优先级寄存器拼成一个 32位寄存器。如前所述,根据 优先级组的设置,优先级可以被分为高低两个位段,分别是抢占优先级和亚优先级。优先级寄存器 都可以按字节访问,当然也可以按半字/字来访问。有意义的优先级寄存器数目由芯片厂商实现的 中断数目决定,优先级配置寄存器的详细信息在附录D中给出(表 D.18)。
表 8.3 中断优先级寄存器阵列 0xE000_E400 – 0xE000_E4EF

名称

类型

地址

复位值

描述

PRI_0

R/W

0xE000_E400

0(8位)

外中断#0的优先级

PRI_1

R/W

0xE000_E401

0(8位)

外中断#1的优先级

PRI_239

R/W

0xE000_E4EF

0(8位)

外中断#239的优先级

表8.3B 系统异常优先级寄存器阵列 0xE000_ED18 - 0xE000_ED23

地址

名称

类型

复位值

描述

0xE000_ED18

PRI_4

   

存储器管理 fault的优先级

0xE000_ED19

PRI_5

   

总线 fault的优先级

0xE000_ED1A

PRI_6

   

用法 fault的优先级

0xE000_ED1B

-

-

-

-

0xE000_ED1C

-

-

-

-

0xE000_ED1D

-

-

-

-

0xE000_ED1E

-

-

-

-

0xE000_ED1F

PRI_11

   

SVC优先级

0xE000_ED20

PRI_12

   

调试监视器的优先级

0xE000_ED21

-

-

-

-

0xE000_ED22

PRI_14

   

PendSV的优先级

0xE000_ED23

PRI_15

   

SysTick的优先级

8.4.2 活动状态

每个外部中断都有一个活动状态位。在处理器执行了其 ISR的第一条指令后,它的活动位就被 置 1,并且直到 ISR返回时才硬件清零。由于支持嵌套,允许高优先级异常抢占某个 ISR。然而, 哪怕中断被抢占,其活动状态也依然为 1(请仔细琢磨前文讲到的“直到 ISR返回时才清零)。活动 状态寄存器的定义,与前面讲的使能/除能和悬起/解悬寄存器相同,只是不再成对出现。它们也能 按字/半字/字节访问,但他们是只读的,如表 8.4所示。
表 8.4 ACTIVE 寄存器族 0xE000_E300_0xE000_E31C(此表参考官方技术参考手册作了些改编——

译者注)

名称

类型

地址

复位值

描述

ACTIVE0

RO

0xE000_E300

0

中断0-31的活动状态寄存器,共32个状态

位[n],中断 #n活动状态(异常号16+n)

ACTIVE1

RO

0xE000_E304

0

中断 32-63 的活动状态寄存器,共 32 个状

态位

ACTIVE7 RO 0xE000_E31C 0 中断 224-239 的活动状态寄存器,共 16 个

状态位

8.4.3 特殊功能寄存器 PRIMASK与 FAULTMASK

PRIMASK用于除能在 NMI和硬 fault之外的所有异常,它有效地把当前优先级改为 0(可编程 优先级中的最高优先级)。该寄存器可以通过 MRS和MSR以下例方式访问:

1. 关中断

MOV

R0,

#1

MSR

2. 开中断

MOV

PRIMASK,

R0,

R0

#0

MSR

PRIMASK,

R0

此外,还可以通过CPS指令快速完成上述功能:

CPSID i ;关中断

CPSIE i ;开中断

FAULTMASK更绝,它把当前优先级改为-1。这么一来,连硬fault都被掩蔽了。使用方案与

PRIMASK的相似。但要注意的是,FAULTMASK会在异常退出时自动清零。 掩蔽寄存器虽然能一手遮天,却都动不了NMI,因为NMI是用在最危急的情况下的。因此系统为
它开出单行道,无需挂号只是不要迟到。当NMI激活时,“谁都是省略号,唯独是你不得了,第一优 先谁比你重要”!试想,如果NMI被连接到系统的掉电报警线上,且系统是体外循环机的电源管理 器……如果因为中断被除能就视而不见,则会使体外循环机因断电而失能,体外循环序列可以被意 外终止,病人的生命也将丢失。

8.4.4 BASEPRI寄存器

在更精巧的设计中,需要对中断掩蔽进行更细腻的控制——只掩蔽优先级低于某一阈值的中断
——它们的优先级在数字上大于等于某个数。那么这个数存储在哪里?就存储在BASEPRI中。不过, 如果往BASEPRI中写0,则另当别论——BASEPRI将停止掩蔽任何中断。例如,如果我们需要掩蔽所 有优先级不高于0x60的中断,则可以如下编程:

MOV R0, #0x60

MSR BASEPRI, R0

如果需要取消 BASEPRI对中断的掩蔽,则示例代码如下:

MOV R0, #0

MSR BASEPRI, R0

另外,我们还可以使用BASEPRI_MAX这个名字来访问BASEPRI寄存器,它俩其实是同一个寄存 器。但是当我们使用这个名字时,会使用一个条件写操作。个中原因如下:尽管它俩在硬件水平上 是同一个寄存器,但是生成的机器码不一样,从而硬件的行为也不同:使用BASEPRI时,可以任意 设置新的优先级阈值;但是使用BASEPRI_MAX时则“许进不许出”——只允许新的优先级阈值比原 来的那个在数值上更小,也就是说,只能一次次地扩大掩蔽范围,反之则不行。就好像绳子打了死 结,只会越拉越紧。举例来说,检视下面的程序片断:

MSR

BASEPRI_MAX, R0

;本次设置被忽略,因为0xf0比0x60的优先级低

MOV MSR

R0, #0x40

BASEPRI_MAX, R0

;Ok。扩大掩蔽范围到优先级不高于0x40的中断

为了把掩蔽阈值降低,或者解除掩蔽,需要使用“BASEPRI”这个名字。上例中,把设置阈值
为0xf0的那条指令改用BASEPRI,则可以操作成功。显然,在用户级下是不得更改BASEPRI寄存器 的。与其它和优先级有关的寄存器一样,系统中表达优先级的位数,也同样影响BASEPRI中有意义 的位数。如果系统中只使用3个位来表达优先级,则BASEPRI有意义的值仅为0x00, 0x20, 0x40,

0x60, 0x80, 0xA0, 0xC0以及0xE0。

8.4.5 其它异常的配置寄存器

用法fault,总线fault以及存储器管理fault都是特殊的异常,因此给它们开了小灶。其中, 它们的使能控制是通过“系统Handler控制及状态寄存器(SHCSR)”(地址:0xE000_ED24)来实现 的。各种faults的悬起状态和大多数系统异常的活动状态也都在该寄存器中,如表8.5所示。
表8.5 系统Handler控制及状态寄存器SHCSR(地址:0xE000_ED24)

位段

名称

类型

复位值

描述

18

USGFAULTENA

R/W

0

用法 fault服务例程使能位

17

BUSFAULTENA

R/W

0

总线 fault服务例程使能位

16

MEMFAULTENA

R/W

0

存储器管理 fault服务例程使能位

15

SVCALLPENDED

R/W

0

SVC 悬起中。本来已经要 SVC服务例程,但

是却被更高优先级异常取代

14

BUSFAULTPENDED

R/W

0

总线 fault悬起中,细节同上。

13

MEMFAULTPENDED

R/W

0

存储器管理 fault悬起中,细节同上

12

USGFAULTPENDED

R/W

0

用法 fault悬起中,细节同上

11

SYSTICKACT

R/W

0

SysTick异常活动中

10

PENDSVACT

R/W

0

PendSV异常活动中

9

-

-

-

-

8

MONITORACT

R/W

0

Monitor异常活动中

7

SVCALLACT

R/W

0

SVC异常活动中

6:4

-

-

-

-

3

USGFAULTACT

R/W

0

用法 fault异常活动中

2

-

-

-

-

1

BUSFAULTACT

R/W

0

总线 fault异常活动中

0

MEMFAULTACT

R/W

0

存储器管理 fault异常活动中

写这些寄存器时要小心,必须确保对活动位的修改是经过深思熟虑的,决不能粗心修改。否则,
如果某个异常的活动位被意外地清零了,其服务例程却不知晓,仍然执行异常返回指令,那么CM3
将视之为无理取闹——在异常服务例程以外做异常返回,从而产生一个fault。

译注:下段文字改编自《Cortex-M3 Technical Reference Manual》, pg8-29,是给那些骨灰级玩家们看的,因为修改这 些位还有更深层次的背景和特效。译文为:上表中的活动位虽然也是可写的,但是改动时必须予以极度的小心,否 则这是玩火行为——设置或者清零这些位,会改变处理器中对异常活动的记录,却不会对应地修复堆栈中的数据(不 会为了此改动而特意执行一次自动入栈或自动出栈操作),于是埋下了破坏堆栈内容而引起程序跑飞的隐患;另外, 其它一些重要的数据结构也得不到清除,后患无穷。事实上,只有操作系统在特殊场合下才会修改它们。例如:在

任务执行系统调用的过程中执行上下文切换(大幅提升实时性),或者在使用软件模拟未定义指令的功能期间(在用 法fault服务例程中),以及软件模拟协处理器的功能期间,执行上下文切换,同样大幅提升实时性。

下面开始讲中断控制及状态寄存器ICSR。对于NMI、SysTick定时器以及PendSV,可以通过此寄存器手工悬起它

们。另外,在该寄存器中,有好多位段都用于调试目的。在大多数情况下,它们对于应用软件都没有什么用处,只 有悬起位对应用程序常常比较有参考价值,如表8.6所示。

表8.5 中断控制及状态寄存器ICSR(地址:0xE000_ED04)

位段

名称

类型

复位值

描述

31

NMIPENDSET

R/W

0

写 1以悬起 NMI。因为 NMI的优先级最高且从不

掩蔽,在置位此位后将立即进入 NMI服务例程。

28

PENDSVSET

R/W

0

写 1 以悬起 PendSV。读取它则返回 PendSV 的

状态

27

PENDSVCLR

W

0

写 1以清除 PendSV悬起状态

26

PENDSTSET

R/W

0

写 1以悬起 SysTick。读取它则返回 PendSV的

状态

25

PENDSTCLR

W

0

写 1以清除 SysTick悬起状态

23

ISRPREEMPT

R

0

=1 时,则表示一个悬起的中断将在下一步时进

入活动状态(用于单步执行时的调试目的)

22

ISRPENDING

R

0

1=当前正有外部中断被悬起(不包括 NMI)

21:12

VECTPENDING

R

0

悬起的 ISR 的编号。如果不止一个中断悬起,

则它的值是这次中断中,优先级最高的那一个。

11

RETTOBASE

R

0

如果异常返回后将回到基级(base level),并

且没有其它异常悬起时,此位为 1。若是在线程 模式下,在某个服务例程中,有不止一级的异常 处于活动状态,或者在异常没有活动时执行了异 常服务例程(此时执行返回指令将产生 fault。 此乃高危行为,大虾也需慎用),则此位为 0

9:0

VECTACTIVE

R

0

当前活动的ISR编号,该位段指出当前运行中的

ISR是哪个中断的(提供异常序号),包括NMI和 硬fault。如果多个异常共享一个服务例程,该例程可

根据本位段的值来判定是哪一个异常的响应导致它的执 行。把本位段的值减去16,就得到了外中断的编号,并 可以用此编号来操作外中断相关的使能/除能等寄存器。

你可能感兴趣的:(内核)