AHB 先进高性能总线 CPI 每条指令的周期数 ETM 嵌入式跟踪宏单元 MMU 存储器管理单元 NMI 不可屏蔽中断
APB 先进外设总线 IDE 集成开发环境 IRQ 中断请求(通常是指外部中断的请求) LSB 最低有效位 MSB 最高有效位
NVIC 嵌套向量中断控制器
1,前言
Cortex ‐ M3处理器内核是单片机的中央处理单元(CPU )。完整的基于CM3 的MCU还需要多其它组件。在芯片制造商得到CM3 处理器内核的使用授权后,它们就可以把CM3 内核用自己的硅片设计中,添加存储器,外设,I/O 以及其它功能块。
ARM 处理器一直支持两种形式上相对独立的指令集,它们分别是:
1。 32位的ARM 指令集。对应处理器状态:ARM 状态
2。 16位的Thumb 指令集。对应处理器状态:Thumb 状态 实际上,Thumb 指令集在功能上是ARM 指令集的一个子集,
但它能带来更高的代码密度,给目标代码减肥。这对于要勒紧裤腰带的应用还是很经济的。
后来的 基于“cortex M3”内核的处理器 基本采用的新的指令集Thumb‐2(Thumb‐2是16位Thumb 指令集的一个超集)
Cortex ‐ M3勇敢地拒绝了32位ARM 指令集,却把自己的处理能力以身相许般地全托给Thumb ‐ 2 指令集。这可能有些令人意外,但事实上这却见证了Cortex ‐ M3的用情专
一:在内核水平上,就已经为适应单片机和小内存器件而抉择、取舍过了。但她没有嫁错郎, 因为Thumb ‐ 2 完全胜任在这个领域挑大梁。不过,这也意味着Cortex ‐ M3作为新生代处理器,不是向后兼容的。因此,为ARM7写的ARM 汇编语言程序不能直接移植到CM3 上来。不过,CM3 支持绝大多数传统的Thumb 指令,因此用Thumb 指令写的汇编程序就从善如流了
2.Cortex-M3概览
Cort ex‐ M3是一个32位处理器内核,CM3 采用了哈佛结构,拥有独立的指令总线和数据总线,可以让取指与数据访问并行不悖。
Cortex ‐ M3处理器拥有 R0‐R15 的寄存器组。其中 R13 作为堆栈指针 SP 。SP 有两个,但在同一刻只能有一个可以看到,这也就是所谓的“banked ”寄存器。
R0‐ R12 都是32位通用寄存器,用于数据操作。但是注意:绝大多数16位Thumb 指令只能访问R0‐ R7,而 32位Thumb ‐ 2 指令可以访问所有寄存器。
Cortex ‐ M3拥有两个堆栈指针,然而它们是 banked ,因此任一时刻只能使用其中的一个。
1. 主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程)
2. 进程堆栈指针(PSP):由用户的应用程序代码使用。堆栈指针的最低两位永远是0,这意味着堆栈总是4字节对齐的。
在ARM 编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception) 。除了外部中断外,当有指令执行了“非法操作”,或者访问被禁的内存区间,因各种错误产生的fault ,以及不可屏蔽中断发生时,都会打断程序的执行,这些情况统称为异常。在不严格的上下文中,异常与中断也可以混用。另外,程序代码也可以主动请求进入
异常状态的(常用于系统调用)。
Cortex ‐ M3还在内核水平上搭载了若干特殊功能寄存器,包括
程序状态字寄存器组(PSRs )
中断屏蔽寄存器组(PRIMASK, FAULTMASK, BASEPRI)
控制寄存器(CONTROL )
xPSR 记录ALU 标志(0 标志,进位标志,负数标志,溢出标志),执行状态,以及当前正服务的中断号
PRIMASK 除能所有的中断——当然了,不可屏蔽中断(NMI )才不甩它呢。
FAULTMASK 除能所有的fault ——NMI 依然不受影响,而且被除能的 faults 会“上访”,
BASEPRI 除能所有优先级不高于某个具体数值的中断。
CONTROL 定义特权状态(见后续章节对特权的叙述),并且决定使用哪一个堆栈指针
3.堆栈指针
堆栈指针用于访问堆栈,并且PUSH指令和POP 指令默认使用SP指针
在Cortex ‐ M3中,有专门的指令负责堆栈操作——PUSH和POP 。它俩的汇编语言语法
如下例所演示
PUSH {R0} ; *(--R13)=R0 。R13 是long* 的指针 向下生长的满栈
POP {R0} ; R0= *R13++
PUSH 和POP 还
能一次操作多个寄存器,如下所示:
subroutine_1
PUSH {R0-R7, R12, R14} ; 保存寄存器列表
… ; 执行处理
POP {R0-R7, R12, R14} ; 恢复寄存器列表
BX R14 ; 返回到主调函数
MSP 和PSP 都被称为R13/SP 。不过,我们可以通过MRS/MSR指令来指名道姓地访问具体的堆栈指针。
MSP,亦写作 SP_main ,这是复位后缺省使用堆栈指针,服务于操作系统内核和异常服务例程;而PSP,亦写作SP_process ,典型地用于普通的用户线程中。
(连接寄存器R14)LR 用于在调用子程序时存储返回地址
R15 是程序计数器,在汇编代码中你也可以使用名字“PC”来访问它。因为CM3 内部
用了指令流水线,读PC时返回的值是当前指令的地址+4。比如说: 0x1000: MOV R0, PC ; R0 = 0x1004
Cortex ‐ M3中的特殊功能寄存器包括:
z 程序状态寄存器组(PSRs 或曰xPSR )
z 中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及BASEPRI)
z 控制寄存器(CONTROL )
它们只能被专用的MSR 和MRS 指令访问,而且它们也没有存储器地址。
MRS <gp_reg>, <special_reg> ; 读特殊功能寄存器的值到通用寄存器
MSR <special_reg>, <gp_reg> ; 写通用寄存器的值到特殊功能寄存器
只有在特权级下,才允许访问这3 个寄存器。
PRIMASK, FAULTMASK 和 BASEPRI 这三个特殊功能寄存器用于控制异常的使能和除能。
只有在特权级下,才允许访问这3 个寄存器,其实,为了快速地开关中断,CM3还专门设置了一条CPS指令,有4种用法
CPSID I ;PRIMASK=1, ;关中断
CPSIE I ;PRIMASK=0, ;开中断
CPSID F ;FAULTMASK=1, ;关异常
CPSIE F ;FAULTMASK=0 ;开异常
控制寄存器用于定义特权级别,还用于选择当前使用哪个堆栈指针
向量表 s
当一个发生的异常被CM3 内核接受,对应的异常 handler就会执行。为了决定 handler的入口地址,CM3 使用了“向量表查表机制”。这里使用一张向量表。向量表其实是一个WORD32位整数)数组,每个下标对应一种异常,该下标元素的值则是该异常handler的入口地址。向量表的存储位置是可以设置的,通过NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后,该寄存器的值为 0 。因此,在地址 0 处必须包含一张向量表,用于初始时的异常分配
堆栈的基本操作
笼统地讲,堆栈操作就是对内存的读写操作,但是其地址由SP 给出。寄存器的数据通过PUSH 操作存入堆栈,以后用POP 操作从堆栈中取回。在PUSH 与POP 的操作中,SP 的
值会按堆栈的使用法则自动调整,以保证后续的PUSH不会破坏先前 PUSH进去的内容。 堆栈的功能就是把寄存器的数据放入内存,以便将来能恢复之——当一个任务或一段子
程序执行完毕后恢复。正常情况下,PUSH与POP 必须成对使用,而且参与的寄存器,不论是身份还是先后顺序都必须完全一致。当PUSH/POP 指令执行时,SP 指针的值也根着自减/自增。
… (主程序)
; R0=X, R1=Y, R2=Z
BL Fx1
Fx1
PUSH {R0 } ;把R0存入栈 & 调整SP
PUSH {R1} ;把R1存入栈 & 调整SP
PUSH {R2} ;把R2存入栈 & 调整SP
… ;执行Fx1 的功能,中途可以改变R0-R2 的值
POP {R2} ;恢复R2早先的值 & 再次调整SP
POP {R1} ;恢复R1早先的值 & 再次调整SP
POP {R0} ;恢复R0早先的值 & 再次调整SP
BX LR ;返回
;回到主程序
;R0=X, R1=Y, R2=Z (调用Fx1 的前后R0-R2 的值没有被改变)