(原创)Cortex-M系列简介

2017/07/16 嵌入式

前提

之前用过cortex系列单片机,时隔多年,居然很多都忘记了,现在又要重新使用,为了避免再次忘记,开始做些笔记。

简介

ARM在1990年成立,当初的名字是“Advanced RISC Machines Ltd.”,是一个处理器设计公司,采用精简指令集,专注于嵌入式芯片解决方案。

该公司只卖处理器核,至于其它外设,完全交给合作伙伴来设计,因此具有很大的扩展功能,它的设计图如下:

img

目前包含4个系列:

  • 款式A:设计用于高性能的“开放应用平台”——越来越接近电脑了
  • 款式R:用于高端的嵌入式系统,尤其是那些带有实时要求的——又要快又要实时。
  • 款式M:用于深度嵌入,更小,更省电。
  • 款式SecurCore:安全加密芯片

这些系列都是采用不同版本的架构,目前已经经过V4,V5,V6,V7,V8几个迭代了。

目前有些架构还带有高级特性,比如Jazelle,MPU,MMU。

  • Jazelle是ARM处理器的硬件Java加速器。

  • MMU,存储器管理单元,用于实现虚拟内存和内存的分区保护,这是应用处理器与嵌入式处 理器的分水岭。电脑和数码产品所使用的处理器几乎清一色地都带MMU。但是MMU也引入了不确定性, 这有时是嵌入式领域——尤其是实时系统不可接受的。然而对于安全关键(safety‐critical)的嵌入式系统, 还是不能没有内存的分区保护的。为解决矛盾,于是就有了MPU。可以把MPU认为是MMU的功能子集,它 只支持分区保护,不支持具有“定位决定性”的虚拟内存机制。

由于历史原因(从ARM7TDMI开始),ARM处理器一直支持两种形式上相对独立的指令 集,它们分别是:

  • 32位的ARM指令集。对应处理器状态:ARM状态
  • 16位的Thumb指令集。对应处理器状态:Thumb状态

img

可见,这两种指令集也对应了两种处理器执行状态。在程序的执行过程中,处理器可以 动态地在两种执行状态之中切换。实际上,Thumb指令集在功能上是ARM指令集的一个子集, 但它能带来更高的代码密度,给目标代码减肥。这对于要勒紧裤腰带的应用还是很经济的。

寄存器

以M3为例,一下是它的寄存器图:

img

R0‐R12 都是32 位通用寄存器,用于数据操作。但是注意:绝大多数16 位Thumb 指令只能访 问R0‐R7,而32 位Thumb‐2 指令可以访问所有寄存器。

Cortex‐M3 拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个。

  • 主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包 括中断服务例程)
  • 进程堆栈指针(PSP):由用户的应用程序代码使用。

堆栈指针的最低两位永远是0,这意味着堆栈总是4 字节对齐的。

在ARM 编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)。除了外部中断外,当有指令执 行了“非法操作”,或者访问被禁的内存区间,因各种错误产生的fault,以及不可屏蔽中断发生时,都会打断程序的 执行,这些情况统称为异常。在不严格的上下文中,异常与中断也可以混用。另外,程序代码也可以主动请求进入 异常状态的(常用于系统调用)。

R14:连接寄存器。当呼叫一个子程序时,由R14 存储返回地址不像大多数其它处理器,ARM 为了减少访问内存的次数(访问内存的操作往往要3 个以上指令周期,带MMU 和cache 的就更加不确定了),把返回地址直接存储在寄存器中。这样足以使很多只有1 级子程序调用的代码无需访 问内存(堆栈内存),从而提高了子程序调用的效率。如果多于1 级,则需要把前一级的R14 值压到堆栈里。在ARM 上编程时,应尽量只使用寄存器保存中间结果,迫不得以时才访问内存。在RISC 处理器中,为了强调访内操作越过 了处理器的界线,并且带来了对性能的不利影响,给它取了一个专业的术语:溅出。

R15:程序计数寄存器。指向当前的程序地址。如果修改它的值,就能改变程序的执行流。

Cortex‐M3 还在内核水平上搭载了若干特殊功能寄存器,例如:

img

Cortex‐M3 处理器支持处理者模式,线程模式两种模式,还支持特权级,用户级两级特权操作。

在CM3 运行主应用程序时(线程模式),既可以使用特权级,也可以使用用户级;但是异常服 务例程必须在特权级下执行。复位后,处理器默认进入线程模式,特权极访问。在特权级下,程序 可以访问所有范围的存储器(如果有MPU,还要在MPU 规定的禁地之外),并且可以执行所有指令。

在特权级下的程序可以为所欲为,但也可能会把自己给玩进去——切换到用户级。一旦进入用 户级,再想回来就得走“法律程序”了——用户级的程序不能简简单单地试图改写CONTROL 寄存器 就回到特权级,它必须先“申诉”:执行一条系统调用指令(SVC)。这会触发SVC 异常,然后由异常 服务例程(通常是操作系统的一部分)接管,如果批准了进入,则异常服务例程修改CONTROL 寄存 器,才能在用户级的线程模式下重新进入特权级。

存储器

总体来说,Cortex‐M3 支持4GB 存储空间。

img

中断

img

0号异常的功能则是个另类,它并不是什么入口地址,而是给出了复位后MSP 的初值。

CM3 的所有中断机制都由NVIC 实现。除了支持240 条中断之外,NVIC 还支持16‐4‐1=11 个内 部异常源,可以实现fault 管理机制。结果,CM3 就有了256 个预定义的异常类型。

Cortex‐M3 在进入异常服务例程时,自动压栈了R0‐R3, R12, LR, PSR 和PC,并且在返回时自 动弹出它们。

复位

在离开复位状态后,CM3 做的第一件事就是读取下列两个32 位整数的值:

  1. 从地址 0x0000,0000 处取出MSP 的初始值。
  2. 从地址 0x0000,0004 处取出PC 的初始值——这个值是复位向量,LSB 必须是1。然 后从这个值所对应的地址处取指。

请注意,这与传统的ARM 架构不同——其实也和绝大多数的其它单片机不同。传统的 ARM 架构总是从0 地址开始执行第一条指令。它们的0 地址处总是一条跳转指令。在CM3 中,0 地址处提供MSP 的初始值,然后就是向量表(向量表在以后还可以被移至其它位置)。 向量表中的数值是32 位的地址,而不是跳转指令。向量表的第一个条目指向复位后应执行 的第一条指令。

因为CM3 使用的是向下生长的满栈,所以MSP 的初始值必须是堆栈内存的末地址加1。 举例来说,如果你的堆栈区域在0x20007C00‐0x20007FFF 之间,那么MSP 的初始值就必须是 0x20008000。堆栈指针SP 指向最后一个被压入堆栈的32 位数值。在下一次压栈时,SP 先自减4,再存入新的数值。


知识共享许可协议
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

站内搜索

    撩我备注-博客

    joinee

    目录结构