一、异常和中断简介
中断一般由硬件(如外设和外部输入引脚)产生的事件,它会引起程序流偏离正常的流程(如给外设提供服务)。当外设或硬件需要处理器的服务时,一般会出现下面的流程:
①外设确认到处理器的中断请求。
②处理器暂停当前执行的任务
③处理器执行外设的ISR,若有必要可以选择由软件清除中断请求。
④处理器继续执行之前暂停的任务。
所有的cortex-m处理器都会提供一个用于中断处理的嵌套向量中断控制器(NVIC)。除了中断请求,还有其他需要服务的事件,将其称为异常。按照ARM的说法,中断也是一种异常。cortex-m处理器中的其他异常包括错误异常和其他用于OS支持的系统异常(如SVC指令)。处理异常的程序代码一般被称作异常处理,它们属于以编译程序映像的一部分。典型的cortex-m4微控制器中,NVIC接收多个中断源产生的中断请求,如下图所示:
cortex-m3 和cortex-m4 的NVIC支持最多240个IRQ(中断请求)、1个不可屏蔽中断(NMI)、1个SysTick(系统节拍)定时中断及多个系统异常。多数IRQ由定时器、I/O端口和通信接口(如UART和I2C)等外设产生。NMI通常由看门狗定时器或掉电检测器等外设产生,其余的异常则是来自处理器内核、中断还可以利用软件生成。
为了继续执行被中断的程序,异常流程需要利用一些手段来保存被中断程序的状态,这样在异常处理完成后还可以被恢复。一般来说,这个过程可以由硬件机制实现,也可由硬件和软件操作共同完成。对于cortex-m4处理器,当异常被接受后,有些寄存器会被自动保存到栈中,而且也会在返回流程中自动恢复。利用这种机制,可以将异常处理写作普通的C函数,同时也不会带来额外的软件开销。
二、异常类型
cortex-m处理器的异常架构具有多种特性,支持多个系统异常和外部中断。编号1-15的为系统异常,16及以上的则为中断输入(处理器的输入,不必从封装上的I/O引脚*问)。包括所有中断在内的多数异常,都具有可编程的优先级,一些系统异常则具有固定的优先级。不同的cortex-m3或cortex-m4微控制器的中断源的编号(1~240)可能会不同,优先级也可能会有所差异。这是因为为了满足不同的应用需求,芯片设计者可能会对cortex-m3或cortex-m4设计进行相应的配置。
系统异常列表如下
异常编号 | 异常类型 | 优先级 | 描述 |
---|---|---|---|
1 | 复位 | -3(最高) | 复位 |
2 | NMI | -2 | 不可屏蔽中断(外部NMI输入) |
3 | 硬件错误 | -1 | 所有的错误都可能会引发,前提是相应的错误处理未使能 |
4 | MemManage错误 | 可编程 | 存储器管理错误,存储器管理单元(MPU)冲突或访问非法位置 |
5 | 总线错误 | 可编程 | 总线错误。当高级高性能总线(AHB)接口收到从总线的错误响应时产生(若未取指也被称作预取终止,数据访问则为数据终止) |
6 | 使用错误 | 可编程 | 程序错误或试图访问协处理器导致的错误(cortex-m3和cortex-m4处理器不支持协处理器) |
7-10 | 保留 | NA | NA |
11 | SVC | 可编程 | 请求管理调用。一般用于OS环境且允许应用任务访问系统服务 |
12 | 调试监控 | 可编程 | 调试监控。在使用基于软件的调试方案时,断点和监视点灯调试事件的异常 |
13 | 保留 | NA | NA |
14 | PendSV | 可编程 | 可挂起的服务调用。OS一般用该异常进行上下文切换 |
15 | SYSTICK | 可编程 | 系统节拍定时器。当其在处理器中存在时,由定时器外设产生。可用于OS或简单的定时器外设。 |
16 | 外部中断#0 | 可编程 | 可由片上外设或外设中断源产生 |
17 | 外部中断#1 | 可编程 | 可由片上外设或外设中断源产生 |
… | … | … | … |
255 | 外部中断#239 | 可编程 | 可由片上外设或外设中断源产生 |
三、中断管理简介
cortex-m处理器具有多个用于中断和异常管理的可编程寄存器,这些寄存器多数位于NVIC和系统控制块(SCB)中。实际上,SCB是作为NVIC的一部分实现的,不过CMSIS-CORE将其寄存器定义在了单独的结构体中。处理器内核中还有用于中断屏蔽的寄存器(如PRIMASK、FAULTMASK和BASEPRI)。NVIC和SCB位于系统控制空间(SCS),地址从0xE000E000开始,大小为4kb。SCS中还有SysTick定时器、存储器保护单元(MPU)以及用于调试的寄存器等。该地址区域中基本上所有的寄存器都只能由运行在特权访问等级的代码访问。唯一的例外为软件触发中断寄存器(STIR),它可被设置为非特权模式访问。对于一般的应用程序编程,最好是使用CMSIS-CORE访问函数。如有必要,还可以直接访问NVIC或SCB中的寄存器。复位后,所有中断都处于禁止状态,且默认的优先级为0.在使用任何一个中断之前,需要:
①设置所需中断的优先级(可选)、
②使能外设中的可以触发中断的中断产生控制
③使能NVIC中的中断。
四、优先级定义
对于cortex-m异常是否能被处理器接受以及何时被处理器接受并执行异常处理,是由异常的优先级和处理器当前的优先级决定的。更高优先级的异常(优先级编号更小)可以抢占低优先级的异常(优先级编号更大),这就是异常/中断嵌套的情形。有些异常(复位、NMI、HardFault)具有固定的优先级,其优先级由负数表示,这样,它们的优先级就会比其他的异常高。其他异常则具有可编程的优先级,范围为0~255.
cortex-m3和cortex-m4处理器在设计上具有3个固定的最高优先级以及256个可编程优先级(具有最多128个抢占等级),可编程优先级的实际数量由芯片设计商决定。多数M3或M4芯片支持的优先级较少,如8、16、32等。这是因为大量的优先级会增加NVIC的复杂度,而且会增加功耗降低的速度。多数情况下,应用程序只需少量的编程优先级。因此,芯片设计人员需要基于目标应用的优先级数量定制处理器设计。优先级的减少是通过去除优先级配置寄存器的最低位(LSB)实现的。
中断优先级由优先级寄存器控制,宽度为3~8位。若设计中只实现了3位优先级,优先级配置寄存器如下图所示:
由于BIT0~BIT4未实现,它们读出总是0,对这些位的写操作会被忽略,根据这种设置,可能的优先级为0x00,0x40,0x60,0x80,0xa0,0xc0,0xe0.对于ARMv7-M架构,宽度最少为3位,对于cortex-m3和cortex-m4处理器,所有的优先级寄存器的复位值都为0.
之所以移除优先级寄存器的LSB 而不是MSB,主要是为了cortex-m4设备之间移植软件时更加容易。按照这种方式,在具有4位优先级配置的寄存器的设备上写的程序,就可能会在具有3位优先级配置寄存器的设备上运行。
优先级寄存器会被进一步分为两个部分:分组优先级和子优先级。其具体见下表:
优先级分组 | 抢占优先级域 | 子优先级域 |
---|---|---|
0(默认) | BIT[7:1] | BIT[0] |
1 | BIT[7:2] | BIT[1:0] |
2 | BIT[7:3] | BIT[2:0] |
3 | BIT[7:4] | BIT[3:0] |
4 | BIT[7:5] | BIT[4:0] |
5 | BIT[7:6] | BIT[5:0] |
6 | BIT[7] | BIT[6:0] |
7 | 无 | BIT[7:0] |
在处理器已经在运行一个中断处理器时能否产生另外一个中断,是由该中断的抢占优先级决定的。子优先级只会用在具有两个相同分组优先级的异常同时产生的情形,此时具有更高子优先级(数值更小)的异常会被首先处理。
cmsis-core提供了一组函数来访问优先级分组设置优先级的信息,如下表:
函数 | 用法 |
---|---|
void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) | 设置优先级分组数值 |
uint32_t NVIC_GetPriorityGrouping(uint32_t PriorityGroup) | 获取优先级分组数值 |
uint32_t NVIC_EncodePriority(uint32_t PriorityGroup,uint32_t PreemptPriority, uint32_t SubPriority) | 基于优先级分组、组优先级和子优先级生成优先级数值 |
uint32_t NVIC_DecodePriority(uint32_t PriorityGroup,uint32_t PreemptPriority, uint32_t SubPriority) | 提前组优先级和子优先级 |
由于优先级分组的存在,分组(抢占)优先级的最大宽度为7,因此也就有了128个等级。若优先级分组被设置为7,所有具有可编程优先级的异常则会处于相同的等级,这些异常间也不会产生抢占,硬件错误、NMI和复位是例外,它们可以抢占这些异常。
在确定实际的分组优先级和子优先级时,必须要考虑以下因素:
①实际的优先级配置寄存器
②优先级分组设置
例如,若配置寄存器的宽度为3,且优先级分组为5,则会有4个分组/强哥优先级,而且每个分组/抢占优先级具有两个子优先级,如下图所示:
五、向量表和向量表重定位
当cortex-m处理器接受了某异常请求后,处理器需要确定该异常处理(若为中断是ISR)的起始地址。该信息位于存储器内的向量表中,向量表默认从地址0开始,向量地址则为异常编号乘4,向量表一般被定义在微控制器供应商的启动代码中。启动代码中使用的向量表还包含主栈指针的初始值,这种设计是很有必要的,因为NMI等异常可能会紧接着复位产生,而且此时还没有进行任何初始化操作。cortex-m处理器中的向量表和ARM7TDMI等传统的ARM处理器的向量表不同。对于传统的ARM处理器,向量表中存在跳转到相应处理的指令,而cortex-m处理器的向量表则为异常处理的起始地址。
一般来说,起始地址(0X00000000)处应为启动存储器,它可以为FLASH存储器或ROM设备,而且在运行时不能对它们进行修改。不过有些应用可能需要在运行时修改或定义向量表。为了进行这种处理,M3/M4处理器实现了一种名为向量表重定位的特性。向量表重定位特性提供了一个名为向量表偏移寄存器(VTOR)的可编程寄存器。该寄存器将正在使用的存储器的起始地址定义为向量表。
VTOR的复位值为0。要将向量表重定位到SRAM区域的开头处,可以使用下面的代码:
#define HW32_REG(ADDRESS) (*(volatile unsigned long *)(ADDRESS))
#define VTOR_NEW_ADDR 0x20000000
int i;
for(i=0;i<48;i++)
{
HW32_REG(VTOR_NEW_ADDR +(i<<2)) = HW32_REG(i<<2); //将每个向量表入口从Flash复制到SRAM
}
_DMB();//基于架构考虑的,可以不加 数据存储器屏障,确保到存储器的写操作结束
SCB->VTOR = VTOR_NEW_ADDR;
_DSB();//基于架构考虑的,可以不加 数据同步屏障,确保接下来的所有指令都使用新配置
在使用VTOR时,需要将向量表大小扩展为下一个2的整数次方,且新向量表的基地址必须要对齐到这个数值。
示例1:微控制器有32个中断源
向量表大小为 32(用于中断) +16(用于系统异常空间)X4(每个向量的字节数)=192.将其扩大为下一个2的整数次方就得到256字节。因此,向量表的地址可被设置为0x00000000、0x00000100以及0x00000200等。由于中断的最小数量为1,最小的向量表对齐为128字节,因此VTOR的最低7位保留,且被强制为0.
向量表重定位特性可用于多种情形
1.具有BootLoader的设备
有些微控制器具有多个程序存储器:启动ROM和用户Flash存储器。微控制器生产商一般会将BootLoader预先写到启动ROM中,这样在微控制器启动时,启动ROM中的BootLoader就会首先执行,而且在跳转到用户Flash的应用程序前,VTOR会被设置为指向用户Flash存储器的开始处,因此会使用用户Flash中的向量表。
2.应用程序加载到RAM
有些情况下,应用程序可能会被从外部设备加载到RAM中执行,它可能会位于SD卡中,或者甚至需要通过网络传输。在这种情况下,存储在片上存储器中用于启动的程序需要初始化一些硬件、复制位于外部设备中的应用程序到RAM、更新VTOR后执行存储在外部的程序。
3.动态修改向量表
有些情况下,ROM中可能会有一个中断的多个处理实例,可能需要在应用的不同阶段在它们之间进行切换。在这种情况下,可以将向量表从程序存储器复制到SRAM,并且设置VTOR指向SRAM中的向量表。由于SRAM中的内容可在任意时间修改,因此可以轻易地在应用的不同阶段修改中断向量。
向量表最少也要提供MSP的初始值以及用于系统启动的复位向量。另外,对于一些应用,若设备在启动时有触发NMI的可能,也许还需要加入NMI向量和用于错误处理的HardFault向量。
六、中断输入和挂起行为
每个中断都有多个属性:
①每个中断都可被禁止(默认)或使能
②每个中断都可被挂起(等待服务的请求)或解除挂起
③每个中断都可处于活跃(正在处理)或非活跃状态
为了支持这些属性,NVIC中包含了多个可编程寄存器,它们可用于中断使能控制、挂起状态和只读的活跃状态位。这些状态属性具有多种可能的组合。例如,在处理中断时(活跃中断),可以将其禁止,若在中断退出前产生了同一个中断的新请求,由于该活跃中断被禁止了,它就会处于挂起状态。若满足以下条件,中断请求可被处理器接受:挂起状态置位,中断使能,且中断的优先级比当前等级高(包括中断屏蔽寄存器配置)。NVIC在设计上既支持产生脉冲请求的外设,也支持产生高电平中断请求的外设。无须配置任何一个NVIC寄存器以选择其中一个中断类型。对于脉冲中断请求,脉冲宽度至少要为一个时钟周期;而对于电平触发的请求,在ISR中的操作清除请求之前,请求服务的外设要一直保持信号电平(如写入寄存器以清除中断请求)。尽管外部中断请求在I/O引脚上的电平可能是低有效的,NVIC收到的请求信号为高有效。
中断的挂起状态被存储在NVIC的可编程寄存器中,当NVIC的中断输入被确认后,它就会引发该中断的挂起状态。即便中断请求被取消,挂起状态仍会为高。这样NVIC可以处理脉冲中断请求。挂起状态的意思是,中断被置于一种等待处理器处理的状态。有些情况下,处理器在中断挂起时就会进行处理。不过,若处理器已经在处理另外一个更高或同等优先级的中断,或者中断被某个中断屏蔽寄存器给屏蔽掉了,那么在其他的中断处理结束前或中断屏蔽被清除前,挂起请求会一直保持。这一点和传统ARM处理器不同。按照之前的方式,若设备产生了中断,如中断请求(IRQ)和快速中断请求(FIQ),那么在它们得到处理前需要一直保持请求信号。目前,由于NVIC中的挂起请求寄存器保存中断请求,即使请求中断的源设备取消了请求信号,已产生的中断仍会被处理。
当处理器开始处理中断请求时,中断的请求信号会被自动清除,如下图所示
当中断正被处理时,它就会处于活跃状态。注意在中断入口处,多个寄存器会被自动压入栈中,这也被称作压栈。同时,ISR的起始地址会被从向量表中取出。对于许多微控制器设计,外设会产生电平触发的中断,因此ISR必须要手动清除中断请求,如写入外设中的某个寄存器。在中断服务完成后,处理器会执行异常返回。之前自动压栈的寄存器会被恢复出来,而且被中断的程序也会继续执行。中断的活跃状态会自动清除。
当中断处于活跃状态时,处理器无法再中断完成和异常返回(有时也被称作异常退出)前再次接受同一个中断请求。中断的挂起状态位于中断挂起状态寄存器中,软件代码可以访问这些寄存器,因此,可以手动清除或设置中断的挂起状态。若中断请求产生时处理器正在处理另一个具有更高优先级的中断,而在处理器对中断请求做出响应之前,挂起状态被清除掉了,该请求就会被取消且不会再得到处理,如下图所示:
若外设持续保持某个中断请求,那么即使软件尝试着清除该挂起状态,挂起状态还是会再次置位的。
若在得到处理后,中断源仍在继续保持中断请求,那么这个中断就会再次进入挂起状态且再次得到处理器的服务,如下图所示:
对于脉冲中断请求,若在处理器开始处理前,中断请求信号产生了多次,它们会被当作一次中断请求,如下图所示:
中断的挂起状态可以在其正在被处理时再次置位。例如下图所示,在之前的中断请求正被处理时产生了新的请求,这样会引发新的挂起状态,因此,处理器在前一个ISR结束后需要再次处理这个中断。
即使中断被禁止了,它的挂起状态仍可置位。在这种情况下,若中断稍后被使能了,它仍可以被触发并得到服务。有些时候,这种情况并不是我们所希望的,因此需要在使能NVIC中的中断前收到清除挂起状态。有些时候,这种情况并不是我们所希望的,因此需要在使能NVIC中的中断前手动清除挂起状态。一般来说,NMI的请求方式和中断类似。若当前没有在运行NMI处理,或者处理器被暂停或处于锁定状态,由于NMI具有最高优先级且不能被禁止,因此它几乎会立即执行。
七、异常流程简介
1.接受异常请求
若满足下面的条件,处理器会接受请求:
①处理器正在运行(未被暂停或处于复位状态)
②异常处于使能状态(NMI和HardFault为特殊情况,它们总是使能的)
③异常的优先级高于当前等级
④异常未被异常屏蔽寄存器(如PRIMASK)屏蔽
注意,对于SVC异常,若SVC指令被意外用在某异常处理中,且该异常处理的优先级不小于SVC,它就会引起HardFault异常处理的执行。
2.异常进入流程包含以下操作:
①多个寄存器和返回地址被压入当前使用的栈。这样就可以将异常处理用普通C函数实现。若处理器处于线程模式且正使用进程栈指针PSP,则PSP指向的栈区域就会用于该压栈过程,否则就会使用MSP指向的栈区域。
②取出异常向量(异常处理/ISR的起始地址)。为了减少等待时间,这一步可能会和压栈操作并行执行。
③取出待执行异常处理的指令。在确定了异常处理的起始地址后,指令就会被取出。
④更新多个NVIC寄存器和内核寄存器,其中包括挂起状态和异常的活跃状态,处理器内核中的寄存器包括PSR、LR、PC以及栈指针(SP)。
根据压栈时实际使用的栈,在异常处理开始前,MSP或PSP的数值会相应地被自动调整。PC也会被更新为异常处理的起始地址,LR则会被更新为名为EXC_RETURN的特殊值。该数值为32位,且高27位为1.低5位中有些部分用于保存异常流程的状态信息(如压栈时使用的那个栈)。该数值用于异常返回。
3.执行异常处理
在异常处理内部,可以执行外设所需的服务。在执行异常处理时,处理器就会处于处理模式。此时:
栈操作使用主栈指针
处理器运行在特权访问等级
若更高优先级的异常在这个阶段产生,处理器会接受新的中断,而当前正在执行的处理会被挂起且被更高优先级的处理抢占,这种情况名为异常嵌套。若另一个在这个阶段产生的异常具有相同或更低的优先级,新到的异常就会处于挂起状态,且等当前异常处理完成后才会得到处理。在异常处理的结尾,程序代码执行的返回会引起EXC_RETURN数值被加载到PC中,并触发异常返回机制。
4.异常返回
对于某些处理器架构,异常返回会使用一个特殊的指令。不过,这也意味着异常处理无法像普通C代码那样编写和编译。对于ARM CORTEX-M处理器,异常返回机制由一个特殊的地址EXC_RETURN触发,该数值在异常入口处产生且被存储在LR中。当该数值由某个允许的异常返回指令写入PC时,它就会触发异常返回流程。
异常返回可由下表所示的指令产生。当触发了异常返回机制后,处理器会访问栈空间里在进入异常期间被压入栈中的寄存器数值,且将它们恢复到寄存器组中,这个过程被称作出栈。另外,多个NVIC寄存器(如活跃状态)和处理器内核中的寄存器(如PSR、SP和CONTROL)都会更新。
返回指令 | 描述 |
---|---|
BX | 若EXC_RETURN数值仍在LR中,则在异常处理结束时可以使用BX LR指令执行中断返回 |
POP {PC}或POP {…, PC} | 在进入异常处理后,LR的值通常会被亚如栈中,可以使用操作一个寄存器或包括PC在内的多个寄存器的POP指令,将EXC_RETURN放到程序计数器中,这样处理器会执行中断返回 |
LDR 或LDM | 可以利用PC为目的寄存器的LDR或LDM指令产生中断返回 |
在压栈操作的同时,处理器会取出之前被中断的程序的指令,并使得程序尽快继续执行。由于使用EXC_RETURN 数值触发异常返回,异常处理就可以和普通的C函数/子例程一样实现。在生成代码时,C编译器将LR中的EXC_RETURN数值作为普通返回地址处理。由于EXC_RETURN机制,函数一般不会返回到地址0XF0000000~0XFFFFFFFF。不过,根据架构定义,这段地址区域不能用于程序代码,因此这样也不会有什么问题。
八、中断控制用的NVIC寄存器细节
NVIC中有多个用于中断控制的寄存器,这些寄存器位于系统控制空间(SCS)地址区域,见下表所示:
地址 | 寄存器 | CMSIS-Core符号 | 功能 |
---|---|---|---|
0xE000E100~0XE000E11C | 中断设置使能寄存器 | NVIC->ISER[0] ~ NVIC->ISER[7] | 写1设置使能 |
0xE000E180~0XE000E19C | 中断清除使能寄存器 | NVIC->ICER[0] ~ NVIC->ICER[7] | 写1清除使能 |
0xE000E200~0XE000E21C | 中断设置挂起寄存器 | NVIC->ISPR[0] ~ NVIC->ISPR[7] | 写1设置挂起状态 |
0xE000E280~0XE000E29C | 中断清除挂起寄存器 | NVIC->ICPR[0] ~ NVIC->ICPR[7] | 写1清除挂起状态 |
0xE000E300~0XE000E31C | 中断活跃位寄存器 | NVIC->IABR[0] ~ NVIC->IABR[7] | 写1设置使能 |
0xE000E400~0XE000E4EF | 中断优先级寄存器 | NVIC->IP[0] ~ NVIC->IR[239] | 写1设置使能 |
0xE000EF00 | 软件触发中断寄存器 | NVIC->STIR | 写中断编号设置相应中断的挂起状态 |
除了软件触发中断寄存器外,所有这些寄存器都只能在特权等级访问。STIR默认只能在特权等级访问,不过可以配置为非特权等级访问。根据默认设置,系统复位后:
①所有中断被禁止(使能位=0)
②所有中断的优先级为0(最高的可编程优先级)
③所有中断的挂起状态清零
NVIC在0xE000E004地址处还有一个中断控制器类型寄存器,它是一个只读寄存器,给出了NVIC支持的中断输入的梳理,如下表所示:
位 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
4:0 | INTLINESNUM | R | — | 以32为单位的中断输入数量 0=1~32 1= 33~64 … |
利用CMSIS的设备驱动库,可以使用SCnSCB->ICTR来访问这个只读寄存器。与中断控制器类型寄存器只能给出可用中断的大致数量不同,可以在PRIMASK置位的情况下,通过下面的方法能得到可用中断的确切数量:写入中断使能/挂起寄存器等中断控制寄存器,读回后查看中断使能/挂起寄存器中实际实现的位数。
九、用于异常和中断控制的SCB寄存器细节
除了CMSIS-CORE中的NVIC数据结构,系统控制块SCB 数据结构中还包含了一些常用于中断控制的寄存器,如下表所示:
地址 | 寄存器 | CMSIS-CORE符号 | 功能 |
---|---|---|---|
0XE000ED00 | CPU ID | SCB->CPUID | 可用于识别处理器类型和版本ID代码 |
0xE000ED04 | 中断控制和状态 | SCB->ICSR | 系统异常的控制和状态 |
0xE000ED08 | 向量表偏移寄存器 | SCB->VTOR | 使能向量表重定位到其他的地址 |
0xE000ED0C | 应用中断/复位控制寄存器 | SCB->AIRCR | 优先级分组配置和自复位控制 |
0xE000ED10 | 系统控制寄存器 | SCB->SCR | 休眠模式和低功耗特性的配置 |
0xE000ED14 | 配置控制寄存器 | SCB->CCR | 高级特性的配置 |
0xE000ED18~0xE000ED23 | 系统处理优先级寄存器 | SCB->SHP[0]~SCB->SHP[11] | 系统异常的优先级设置 |
0xE000ED24 | 系统处理控制和状态寄存器 | SCB->SHCSR | 使能错误异常和系统异常状态的控制 |
0xE000ED28 | 可配置错误状态寄存器 | SCB->CFSR | 引起错误异常的提示信息 |
0xE000ED2C | 硬件错误状态寄存器 | SCB->HFSR | 引起硬件错误异常的提示信息 |
0xE000ED30 | 调试错误状态寄存器 | SCB->DFSR | 引起调试事件的提示信息 |
0xE000ED34 | 存储器管理错误寄存器 | SCB->MMFAR | 存储器管理错误的地址值 |
0xE000ED38 | 总线错误寄存器 | SCB->BFAR | 总线错误的地址值 |
0xE000ED3C | 辅助错误状态寄存器 | SCB->AFSR | 设备相关错误状态的信息 |
0xE000ED40~0xE000ED44 | 处理器特性寄存器 | SCB->PFR[0] ~SCB->PFR[1] | 可用处理器特性的只读信息 |
0xE000ED48 | 调试特性寄存器 | SCB->DFR | 可用调试特性的只读信息 |
0xE000ED4C | 辅助特性寄存器 | SCB->AFR | 可用辅助特性的只读信息 |
0xE000ED50~0xE000ED5C | 存储器模块特性寄存器 | SCB->MMFR[0] ~SCB->MMFR[3] | 可用存储器模块特性的只读信息 |
0xE000ED60~0xE000ED70 | 指令集属性寄存器 | SCB->ISAR[0] ~SCB->ISAR[4] | 指令集特性的只读信息 |
0xE000ED88 | 协处理器访问控制寄存器 | SCB->CPACR | 使能浮点特性的寄存器,只存在于具有浮点单元的CORTEX-M4 |
0ED50~0xE000ED5C | 存储器模块特性寄存器 | SCB->MMFR[0] ~SCB->MMFR[3] | 可用存储器模块特性的只读信息 |
| 0xE000ED60~0xE000ED70 | 指令集属性寄存器 | SCB->ISAR[0] ~SCB->ISAR[4] | 指令集特性的只读信息 |
| 0xE000ED88 | 协处理器访问控制寄存器 | SCB->CPACR | 使能浮点特性的寄存器,只存在于具有浮点单元的CORTEX-M4 |
备注:参考ARM Cortex-M3与Cortex-M4权威指南