本节介绍Cortex-M0+处理器的存储空间结构,内容包括存储空间映射、代码区域地址映射、SRAM区域地址映射、外设区域地址映射、PPB地址空间映射、SCS地址空间映射,以及系统控制和ID寄存器。
Cortex-M0+处理器采用了Armv6-M架构,该架构支持预定义的32位地址空间,并细分为代码、SRAM和外设,以及片上和片外资源的区域,如图2.12所示。其中,片上是指紧耦合到处理器的资源。地址空间支持8个基本分区,每个分区是0.5GB,包括:
(1)代码;
(2)SRAM;
(3)外设;
(4)两个RAM区域;
(5)两个设备区域;
(6)系统。
该架构分配用于系统控制、配置以及用作事件入口点或向量的物理地址。该架构定义相对基地址的向量,该基地址在Armv6-M中固定为地址0x00000000。
地址空间0xE0000000到0xFFFFFFFF保留供系统级使用。
注: 尽管默认规定了这些区域的使用方法,但是程序设计人员可以灵活地根据具体要求定义存储器地址空间映射,例如,访问内部私有外设总线。
图2.12 Cortex-M0+处理器的存储器地址空间映射
Armv6-M地址映射关系如表2.2所示。
表2.2 Armv6-M地址映射关系
表中:
(1)XN表示从不执行区域(execute never region)。从XN区域执行代码的任何尝试都会出错,从而生成硬件故障异常。
(2)缓存列指示用于标准存储器区域、内部和外部缓存的缓存策略,以支持系统缓存。声明的缓存类型可以降级,但不能升级,如下:
①直接写(Write-Through,WT),可以看作非缓存;
②回写和写分配(Write-Back,Write Allocate,WBWA),可以看作直接写或非缓存。
(3)在设备类型一列中,可共享表示该区域支持同一存储器区域中多个代理共享使用。这些代理可以是处理器和DMA(直接存储器访问)代理的任意组合。标准表示处理器可以对交易进行重新排序以提高效率或者执行预测读取。设备表示处理器将保持相对于到设备或强顺序存储器的其他交易的顺序。
注: (1)Armv6-M不支持诸如LDREX或STREX之类的互斥访问指令,也不支持任何形式的原子交换指令。在使用共享存储器的多处理环境中,软件必须考虑这一点。
(2)代码、SRAM和外部RAM区域都可以保存程序。
(3)MPU可以覆盖该部分介绍的默认存储器访问行为。
Code(代码)区域地址映射关系如表2.3所示。
表2.3 Code区域地址映射关系(STM32G071xx和STM32G081xx)
Flash存储器的构成形式为72位宽的存储单元(64位加8个ECC位),可用于保存代码和数据常量。Flash存储器的组织方式如下。
(1)一个主存储器块,包含64个(具体数量和器件型号有关)2KB的页面,每页有8行,每行256B。
(2)信息块。
①在系统存储器模式中,CPU从系统存储器启动引导。该区域是保留区域,包含用于通过以下接口之一对Flash存储器进行重新编程的启动引导程序,这些接口包括:USART1、USART2、I2C1和I2C2(适用于所有器件),USART3、SPI1和SPI2(适用于STM32G071xx、STM32G081xx、STM32G0B1xx和STM32G0C1xx),以及USB(DFU)和FDCAN2(适用于STM32G0B1xx和STM32G0C1xx)。在生产线上,对芯片进行编程并提供保护,以防止伪造的写/擦除操作。
②1KB(128个双字)一次性可编程(One-Time Programmable,OTP)用于用户数据。OTP数据无法删除,只能写入一次。如果只有1位为0,则即使值0x0000 0000 0000 0000,也无法再写入整个双字(64位)
当读出保护机制(RDP)级别为1,并且引导源不是主Flash存储器区域时,无法读取OTP区域。
③用于用户配置的选项字节。
注: 在STM32G0x1中,可以通过BOOT0引脚,FLASH_SECR寄存器中的BOOT_LOCK位以及用户选项字节中的引导配置位nBOOT1、nBOOT_SEL和nBOOT0选择三种不同的引导模式,启动模式配置如表2.4所示。
表2.4 启动模式配置
复位后,在SYSCLK的第四个上升沿,锁存引导模式配置。用户可以设置与所需引导模式相关的引导模式配置。
当从待机模式退出时,也会重新采样引导模式配置。因此,在待机模式下必须保持所要求的启动引导模式。当从待机模式退出时,CPU从地址0x00000000获取堆栈顶部的值,然后从在0x00000004的启动存储器启动代码。
根据所选择的启动引导模式,可以按如下方式访问主Flash存储器、系统存储器或SRAM。
(1)从主Flash存储器启动:主Flash存储器在启动存储器空间(0x00000000)具有别名,但是仍可以从其原始存储空间(0x08000000)访问。换句话说,可以从地址0x00000000或0x08000000开始访问主Flash存储器内容。
(2)从系统存储器启动:系统存储器在启动引导存储器空间(0x00000000)中是别名,但仍可以从其原始的存储器空间0x1FFF0000访问。
(3)从SRAM启动:SRAM在引导存储器空间(0x00000000)中具有别名,但仍可以从其原始存储空间(0x20000000)对其进行访问。
SRAM区域地址映射关系如表2.5所示。
表2.5 SRAM区域地址映射关系
STM32G071x8/xB器件提供了32KB的具有奇偶校验的嵌入式SRAM。硬件奇偶校验可以检测到存储器的数据错误,这将有助于提高应用程序的功能安全性。
当由于应用程序的安全性要求不高而不需要奇偶校验保护时,可以将奇偶效验存储位用作附加的SRAM,以将其总大小增加到36KB。
片内嵌入SRAM的优势是可以以零等待状态和CPU的时钟速度读写存储器。
外设区域地址映射关系(不包括Cortex-M0+内部外设)如表2.6所示。
表2.6 外设区域地址映射关系
续表
续表
①SYSCFG(ITLINE)寄存器使用0x40010000作为参考外设基地址。
0xE0000000~0xFFFFFFFF区域的存储空间映射关系如表2.7所示。
表2.7 0xE0000000~0xFFFFFFFF区域的存储空间映射关系
①在所有实现中,对它只能通过特权访问。
从表2.7中可知,地址空间为0xE0000000~0xE00FFFFF的区域为PPB区域,PPB地址空间映射关系如表2.8所示。
表2.8 PPB地址空间映射关系
注: 表中地址不连续的区域为保留区域。
除了SCB、DCB和SCS中的其他调试控制外,其他与调试相关的资源在Armv6-M系统地址映射的PPB区域内分配了固定的4KB区域。这些资源如下。
(1)断点单元(BreakPoint Unit,BPU)。它提供了断点支持。BPU是Armv7-M中可用的Flash补丁和断点块(Flash Patch and Breakpoint,FPB)的子集。
(2)ROM表。ROM表的入口为调试器提供了一种机制,以标识实现所支持的调试基础结构。
通过DAP接口,可以访问这些资源以及SCS中的调试寄存器。
在Armv6-M架构中,PPB区域中的通用规则包括:
(1)将该区域定义为强顺序存储器;
(2)始终以小端方式访问寄存器,与处理器当前的端状态无关;
(3)PPB区域地址空间仅支持对齐的字访问,字节和半字访问是不可预测的。
注: 这与Armv7-M不同,后者在某些情况下支持字节和半字访问。对于Armv6-M,软件必须执行读-修改-写访问序列,在该序列中,软件必须修改PPB区域中某个字内的字节字段。
(4)术语“设置”,表示写入1;术语“清除”,表示写入0。该术语适用于多个位,所有位均为写入值。
(5)通过将0写入相应的寄存器位来禁用功能,并通过将1写入该位来使能。
(6)在将某一定义位在读取时清零的情况下,当该位的读取与将该位设置为1的事件一致时,该架构保证以下原子行为:
①如果该位读取为1,则通过读操作将该位清除为0;
②如果该位读取为0,则将该位设置为1,并通过后续的读取操作将其清零。
(7)保留的寄存器或位字段必须看作UNK/SBZP。
(8)对PPB的非特权访问会产生硬件故障错误,而不会引起PPB访问。
SCS是存储器映射的4KB地址空间,它提供了32位寄存器用于配置、状态报告和控制。SCS寄存器一般分为以下几组:
(1)系统控制和识别;
(2)CPUID处理器标识空间;
(3)系统配置和状态;
(4)可选的系统定时器,SysTick;
(5)嵌套向量中断控制器(Nested Vectored Interrupt Controller,NVIC);
(6)调试。
SCS地址空间映射如表2.9所示。
表2.9 SCS地址空间映射关系
注: 未分配的地址被保留。
在Armv6-M中,SCS中的系统控制块(SCB)提供了处理器的关键状态信息和控制功能。SCB支持如下功能。
(1)不同级别的软件复位控制。
(2)通过控制表的指针来管理异常模型的基地址。
(3)系统异常管理,包括:
①异常使能;
②将异常的状态设置为“挂起”,或者从异常中删除挂起的状态;
③将每个异常的状态显示为非活动、挂起或者活动;
④设置可配置系统异常的优先级;
⑤提供其他控制功能和状态信息。
这里不包括外部中断处理,NVIC管理所有的外部中断。
(4)当前正在执行代码和挂起的最高优先级异常的异常号。
(5)其他控制和状态功能。
(6)调试状态信息。这是通过调试专用寄存器区域中的控制和状态来实现的。
思考与练习2.12:Cortex-M0+处理器的存储器地址空间为_____________。
思考与练习2.13:Cortex-M0+处理器的中断向量表的开始地址是________________。
思考与练习2.14:Cortex-M0+处理器的PPB所实现的功能是_________________。
思考与练习2.15:说明Cortex-M0+处理器SCS实现的功能。
思考与练习2.16:说明Cortex-M0+处理器SCB实现的功能。
系统控制和ID寄存器如表2.10所示,从存储器基地址开始按地址顺序显示系统控制和ID寄存器。
表2.10 系统控制和ID寄存器
①查看寄存器描述,以获取更多信息;
②SVCall优先级位[31:30]是0;
③SysTick位[31:30]和PendSV位[23:22]是0。
1.CPUID基寄存器
CPUID基寄存器包含处理器部件号、版本和实现信息,其位分配如图2.13所示。
图2.13 CPUID基寄存器的位分配
(1)[31:24](IMPLEMENTER):表示实施者代码,取值为0x41,标识为Arm;
(2)[23:20](VARIANT):表示rnpm修订状态中的主要修订号n,取值为0x0,表示修订版0;
(3)[19:16](ARCHITECTURE):表示定义处理器架构的常数,取值为0xC,表示Armv6-M架构;
(4)[15:4](PART No):表示处理器的器件号,取值为0Xc60,表示Cortex-M0+;
(5)[3:0](REVISION):表示rnpm修订状态中的小修订号m,取值为0x1,表示补丁1。
2.中断控制和状态寄存器
中断控制和状态寄存器(Interrupt Control and State Register,ICSR)提供:
(1)不可屏蔽中断(Non-Maskable Interrupt,NMI)异常的设置挂起位;
(2)为PendSV和SysTick异常设置挂起和清除挂起位。
此外,它还给出正在挂起的最高优先级异常的异常号,该寄存器的位分配如图2.14所示。
图2.14 ICSR的位分配
(1)[31](NMIPENDSET):表示NMI设置挂起位。当给该位写1时,将NMI异常修改为挂起;当读取该位时,0表示没有挂起NMI异常,1表示正在挂起NMI异常。
由于NMI是优先级最高的异常,因此通常处理器一旦检测到对该位写入1,便立即进入NMI异常句柄。当进入句柄时,将该位清零。
这意味着只有在处理器执行该句柄重新使NMI信号有效时,NMI异常句柄对该位的读取才返回1。
(2)[30:29]:保留;
(3)[28](PENDSVSET):设置PENDSVSET挂起位。当该位设置为1时,将PendSV异常修改为挂起。读取该位时,0表示没有挂起PendSV异常,1表示正在挂起PendSV异常。对该位写1是使得PendSV异常挂起的唯一方法。
(4)[27](PENDSVCLR):清除PendSV挂起位。当该位设置为1时,从PendSV异常中删除挂起。
(5)[26](PENDSTSET):设置SysTick异常挂起位。当该位设置为1时,将SysTick异常修改为挂起。读取该位时,0表示没有挂起SysTick异常,1表示正在挂起SysTick异常。
(6)[25](PENDSTCLR):清除SysTick异常挂起位。当该位设置为1时,从SysTick异常中删除挂起。该位是只写位。在寄存器上读取它的值是未知。
(7)[24:18]:保留。
(8)[17:12](VECTPENDING):表示优先级最高的挂起的使能异常号。读取该位,返回0表示没有挂起的异常;非零表示优先级最高的挂起的使能异常号。
从该值减去16,即可获得CMSIS IRQ的编号,该编号表示中断清除使能、设置使能、清除挂起、设置挂起和优先级寄存器中相应的位。
(9)[11:0]:保留。
当写ICSR时,如果执行下面的操作,则结果是不可预知的。
(1)给PENDSVSET写1,并且给PENDSVCLR位写1。
(2)给PENDSTSET写1,并且给PENDSTCLR位写1。
3.向量表偏移寄存器
向量表偏移寄存器(Vector Table Offset Register,VTOR)表示向量表基地址与存储器地址0x00000000的偏移量,该寄存器的位分配如图2.15所示。
图2.15 VTOR的位分配
(1)[31:7](TBLOFF):表示向量表的基本偏移字段。它包含表的基地址与存储器映射底部偏移量的位[31:7]。
(2)[6:0]:保留。
4.应用中断和复位控制寄存器
应用中断和复位控制寄存器(Application Interrupt and Reset Control Register,AIRCR)为数据访问和系统的复位控制提供端状态。要写入该寄存器,必须将0x05FA写入VECTKEY字段,否则处理器将忽略该写入操作。该寄存器的位分配如图2.16所示。
图2.16 AIRCR的位分配
(1)[31:16](VECTKEYSTAT):VECTKEY注册键,为注册密钥。当读取时,未知;当写入时,将0x05FA写入VECTKEY字段,负责忽略写操作。
(2)[15](ENDIANESS):数据端比特。当读取该位时,返回值为0,表示小端模式。
(3)[14:3]:保留。
(4)[2](SYSRESETREQ):系统复位请求。当给该位设置为1时,请求一个系统级复位。当读取该位时,返回值为0。
(5)[1](VECTCLRACTIVE):保留用于调试。当读取该位时,返回值为0。当写入该位时,必须向该位写0,否则行为不可预测。
(6)[0]:保留。
5.系统控制寄存器
系统控制寄存器(System Control Register,SCR)控制进入和退出低功耗的功能。SCR的位分配如图2.17所示。
图2.17 SCR的位分配
(1)[31:5]:保留。
(2)[4](SEVONPEND):表示在挂起位上发送事件。当该位为0时,只有允许的中断或事件才能唤醒处理器,禁止的中断将被排除在外;当该位为1时,使能的事件和所有中断(包括禁止的中断)都可以唤醒处理器。
当挂起一个事件或中断时,事件信号将处理器从WFE唤醒。如果处理器不等待一个事件,则寄存该事件并影响下一个WFE。
在执行SEV指令或一个外部事件时,也会唤醒处理器。
(3)[3]:该位必须保持清零。
(4)[2](SLEEPDEEP):控制处理器在低功耗模式时使用休眠或深度休眠。当该位为0时,使用休眠;当该位为1时,使用深度休眠。
(5)[1](SLEEPONEXIT):当从句柄模式返回到线程模式时,表示退出时休眠。将该位设置为1时,可使中断驱动的应用程序避免返回到空的主应用程序。当该位为0时,返回线程时不休眠;当该位为1,并且从中断服务程序(Interrupt Service Routine,ISR)返回线程模式时,进入休眠或深度休眠。
(6)[0]:保留,必须保持清除状态。
6.配置和控制寄存器
配置和控制寄存器(Configuration and Control Register,CCR)是只读存储器,它指示Cortex-M0+处理器行为的某些方面。CCR的位分配如图2.18所示。
图2.18 CCR的位分配
(1)[31:10]:保留,必须保持清除状态。
(2)[9](STKALIGN):始终读为1,表示在异常入口上8个字节堆栈对齐。在异常入口处,处理器使用入栈PSR的第[9]位指示堆栈对齐。从异常返回时,它使用这个堆栈位恢复正确的堆栈对齐方式。
(3)[8:4]:保留,必须保持清除状态。
(4)[3](UNALIGN_TRP):总是读取为1,指示所有未对齐的访问将产生一个硬件故障。
(5)[2:0](Reserved):保留,必须保持未清除状态。
7.系统句柄优先级寄存器
系统句柄优先级寄存器(System Handler Priority Register,SHPR)2和3,将具有可配置优先级的系统异常句柄的优先级设置为0~192。SHPR2、SHPR3是字访问的。SHPR2的位分配如图2.19所示,SHPR3的位分配如图2.20所示。
图2.19 SHPR2的位分配
(1)[31:30](PRI_11):系统句柄11(SVCall)的优先级。
(2)[29:0]:保留,必须保持清除状态。
图2.20 SHPR3的位分配
(1)[31:30](PRI_15):系统句柄15(SysTick异常)的优先级(当没有实现SysTick定时器时,该字段为保留字段)。
(2)[23:22](PRI_14):系统句柄14(PendSV)的优先级。
当使用CMSIS访问系统异常优先级时,使用下面的CMSIS函数:
(1)uint32_t NVIC_GetPriority(IRQn_Type IRQn)
(2)void NVIC_SetPriority(IRQn_Type IRQn,uint32_t priority)
输入参数IRQn是IRQ的编号。
端(Endian)是指保存在存储器中的字节顺序。根据字节在存储器中的保存顺序,将其划分为小端(Little Endian)和大端(Big Endian)。
(1)小端。
对一个32位字长的数据来说,最低字节保存该数据的第0位至第7位,如图2.21(a)所示,也就是我们常说的“低址低字节,高址高字节”。
(2)大端。
对一个32位字长的数据来说,最低字节保存该数据的第24位至第31位,如图2.21(b)所示,也就是我们常说的“低址高字节,高址低字节”。
图2.21 Cortex0-M0+小端和大端定义
对Cortex-M0+处理器来说,默认支持小端。然而,端概念只存在硬件这一层。
思考与练习2.17:请说明在Cortex-M0+处理器中,端的含义。
思考与练习2.18:请说明大端和小端的区别。
异常(Exception)是事件,它将使程序流退出当前的程序线程,然后执行和该事件相关的代码片段(子程序)。通过软件代码,可以使能或者禁止处理器核对异常事件的响应。事件可以是内部的也可以是外部的,如果事件来自外部,则称为中断请求(Interrupt Request,IRQ)。
本节介绍Cortex-M0+处理器异常所处的状态、异常类型、异常优先级、向量表等。
每个异常均处于以下状态之一。
(1)非活动(Inactive)。当异常处于该状态时,它既不活动也不挂起。
(2)挂起(Pending)。当异常处于该状态时,表示它在等待处理器为其提供服务。一个来自外设或软件的中断请求可以将相应中断的状态改为挂起。
(3)活动(Active)。处理器正在处理异常但尚未完成。异常句柄可以中断另一个异常的执行。在这种情况下,两个异常均处于活动状态。
注: 异常句柄是指在异常模式中,所执行的一段代码,也称为异常服务程序。如果异常是由IRQ引起的,则将其称为中断句柄(Interrupt Handler)/中断服务程序(Interrupt Service Route,ISR)。
(4)活动和挂起。处理器正在处理异常,并且同一来源还有一个挂起的异常。
在Cortex-M0+处理器中,提供了不同的异常类型,以满足不同应用的需求,包括复位、不可屏蔽中断、硬件故障、请求管理调用、可挂起的系统调用、系统滴答和外部中断。
1.复位
Armv6-M框架支持两级复位。复位包括:
(1)上电复位用于复位处理器、SCS和调试逻辑;
(2)本地复位用于复位处理器和SCS,不包括与调试相关的资源。
2.不可屏蔽中断
不可屏蔽中断(Non-Maskable Interrupt,NMI)特点如下:
(1)用户不可屏蔽NMI;
(2)它用于对安全性苛刻的系统中,如工业控制或汽车;
(3)它可以用于电源失败或看门狗。
对STM32G0来说,NMI是由SRAM奇偶校验错误、Flash存储器双ECC错误或时钟故障引起的。
3.硬件故障
硬件故障(HardFault)常用于处理程序执行时产生的错误,这些错误可以是试图执行未知的操作码、总线接口或存储器系统的错误,也可以是尝试切换到Arm状态之类的非法操作。
4.请求管理调用
请求管理调用(SuperVisor Call,SVC)是由SVC指令触发的异常。在操作系统环境中,应用程序可以使用SVC指令来访问操作系统内核功能和设备驱动程序。
5.可挂起的系统调用
可挂起的系统调用(PendSV)是用于包含操作系统的应用程序的另一个异常,SVC异常在SVC指令执行后会马上开始,PendSV在这点上有所不同,它可以延迟执行,在操作系统上使用PendSV可以确保高优先级任务完成后再执行系统调用。
6.系统滴答(SysTick)
NVIC中的SysTick定时器为操作系统可以使用的另一个特性。几乎所有操作系统的运行都需要上下文(现场)切换,而这一过程通常需要依靠定时器来完成。Cortex-M0+处理器内集成了一个简单的定时器,这样使得操作系统的移植更加容易。
7.外部中断
Cortex-M0+处理器中的NVIC,支持最多32个中断请求(IRQ)。由于STM32G0提供了SYSCFG模块,使得STM32G0可以响应中断事件的数量大于32个,这是因为SYSCFG模块可以将几个中断组合到一个中断线上。通过读取SYSCFG模块中的ITLINEx寄存器,就可以快速确定产生中断请求的外设源了。
只有用户使能外部中断后,才能使用它。如果禁止了外部中断,或者处理器正在运行另一个相同或更高优先级的异常处理,则中断请求会被保存在挂起状态寄存器中。当处理完高优先级的中断或返回后,才能执行挂起的中断请求。对NVIC来说,可接受的中断请求信号可以是高逻辑电平,也可以是中断脉冲(最少为一个时钟周期)。
注: (1)在MCU外部接口中,外部中断信号可以是高电平也可以是低电平,或者可以通过编程配置。
(2)软件可以修改外部中断的优先级,但是不能修改复位、NMI和硬件故障的优先级。
在Cortex-M0+处理器中,每个异常都有相关联的优先级,其中:
(1)较低的优先级值意味着具有较高的优先级;
(2)除了复位、硬件故障和NMI外,软件可配置其他所有异常的优先级。
如果软件没有配置任何优先级,则所有可配置优先级异常的优先级为0。
注: 可配置优先级的值在0~192的范围内,以64为步长。具有固定负优先级值的复位、硬件故障和NMI异常始终有比其他任何异常更高的优先级。复位的优先级值为-3,NMI的优先级值为-2,硬件故障的优先级值为-1,除此之外的其他异常(包括外设中断和软件异常)的优先级为0~3。
为IRQ[0]分配较高的优先级值,为IRQ[1]分配较低的优先级值,则意味着IRQ[1]的优先级高于IRQ[0]。如果IRQ[1]和IRQ[0]均有效,则先处理IRQ[1],处理完毕后再处理IRQ[0]。
如果多个挂起的异常具有相同的优先级,则优先处理具有最低优先级编号的异常。例如,如果IRQ[0]和IRQ[1]都处于挂起状态并具有相同的优先级,则先处理IRQ[0]。
当处理器执行一个异常句柄时,如果发生了具有更高优先级的异常,则会抢占该异常句柄。如果又发生与正在处理的异常具有相同优先级的异常,则不会抢占当前正在处理的句柄。然而,新中断的状态变为挂起。
向量表包含用于所有异常句柄的堆栈指针和起始地址(也称为异常向量)。向量表中异常向量的顺序如图2.22所示。每个向量的最低有效位必须为1,用来指示异常句柄是用Thumb代码编写的。
图2.22 向量表中异常向量的顺序
系统复位时,向量表固定在地址0x00000000。具有特权级的软件可以写入向量表偏移寄存器(Vector Table Offset Register,VTOR),以根据向量表的大小和TBLOFF设置的粒度,将向量表的起始地址重新定位到其他存储器位置。
注: 为了简化软件层的应用程序设计,Cortex微控制器软件接口标准(Cortex Microcontroller Software Interface Standard,CMSIS)只使用IRQ号。它对中断以外的其他异常使用负值。IPSR返回异常号。
在描述异常的处理时,会用到下面的术语。
(1)抢占(preemption)。
如图2.23所示,当处理器正在处理一个中断,一个具有更高优先级的新请求到达时,新的异常可以抢占当前的中断,称之为嵌套的异常处理。
图2.23 抢占和中断嵌套
注: 图中的保存上下文就是通常所说的保存现场,也就是说,在处理器进入异常句柄之前,先将进入异常句柄之前处理器的状态保存起来,处理器的状态包括寄存器以及状态标志等,称之为上文。此外,处理器还得知道在处理完中断句柄后该如何继续执行原来的程序,称之为下文。只有处理器能正确地保存上下文的信息,才能在其进入异常句柄后,正确地从异常句柄返回。应该说术语“上下文”比“现场”更能反映处理器处理异常的机制。
在处理完较高优先级的异常后,先前被打断的异常句柄将恢复继续执行。
Cortex-M0+处理器内的微指令控制序列会自动地将上下文保存到当前堆栈,并在中断返回时将其恢复。
(2)返回(return)。
当完成处理异常句柄时,会发生返回这种情况,并且:
①没有正在挂起需要待处理的具有足够优先级的异常;
②已完成的异常句柄未处理迟到的异常。
处理器弹出堆栈,并且将处理器的状态恢复到发生中断之前的状态。
(3)尾链(tail-chaining)。
如图2.24所示,这种机制加快了异常处理的速度。在处理完一个异常句柄后,如果一个挂起的异常满足进入异常的要求,则跳过弹出堆栈的过程,并将控制权转移到新的异常句柄。
图2.24 尾链机制
因此,将具有较低优先级(较高优先级值)的背靠背中断连接在一起,这样在处理异常句柄时,就能显著减少处理延迟并降低器件功耗。
(4)迟到(late-arriving)。
如图2.25所示,这种机制可加快抢占速度。如果在保存当前异常的状态期间又发生了较高优先级的异常,则处理器将切换未处理较高优先级的异常,并为该异常启动向量获取。由于状态保存不受延迟到达的影响,因此对于两种异常状态,保存的状态都相同。从迟到异常的异常句柄返回时,将应用常规的尾链规则。
图2.25 迟到机制
1.异常进入
当存在具有足够优先级的挂起异常时,将发生进入异常,并且:
(1)处理器处于线程模式;
(2)新异常的优先级要高于正在被处理的异常,在这种情况下,新异常抢占正在被处理的异常。
当一个异常抢占另一个异常时,将嵌套异常。当处理采纳(处理)一个异常时,除非异常是尾链或迟到的异常,处理器将信息压入当前的堆栈。该操作称为压栈(入栈)。8个数据字的结构称为堆栈帧,堆栈帧如图2.26所示。
图2.26 堆栈帧
在压栈之后,堆栈指针指向堆栈中的最低地址。堆栈帧与双字地址对齐。堆栈帧包含返回地址。这是被中断打断的当前正在执行程序的下一条地址。当从异常返回时,将该值恢复到PC,这样可以继续执行被打断的程序。
处理器提取向量,从向量表中读取异常句柄的起始地址。当完成压栈后,处理器开始执行异常句柄。同时处理器将EXC_RETURN值写入LR。这指示哪个堆栈指针对应于堆栈帧,以及处理器在进入异常之前所处的模式。
如果处理器在进入异常期间没有发生更高优先级的异常,则处理器开始执行异常句柄,并自动将当前挂起的中断状态修改为活动。
如果处理器在进入异常期间发生了一个更高优先级的异常,则处理器开始对该异常执行异常句柄,并且不会更改较早异常的挂起状态。这是迟到的情况。
2.异常返回
当处理器处理句柄模式,并且执行以下指令之一,尝试将PC设置为EXC_RETURN值时,将发生异常返回:
(1)加载PC的POP指令;
(2)使用任何寄存器的B PBX指令。
处理器在异常入口处将EXC_RETURN值保存到LR中。异常机制依靠该值来检测处理器何时完成异常句柄。EXC_RETURN值的第[31:4]位为0xFFFFFFF。当处理器将匹配该模式的值加载至PC时,它将检测到该操作不是正常的分支操作,而是完成异常。结果,它启动异常返回序列。EXC_RETURN值的位[3:0]指示所要求返回的堆栈和处理器模式,异常返回行为如表2.11所示。
表2.11 异常返回行为
思考与练习2.19:请说明在Cortex-M0+处理器中,异常的定义,以及处理异常的过程。
思考与练习2.20:根据图2.23,说明处理中断嵌套的过程。
思考与练习2.21:请说明在Cortex-M0处理器中,向量表所实现的功能。
思考与练习2.22:请说明在Cortex-M0处理器中,异常的类型。
NVIC中的中断寄存器集如表2.12所示。本节详细介绍这些寄存器的功能,以帮助读者更好地理解处理器异常的原理和控制机制。
表2.12 NVIC中的中断寄存器集
1.中断设置使能寄存器
中断设置使能寄存器(NVIC Interrupt Set Enable Register,NVIC_ISER)使能中断,并显示了所使能的中断,该寄存器的位分配如图2.27所示。
图2.27 中断设置使能寄存器的位分配
[31:0]:SETENA,中断设置使能位。当写入时:
①0,没有影响;
②1,使能中断。
当读取时:
①0,表示禁止中断;
②1,表示使能中断。
如果使能了待处理的中断,则NVIC会根据其优先级激活该中断。如果未使能中断,则中断有效信号将中断的状态改为挂起,但NVIC不会激活该中断,无论其优先级如何。
2.中断清除使能寄存器
中断清除使能寄存器(NVIC Interrupt Clear Enable Register,NVIC_ICER)禁用中断,并显示使能了哪些中断,该寄存器的位分配如图2.28所示。
图2.28 中断清除使能寄存器的位分配
[31:0]:CLRENA,中断清除使能位。当写入时:
①0,没有影响;
②1,禁止中断。
当读取时:
①0,禁止中断;
②1,使能中断。
3.中断设置挂起寄存器
中断设置挂起寄存器(NVIC Interrupt Set Pending Register,NVIC_ISPR)强制中断进入挂起状态,并指示正在挂起的中断,该寄存器的位分配如图2.29所示。
图2.29 中断设置挂起寄存器的位分配
[31:0]:SETPEND,中断设置挂起位。当写入时:
①0,没有影响;
②1,将中断状态改为挂起。
当读取时:
①0,当前没有挂起中断;
②1,当前有挂起中断。
注: 将1写入NVIC_ISPR位对应于:对于一个正在挂起的中断无效;禁用的中断将该中断的状态设置为挂起。
4.中断清除挂起寄存器
中断清除挂起寄存器(NVIC Interrupt Clear Pending Register,NVIC_ICPR)从中断中删除挂起状态,并显示正在挂起的中断,该寄存器的位分配如图2.30所示。
图2.30 中断清除挂起寄存器的位分配
[31:0]:CLRPEND,清除中断挂起位。当写入时:
①0,没有影响;
②1,删除挂起状态并中断。
当读取时:
①0,没有挂起中断;
②1,正在挂起中断。
5.中断优先级寄存器
中断优先级寄存器(NVIC Interrupt Priority Register,NVIC_IPR)0~7为每个中断提供了8位的优先级字段。这些寄存器只能通过字访问,每个寄存器包含4个优先级字段,这8个寄存器的位分配如图2.31所示,这些位分配的功能如表2.13所示。
图2.31 中断优先级寄存器的位分配
表2.13 位分配的功能
Cortex-M0+处理器中断对电平和脉冲均敏感。脉冲中断也称为边沿触发中断。
电平敏感中断一直保持有效,直到外设将中断信号设置为无效为止。通常,发生这种情况是因为ISR访问外设,导致其清除了中断请求。脉冲中断是在处理器时钟的上升沿同步采样的中断信号。为了确保NVIC检测到中断,外设必须在至少一个时钟周期内使中断信号有效,在此期间NVIC检测到脉冲并锁存中断。
当处理器进入ISR时,它会自动从中断中删除挂起中断。对于电平敏感的中断,如果在处理器从ISR返回之前没有使该信号无效,则中断状态再次变为挂起,处理器必须再次执行它的ISR。这意味着外设可以保持有效的中断信号,直到不需要继续服务为止。
Cortex-M0+处理器锁存所有中断。由于以下原因之一,挂起外设中断。
(1)NVIC检测到中断信号有效,而相应的中断无效。
(2)NVIC检测到中断信号的上升沿。
(3)软件写入相应的中断设置挂起寄存器位。
中断状态保持挂起,直到发生下面的情况之一为止。
(1)处理器进入中断的ISR。这会将中断的状态从挂起改为活动。
①对于电平敏感中断,当处理器从ISR返回时,NVIC采样中断信号。如果该信号有效,则中断状态变为挂起,这可能导致处理器立即重新进入ISR。否则,中断状态将变为非活动状态。
②对于脉冲中断,NVIC持续监视中断信号,如果发出脉冲信号,则中断状态将变为挂起并激活。在这种情况下,当处理器从ISR返回时,中断状态将变为挂起,这可能导致处理器立即重新进入ISR。如果在处理器处于ISR中时没有发出中断信号,则当处理器从ISR返回时,中断状态变为非活动状态。
(2)软件写入相应的中断清除挂起寄存器位。
对于电平敏感的中断,如果中断信号仍然有效,则中断状态不会变化。否则,中断状态将变为非活动状态。
对于脉冲中断,中断状态变为:
①非活动状态(如果状态为挂起);
②活动(如果状态是活动和挂起)。
确保软件使用正确对齐的寄存器访问。处理器不支持对NVIC的非对齐访问。即使一个中断被禁止,它也可以进入挂起状态。禁用中断只会阻止处理器接收该中断。
在对VTOR进行编程以重定位向量表之前,应确保新的向量表的入口已经设置了故障句柄、NMI和所有类似中断的使能异常。