本学习参照 "Cortex-M3权威指南"学习,需要详细学习,建议自行观看。
Cortex-M3基础
CM3介绍
Cortex-M3 处理器内核其实就是单片机的中央处理单元( CPU )。
完整的基于 CM3 的 MCU 还需要很多其它组件,如下,
Cortex-M3 是一个 32 位处理器内核;
内部的数据路径是 32 位的,寄存器是 32 位的,存储器 接口也是 32 位的;
CM3 采用了哈佛结构,拥有独立的指令总线和数据总线;
CM3 提供一个可选的 MPU ,而且在需要的情况下也可以使用外部的 cache。
CM3的简化试图如下,
ARM 处理器一直支持两种形式上相对独立的指令集,它们分别是:
- 32位的ARM指令集。对应处理器状态:ARM状态
- 16位的Thumb指令集。对应处理器状态:Thumb状态
备注:Thumb-2指令集是16位指令首次与32位指令并存的指令集。
寄存器组
Cortex-M3 处理器拥有 R0-R15 的寄存器组以及一些特殊功能寄存器。
通用寄存器R0-R7
R0-R7 也被称为低组寄存器,用于数据操作,且所有指令都能访问她们,32 位 ,
复位后的初始值是不可预料。
通用寄存器R8-R12
R8-R12 也被称为高组寄存器,也是用于数据操作,32位,但是只有很少的16位Thumb指令可以访问它们,32 位的Thumb-2 指令则不受限制。
堆栈指针R13
R13 是堆栈指针,也可以写作SP。
Cortex-M3 拥有两个堆栈指针,然而它们是 banked ,因此任一时刻只能使用其中的一个。
- 主堆栈指针( **MSP):**复位后默认使用的堆栈指针,OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。
- **进程堆栈指针(PSP):**用于常规的应用程序代码(不处于异常服用例 程中时)。
R13 (SP) 总是指向当前使用的堆栈指针(要么是 MSP,要么是 PSP)。
如果你需要在代码中明确地访问另一个(非当前)堆栈指针,例如当前使用 MSP,但你想读取或写入 PSP,你需要使用特殊的指令(MRS,MSR)来进行操作。
- MRS 指令 :用于将特殊寄存器的内容(例如 MSP 或 PSP)移动到通用寄存器中。例如:
MRS R0, PSP
会将 PSP 的值读取到通用寄存器 R0 中。 - MSR 指令 :用于将通用寄存器的内容写入特殊寄存器(例如 MSP 或 PSP)。例如:
MSR PSP, R0
会将通用寄存器 R0 的值写入到 PSP 中。
堆栈指针(SP)用于访问堆栈,指向栈顶,并且 PUSH 指令和 POP 指令默认使用 SP 。
堆栈指针的最低两位永远是 0 ,这意味着堆栈总是 4 字节对齐的。
当最后两位为0时,相当于把二进制数左移两位也就是乘以4,所以一定是4的倍数,就是 4字节对齐
原因:目的是使内存访问更高效、更稳定。
堆栈由 一块连续的内存和一个栈顶指针组成,特点是**"后进先出"。**
PUSH(出栈)与POP(入栈)的简单示意图如下,详细会在后面讲述,
连接寄存器R14
R14 是连接寄存器( LR )。
LR用于存储函数(子程序)调用的返回地址。
当一个函数被调用时,处理器需要知道在函数执行完毕后需要返回到哪个位置继续执行程序。连接寄存器 R14 就是用来保存这个返回地址的。
指向BL指令后,会将 PC+4 的值存入R14.
程序计数器R15
R15 是程序计数器,在汇编代码中一般叫它的外号" PC "。
主要作用是保存 当前正在执行的指令的地址。
处理器通过读取 PC 的值来确定下一条指令的位置。
比如对于32位长的指令,每当处理器执行一条指令时, PC 的值通常会自动增加4个字节。
特殊功能寄存器
Cortex-M3 还在内核水平上搭载了若干特殊功能寄存器,包括
- 程序状态字寄存器组(PSRs)
- 中断屏蔽寄存器组(PRIMASK, FAULTMASK, BASEPRI)
- 控制寄存器(CONTROL)
备注:它们只能被专用的 MSR/MRS 指令访问,而且它们也没有与之相关联的访问地址。
程序状态寄存器(PSR)
程序状态寄存器在其内部又被分为三个子状态寄存器:
- 应用程序 PSR(APSR)
- 中断号 PSR(IPSR)
- 执行 PSR(EPSR)
备注:只能通过MRS/MSR指令访问,可单独访问和组合访问 。
中断屏蔽寄存器
三个中断屏蔽寄存器用于控制异常的使能和失能,功能如下,
备注:只能通过MRS/MSR指令访问。
控制寄存器(CONTROL)
控制寄存器有两个用途,其一用于定义特权级别,其二用于选择当前使用哪个堆栈指针。
-
在 Cortex-M3 的 handler 模式中,CONTROL[1]总是 0。在特权级的线程模式中则可以为修改 0 或 1。
-
CONTROL[1]仅当在特权级下操作时才允许写该位。一旦进入了用户级,唯一返回特权级的途径,就是触发 一个(软)中断,再由服务例程改写该位。
备注:只能通过MRS/MSR指令访问。
操作模式
Cortex-M3 处理器支持两种处理器的操作模式 :
两种操作模式分别为: 处理者模式 (handler mode) 和 线程模式( thread mode )。
Cortex-M3 的另一个侧面则是特权的分级------ 特权级 和 用户级 。
线程模式:用于执行主程序(应用程序代码)和中断以外的所有正常代码。
处理器模式:用于处理所有的异常和中断服务例程,中断或异常发生时,CM3自动切换到处理器模式来执行相应的异常处理代码。
特权级:代码可以访问处理器的所有功能和系统资源,括访问系统级寄存器、禁用中断和更改堆栈指针。
用户级:无法访问一些关键系统资源和系统控制寄存器,用于用户应用程序代码。
从用户级到特权级的唯一途径就是异常:如果在程序执行过程中触发了一个异常,处
理器总是先切换入特权级,并且在异常服务例程执行完毕退出时,返回先前的状态
异常和中断
Cortex-M3 支持大量异常,包括 16-4-1=11 个系统异常,和最多 240 个外部中断------简称 IRQ。
由外设产生的中断信号,除了 SysTick 的之外,全都连接到 NVIC 的中断输入信号线。
Cortex-M3的异常类型如下,
向量表
当 CM3 内核响应了一个发生的异常后,对应的异常服务例程 (ESR) 就会执行。
为了决定 ESR 的入 口地址,CM3 使用了"向量表查表机制"。
向量表其实是一个 WORD ( 32 位 整数)数组,每个下标对应一种异常,该下标元素的值则是该 ESR 的入口地址。
向量表在地址空间 中的位置是可以设置的,通过 NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后,该寄 存器的值为 0 。因此,在地址 0 处必须包含一张向量表,用于初始时的异常分配。
比如,如果发生了异常 11(SVC),则 NVIC 会计算出偏移移量是 11x4=0x2C,然后从那里
取出服务例程的入口地址并跳入。
栈内存操作
堆栈操作就是对内存的读写操作,但是访问地址由 SP 给出。寄存器的数据通过 PUSH
操作存入堆栈,以后用 POP 操作从堆栈中取回。
PUSH/POP 指令支持一次操作多个寄存器。
在寄存器列表中,不管寄存器的序号是以什么顺序给出的,汇编器都将把它们升序排序。
先 push 序号大的寄存器,所以也就先 pop 序号小的寄存器。
Cortex-M3 使用的是"向下生长的满栈"模型。堆栈指针 SP 指向最后一个被压入堆栈的 32 位数值。在下一次压栈时,SP 先自减 4 ,再存入新的数值。
堆栈的PUSH和POP实现过程,
双堆栈机制
当 CONTROL[1]=0 时,只使用 MSP,此时用户程序和异常 handler 共享同一个堆栈。
当 CONTROL[1]=1 时,线程模式将不再使用 MSP,而改用 PSP(handler 模式永远使用 MSP)。
复位序列
在离开复位状态后, CM3 做的第一件事就是读取下列两个 32 位整数的值:
- 从地址 0x0000,0000 处取出 MSP 的初始值。
- 从地址 0x0000,0004 处取出 PC 的初始值------这个值是复位向量,LSB 必须是 1。然后从这 个值所对应的地址处取指
由于CM3使用的是向下生长的满栈,MSP初始化时指向的是栈顶,也就是堆栈内存的末地址加1 。
向量表跟随在 MSP 的初始值之后------也就是第 2 个表目。