本文参考资料来自《ARM Cortex-M3与Cortex-M4 权威指南》
Cortex-M4 处理器基于ARMv7-M架构,发布时,架构中又额外增加了新的指令和特性,改进后的架构也被称为ARMv7E-M
编程模型
操作模式和状态
操作状态:
- 调试状态:当处理器被暂停后(触发断点等),进入调试状态并停止指令执行
- Thumb状态:处理器执行代码则处于此状态(由于Cortex-M处理器不支持ARM指令集,所以ARM状态不存在)
操作模式:
- 处理模式:执行中断服务程序(ISR)等异常处理。在处理模式下处理器总是具有特权访问等级。
- 线程模式:执行普通的应用程序代码时,处理器可处于特权访问等级,也可以处于非特权访问等级
操作模式和状态:
寄存器
Cortex-m4处理器的寄存器组中有16个寄存器,其中13个为32位通用目的寄存器,其他3个有特殊用途
- R0~R12:通用寄存器,初始值未定义; R0~R7被称作低寄存器(16位指令只能访问低寄存器); R8~R12被称作高寄存器
- R13,栈指针(SP):通过PUSH和POP操作存储的访问;物理上存在两个栈指针:主栈指针(MSP,默认栈指针)和进程栈指针(PSP,只用于线程模式);对于一般程序,两个寄存器只会有一个可见
- R14,链接寄存器(LR):用于函数或子程序调用时返回地址的保存;函数或子程序结束时,程序控制可以通过将LR的数值加载到PC中返回调用程序并继续执行
- R15,程序计数器(PC):可读可写的寄存器,读操作返回当前指令地址加4(三级流水线),写操作会引起跳转;PC永远下一条要取指的指令地址
特殊寄存器
通过MSR和MRS等特殊寄存器访问指令来操作特殊寄存器
MRS<reg>, <special_reg> ; 将特殊寄存器读入寄存器
MSR<special_reg>, <reg> ; 写入特殊寄存器
1. 程序状态寄存器:
程序状态寄存器包括:应用PSR(APSR); 执行PSR(EPSR); 中断PSR(IPSR)
MRS r0, PSR ; 读组合程序状态字
MSR PSR, r0 ; 写组合程序状态字
MRS r0, APSR ; 将标志状态读入R0
MRS r0, IPSR ; 读取异常/中断状态
MSR APSR, r0 ; 写标志状态
位 | 描述 |
---|---|
N | 负标志 |
Z | 零标志 |
C | 进位(或者非借位)标志 |
V | 溢出标志 |
Q | 饱和标志 |
GE[3:0] | 大于或等于标志,对应每个字节通路 |
ICI/IT | 中断继续指令(ICI)位,IF-THEN指令状态位用于条件执行 |
T | Thumb状态,总是1,清除此位会引起错误异常 |
异常编号 | 表示处理器正在处理的异常 |
2. PRIMASK、FAULTMASK 和 BASEPRI寄存器
PRIMASK、FAULTMASK 和 BASEPRI寄存器用于异常或中断屏蔽
- PRIMASK寄存器为1位宽的中断屏蔽寄存器,用于禁止除NMI和HardFault外的所有异常,实际上是将当前优先级改为0(最高可编程优先级);写入1禁止所有中断,写入0使能中断
- FAULTMASK与PRIMASK类似,实际上会将当前优先级修改为-1,这样甚至HardFault也会被屏蔽
- BASEPRI寄存器禁止优先级低于某特定等级的中断,将所需屏蔽的优先级写入BASEPRI寄存器即可
3. CONTROL寄存器
Cortex-M4处理器的CONTROL寄存器定义了:
- 栈指针的选择(主栈指针/进程栈指针)
- 线程模式的访问等级(特权/非特权)
- 有一位表示当前上下文(正在执行的代码)是否使用浮点单元
位 | 功能 |
---|---|
nPRIV(第0位) | 定义线程模式中的特权等级:该位为0时(默认),处理器会处于线程模式中的特权等级; 1时,则处于线程模式中的非特权等级 |
SPSEL(第1位) | 定义栈指针的选择:该位为0时(默认),线程模式使用主栈指针(MSP); 1时,线程模式使用进程栈指针; 处理模式时,该位始终位0且对其的写操作会被忽略 |
FPCA(第2位) | 异常处理机制使用该位确定异常产生时浮点单元中的寄存器是否需要保存;1时,当前上下文使用浮点指令,需要保存浮点寄存器 |
nPRIV和SPSEL的不同组合:
nPRIV | SPSEL | 应用场景 |
---|---|---|
0 | 0 | 简单应用,整个应用运行在特权访问等级,主程序和中断处理只会使用一个栈(即主栈MSP) |
0 | 1 | 具有嵌入式OS的应用,当前执行的任务运行在特权线程模式,当前任务选择使用进程栈指针(PSP),而MSP则用于OS内核以及异常处理 |
1 | 1 | 具有嵌入式OS的应用,当前执行的任务运行在非特权线程模式,当前任务选择使用进程栈指针(PSP),而MSP则用于OS内核以及异常处理 |
0 | 1 | 线程模式运行在非特权访问等级并且使用MSP,处理模式中可见,而用户任务则一般无法使用,因为在多数嵌入式OS中,应用任务的栈和OS内核以及异常处理使用的栈时相互独立的 |
4. 浮点寄存器
Cortex-M4中具有可选的浮点单元
- S0\~S31和D0\~D15:S0~S31都是32位寄存器,每个都可以通过浮点指令访问,或者利用符号D0~D15成对访问
- 浮点状态和控制寄存器(FPSCR)
位 | 描述 |
---|---|
N | 负标志(由浮点比较运算更新) |
Z | 零标志(由浮点比较运算更新) |
C | 进位/借位标志(由浮点比较运算更新) |
V | 溢出标志(由浮点比较运算更新) |
AHP | 交替半精度控制位:0,IEEE半精度格式(默认);1,交替半精度格式 |
DN | 默认NaN(非数值)模式控制位:0,NaN操作数会变为浮点运算的输出(默认);1,任何涉及一个或多个NaN的运算会返回默认的NaN |
FZ | 清零模式控制位:0,清零模式禁止(默认);1,清零模式使能 |
RMode | 舍入模式控制位,表示的舍入模式基本上适用于所有的浮点指令:00,最近摄入(RN)模式(默认);01,正无穷舍入(RP)模式;10,负无穷舍入(RM)模式;11,向零舍入(RZ)模式 |
IDC | 输入非正常累积异常位,在产生浮点异常时为1,写0则清除该位 |
IXC | 不精确的累积异常位,浮点异常产生时位1,写0会将其清除 |
UFC | 下溢累积异常位,浮点异常产生时位1,写0会将其清除 |
OFC | 溢出累积异常位,浮点异常产生时位1,写0会将其清除 |
DZC | 被零除累积异常位,浮点异常产生时位1,写0会将其清除 |
IOC | 非法操作累积异常位,浮点异常产生时位1,写0会将其清除 |
- 经过存储器映射的浮点单元控制寄存器CPACR:
浮点单元默认被禁止以降低功耗,在使用任何浮点指令前,都必须通过编程CPACR寄存器来使能浮点单元
存储器系统
存储器系统特性
- 4GB线性地址空间。通过32位选址,ARM处理器可以访问2^32 Byte=4GB的存储器空间。尽管许多嵌入式系统存储器要不了这么大的存储器,32位的寻址能力可以确保将来升级和扩展的可能
- 架构定义存储器映射。4GB的存储器空间被划分为多个区域,用于预定义的存储器和外设,以优化处理器设计的性能(Cortex-M4处理器具有多个总线接口,允许程序代码用的CODE区域的访问和对SRAM或对外设区域的数据操作同时进行)
- 支持小端和大端的存储器系统。Cortex-M4处理器可以选择使用小端或者大端的存储器系统
- 位段访问(可选)。当包含位段特性时,存储器映射中的两个1MB区域可以通过两个位段区域进行位寻址,这样可以实现对SRAM或外设地址空间中单独位的原子操作
- 写缓冲。对可缓冲存储器区域写操作需要花费几个周期时间,Cortex-M4处理器的写缓冲可以把写操作缓存起来,这样处理器就可以继续执行下一条指令,于是便提高了程序的执行速度
- 存储器保护单元(MPU)。MPU定义了各存储器区域的访问权限,且为可编程。Cortex-M4处理器中的MPU支持8各可编程区域,可在嵌入式OS中提高系统的健壮性
- 非对齐传输支持。ARMv7-M架构的所有处理器(包括Cortex-M4)支持非对齐传输
存储器映射
Cortex-M处理器的4GB地址空间被分为了多个存储器区域:
1. 程序代码访问(如CODE区域)
2. 数据访问(如SRAM区域)
3. 外设(如外设区域)
4. 处理器的内部控制和调试部件
这样的架构具有很大的灵活性,存储器区域可用于其他目的。(程序既可以在CODE区域里执行,也可以在SRAM区域执行,并且微控制器也可以在CODE区域加入SRAM块)
实际上,微控制器设备只会使用每个区域的一小部分作为程序的Flash、SRAM和外设,有些区域可能不会用到
所有Cortex-M处理器的存储器映射处理都是一样的。比如PPB地址区域中存在嵌套向量中断控制器(NVIC)的寄存器、处理器配置寄存器以及调试部件的寄存器等(这样做提高不同Cortex-M设备间的软件可移植性和代码可重用性)
栈储存
ARM处理器将系统主存储器用于栈空间操作,使用PUSH指令进栈以及POP指令出栈.每次使用PUSH和POP操作后,当前使用的栈指针都会自动调整
栈可用于:
- 当正在执行的函数需要使用寄存器(寄存器组中)进行数据处理时,临时存储数据的初始值。这些数据在函数结束时可以被恢复出来,以免调用函数的程序丢失数据
- 往函数或子程序中的信息传递
- 用于存储局部变量
- 在中断等异常产生时保存处理器状态和寄存器数值
Cortex-M处理器使用的栈模型被称作”满递减”。处理器启动后,SP被设置为栈存储空间最后的位置。对于每次PUSH操作,处理器首先减小SP的值,然后将数据存储在SP指向的存储器位置。对于POP操作,SP指向的存储器位置的数据被读出,然后POP的数值自动增加
Cortex-M处理器在物理上存在两个栈指针:
- 主栈指针(MSP).复位后默认使用的栈指针,用于所有的异常处理
- 进程栈指针(PSP).只能用于线程模式的栈指针,通常用于运行嵌入式OS的嵌入式系统中的应用任务
MSP和PSP的选择由CONTROL寄存器的第二位SPSEL的数值决定,若该位为0,则线程模式在栈操作时使用MSP,否则线程模式使用PSP。另外,在从处理模式到线程模式的异常返回期间,栈指针的选择可由EXC_RETURN(异常返回)数值决定,这样处理器硬件会响应地自动更新SPSEL的数值
存储器保护单元(MPU)
Cortex-M4处理器中的MPU是可选的。多数应用不会用到MPU,可以忽略。在需要可靠性高的嵌入式系统中,MPU可以通过定义特权和非特权访问权限,来保护存储器区域
MPU可编程,Cortex-M4中的MPU支持8个可编程区域
异常和中断
异常
异常时会改变程序流的事件,当其产生时,处理器会暂停当前正在执行的任务,转而执行一段被称为异常处理的程序
Cortex-M处理器具有多个异常源:
1. NVIC处理异常。NVIC可以处理多个中断请求(IRQ)和一个不可屏蔽中断(NMI)请求,IRQ一般由片上外设或外部中断通过I/O端口产生,NMI可用于看门狗对时期或掉电检测。处理器内部也有名为SysTick的定时器,可以产生周期性的定时中断请求
2. 处理器自身也是一个异常事件源,其中包括表示系统错误状态的错误事件以及软件产生、支持嵌入式OS操作的异常。
3.
异常类型表:
每个异常源都有一个异常编号,编号1~15被归为系统异常,16号及其之上的则用于中断。
嵌套向量中断控制器(NVIC)
NVIC是Cortex-M处理器的一部分,它是可编程的且寄存器位于存储器映射的系统控制空间(SCS)
NVIC具有特性:
1. 灵活的异常和中断管理:每个中断(除了NMI)都可以被使能或禁止,而且都具有可由软件设置或清除的挂起状态
2. 嵌套向量/中断支持:异常产生后,NVIC会将异常优先级和当前执行异常优先级进行比较,若新异常的优先级高,则暂停当前正在执行的任务,有些寄存器则会被保存在栈空间,处理器执行新异常的异常处理,当更高优先级的异常处理完成后,会被异常返回操作终止,处理器自动从栈中恢复寄存器内容,并继续执行之前任务
3. 向量化的异常/中断入口:当异常发生时,处理器需要确定相应的异常处理入口的位置,Cortex-M处理器则会从存储器的向量表中自动定位异常处理的入口(降低从异常产生到异常处理执行间的延时)
4. 中断屏蔽:Cortex-M4处理器中的NVIC提供了多个中断屏蔽寄存器(PRIMASK,FAULTMASK和BASEPRI)
向量表
确定异常处理的起始地址,处理器使用了一种向量表机制。 向量表为系统存储器内的字数据数组,每个元素都代表一个异常类型的起始地址。
向量表可以重定位,重定位由NVIC中名为向量表偏移寄存器(VTOR)的可编程寄存器控制。复位后,VTOR默认位0,向量表位于地址0x0处
错误处理
Cortex-M4处理器中有几个异常为错误处理异常。处理器检测到错误时,触发错误异常,检测到的错误包括执行未定义的指令以及总线错误对存储器访问返回错误的响应等
总线错误、使用错误以及存储器管理错误默认都是禁止的,且所有的错误事件都会触发HardFault异常。配置都是可编程的,可以单独使能这三个错误异常,以处理不同类型的错误,HardFault异常总是使能的
系统控制块(SCB)
SCB为处理器的一部分,位于NVIC中。SCB包含寄存器,用于:
- 控制处理器配置(如低功耗模式)
- 提供错误状态信息(错误状态寄存器)
- 向量表重定位(VTOR)
调试
Cortex-M处理器提供了两种接口:调试和跟踪
利用调试接口,调试适配器可以连接到Cortex-M微控制器上以控制调试特性和访问片上存储器空间。Cortex-M处理器支持传统的使用4或5个引脚的JTAG协议或者串行线调试(SWD)的2针协议
跟踪接口用于运行时手机处理器的信息,比如数据、事件、概况信息或者程序执行的完整细节。支持跟踪的接口:串行线查看(SWV)的单引脚协议以及跟踪端口的多脚协议
复位和复位流程
Cortex-M的复位:
- 上电复位。复位微控制器中的所有部分,其中包括处理器、调试支持部件和外设等
- 系统复位。只复位处理器和外设,不包括处理器的调试支持部件
- 处理器复位。只复位处理器