Cortex-M3权威指南学习笔记

Cortex-M3 概述

单片机和内核关系

Cortex‐M3处理器内核是单片机的中央处理单元(CPU)。完整的基于Cortext-M3的MCU还需要很多其它组件。在芯片制造商得到Cortext-M3处理器内核的使用授权后,它们就可以把Cortext-M3内核用在自己的硅片设计中,添加存储器,外设,I/O以及其它功能块。不同厂家设计出的单片机会有不同的配置,包括存储器容量、类型、外设等都各具特色。

Cortex-M3 内核和芯片(单片机)的关系示意图 Cortex-M3 内核和芯片(单片机)的关系示意图

Cortex-M3 内核

Cortex‐M3 是一个 32 位处理器内核。内部的数据路径是 32 位的,寄存器是 32 位的,存储器接口也是 32 位的。

Cortext-M3 采用了哈佛结构,拥有独立的指令总线和数据总线,可以让取指与数据访问并行不悖。这样一来数据访问不再占用指令总线,从而提升了性能。为实现这个特性, Cortext-M3 内部含有好几条总线接口,每条都为自己的应用场合优化过,并且它们可以并行工作。但是另一方面,指令总线和数据总线共享同一个存储器空间(一个统一的存储器系统)。换句话说,不是因为有两条总线,可寻址空间就变成 8GB 了。

比较复杂的应用可能需要更多的存储系统功能,为此 Cortext-M3 提供一个可选的 MPU。

Cortex‐M3 的一个简化视图 Cortex‐M3 的一个简化视图

这个图都是英文,因此我翻译一下,让大家比较直观一点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#中断相关:
Interrupts : 中断
Interrupt Controller (NVIC)  : 嵌套矢量中断控制器

#CPU相关:
Memory Interface : 内存接口
Instruction Fetch Unit : 指令获取单元
Decoder : 指令解码器
Register Bank : 寄存器组
ALU : 算术逻辑单元

#调试相关:
Debug System : 调试系统
Trace Interface : 跟踪调试接口
Debug Interface : 调试接口

#总线相关:
Memory Protection Unit : 内存保护单元
Instruction Bus : 指令总线
Data Bus :  数据总线
Bus Interconnect : 总线互联

#总线外部接口相关: 
Code Memory : 代码空间
Memory System and Peripherals : 存储系统和外设
Private Peripherals : 私有外围设备

寄存器

寄存器(Register)是中央处理器内用来暂存指令、数据和地址的电脑存储器。寄存器的存贮容量有限,读写速度非常快。

Cortex‐M3 处理器拥有 R0‐R15 的寄存器组。(注意 Cortex-M3 的寄存器是32位的)。

其中 R13 作为堆栈指针 SP。SP 有两个,但在同一时刻只能有一个可以看到,这也就是所谓的 “banked” 寄存器。

Cortex-M3 寄存器组示意图 Cortex-M3 寄存器组示意图

通用寄存器

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

堆栈指针寄存器

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

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

连接寄存器

当呼叫一个子程序时,由 R14 存储返回地址。

程序计数寄存器

指向当前的程序地址。如果修改它的值,就能改变程序的执行流。

特殊功能寄存器

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

  • 程序状态字寄存器组(PSRs)
  • 中断屏蔽寄存器组(PRIMASK, FAULTMASK, BASEPRI)
  • 控制寄存器(CONTROL)

Cortex-M3 的特殊功能寄存器 Cortex-M3 的特殊功能寄存器

寄存器功能
xPSR记录 ALU 标志(0 标志,进位标志,负数标志,溢出标志),执行状态,以及当前正服务的中断号
PRIMASK除能所有的中断——当然了,不可屏蔽中断(NMI)才不甩它呢。
FAULTMASK除能所有的 fault——NMI 依然不受影响,而且被除能的 faults 会“上访”
BASEPRI除能所有优先级不高于某个具体数值的中断。
CONTROL定义特权状态,并且决定使用哪一个堆栈指针

操作模式

操作系统的内核通常都在特权级下执行,所有没有被 MPU 禁掉的存储器都可以访问。在操作系统开启了一个用户程序后,通常都会让它在用户级下执行,从而使系统不会因某个程序的崩溃或恶意破坏而受损。

存储器系统

Cortex‐M3 只有一个单一固定的存储器映射。这一点极大地方便了软件在各种 Cortex‐M3 单片机间的移植。举个简单的例子,各款 Cortex‐M3 单片机的 NVIC 和 MPU 都在相同的位置布设寄存器,使得它们变得通用。尽管如此,Cortex‐M3 定出的条条框框是粗线条的,它依然允许芯片制造商灵活地分配存储器空间,以制造出各具特色的单片机产品。

存储空间的一些位置用于调试组件等私有外设,这个地址段被称为 私有外设区。私有外设区的组件包括:

  • 闪存地址重载及断点单元(FPB)
  • 数据观察点单元(DWT)
  • 指令跟踪宏单元(ITM)
  • 嵌入式跟踪宏单元(ETM)
  • 跟踪端口接口单元(TPIU)
  • ROM 表

存储器映射

Cortext-M3 预定义的存储器映射 Cortext-M3 预定义的存储器映射

内部 SRAM 区的大小是 512MB,用于让芯片制造商连接片上的 SRAM,这个区通过系统总线来访问。在这个区的下部,有一个 1MB 的位带区,该位带区还有一个对应的 32MB 的“位带别名(alias)区”,容纳了 8M 个“位变量”(对比 8051 的只有 128 个位)。位带区对应的是最低的 1MB 地址范围,而位带别名区里面的每个字对应位带区的一个比特。位带操作只适用于数据访问,不适用于取指。通过位带的功能,可以把多个布尔型数据打包在单一的字中,却依然可以从位带别名区中,像访问普通内存一样地使用它们。位带别名区中的访问操作是原子的,消灭了传统的“读-改-写”三步曲。位带操作的细节待会还要讲到。地址空间的另一个 512MB 范围由片上外设(的寄存器)使用。这个区中也有一条 32MB的位带别名,以便于快捷地访问外设寄存器。例如,可以方便地访问各种控制位和状态位。要注意的是,外设内不允许执行指令。还有两个 1GB 的范围,分别用于连接外部 RAM 和外部设备,它们之中没有位带。两者的区别在于外部 RAM 区允许执行指令,而外部设备区则不允许。

最后还剩下 0.5GB 的隐秘地带,Cortext-M3 内核的闺房就在这里面,包括了系统级组件,内部私有外设总线 s,外部私有外设总线 s,以及由提供者定义的系统外设。

私有外设总线有两条:

  • AHB 私有外设总线,只用于 Cortext-M3 内部的 AHB 外设,它们是:NVIC, FPB, DWT 和 ITM。
  • APB 私有外设总线,既用于 Cortext-M3 内部的 APB 设备,也用于外部设备(这里的“外部”是对内核而言)。Cortext-M3 允许器件制造商再添加一些片上 APB 外设到 APB 私有总线上,它们通过 ABP 接口来访问。

NVIC 所处的区域叫做“系统控制空间(SCS)”,在 SCS 里的还有 SysTick、MPU 以及代码调试控制所用的寄存器。

最后,未用的提供商指定区也通过系统总线来访问,但是不允许在其中执行指令。Cortext-M3 中的 MPU 是选配的,由芯片制造商决定是否配上。上述的存储器映射只是个粗线条的模板,半导体厂家会提供更展开的图示,来表明芯片中片上外设的具体分布,RAM 与 ROM 的容量和位置信息。

存储器访问属性

Cortext-M3 在定义了存储器映射之外,还为存储器的访问规定了 4 种属性,分别是:

  • 可否缓冲(Bufferable)
  • 可否缓存(Cacheable)
  • 可否执行(Executable)
  • 可否共享(Sharable)

如果配了 MPU,则可以通过它配置不同的存储区,并且覆盖缺省的访问属性。Cortext-M3 片内没有配备缓存,也没有缓存控制器,但是允许在外部添加缓存。通常,如果提供了外部内存,芯片制造商还要附加一个内存控制器,它可以根据可否缓存的设置,来管理对片内和片外 RAM 的访问操作。

Cortext-M3 有一个缺省的存储访问许可,它能防止使用户代码访问系统控制存储空间,保护 NVIC、MPU 等关键部件。缺省访问许可在下列条件时生效:

  • 没有配备 MPU.
  • 配备了 MPU, 但是 MPU 被除能。
存储器区域地址范围用户级许可权限
代码区0000_0000 – 1FFF_FFFF无限制
片内 SRAM2000_0000 – 3FFF_FFFF无限制
片上外设4000_0000 – 5FFF_FFFF无限制
外部 RAM6000_0000 – 9FFF_FFFF无限制
外部外设A000_0000 – DFFF_FFFF无限制
ITME000_0000 – E000_0FFF可以读。对于写操作,除了用户级下允许时的 stimulus 端口外,全部忽略
DWTE000_1000 – E000_1FFF阻止访问,访问会引发一个总线 fault
FPBE000_2000 – E000_3FFF阻止访问,访问会引发一个总线 fault
NVICE000_E000 – E000_EFFF阻止访问,访问会引发一个总线 fault。但有个例外:软件触发中断寄存器可以被编程为允许用户级访问。
内部 PPBE000_F000 – E003_FFFF阻止访问,访问会引发一个总线 fault
TPIUE004_0000 – E004_0FFF阻止访问,访问会引发一个总线 fault
ETME004_1000 – E004_1FFF阻止访问,访问会引发一个总线 fault
外部 PPBE004_2000 – E004_2FFF阻止访问,访问会引发一个总线 fault
ROM 表E00F_F000 – E00F_FFFF阻止访问,访问会引发一个总线 fault
供应商指定E010_0000 – FFFF_FFFF无限制

系统方框图

Cortext-M3 里面除了处理核心外,还有了好多其它组件,以用于系统管理和调试支持。

Cortext-M3 处理器系统方框图 Cortext-M3 处理器系统方框图

请注意:虚线框住的 MPU 和 ETM 是可选组件,不一定会包含在每一个 Cortext-M3 的 MCU 中。

缩写含义
NVIC嵌套向量中断控制器
SYSTICK Timer一个简易的周期定时器,用于提供时基,多为操作系统所使用
MPU存储器保护单元(可选)
Cortext-M3BusMatrix内部的 AHB 互连
AHB to APB把 AHB 转换为 APB 的总线桥
SW‐DP/SWJ‐DP串行线/串行线 JTAG 调试端口(DP)。通过串行线调试协议或者是传统的 JTAG 协议(专用于 SWJ‐DP),都可以用于实现与调试接口的连接
AHB‐APAHB 访问端口,它把串行线/SWJ 接口的命令转换成 AHB 数据传送
ETM嵌入式跟踪宏单元(可选组件),调试用。 用于处理指令跟踪
DWT数据观察点及跟踪单元,调试用。这是一个处理数据观察点功能的模块
ITM指令跟踪宏单元
TPIU跟踪单元的接口单元。所有跟踪单元发出的调试信息都要先送给它,它再转发给外部跟踪捕获硬件的。
FPBFlash 地址重载及断点单元
ROM 表一个小的查找表,其中存储了配置信息

可见,Cortex‐M3 处理器是以一个“处理器子系统”呈现的,其 CPU 内核本身与 NVIC 和一系列调试块都亲密耦合:

Cortext-M3Core: Cortex‐M3 处理器的中央处理核心。

嵌套向量中断控制器 NVIC: NVIC 是一个在 Cortext-M3 中内建的中断控制器。中断的具体路数由芯片厂商定义。NVIC 是与 CPU 紧耦合的,它还包含了若干个系统控制寄存器。因为 NVIC 支持中断嵌套,使得在 Cortext-M3 上处理嵌套中断时清爽而强大。它还采用了向量中断的机制。在中断发生时,它会自动取出对应的服务例程入口地址,并且直接调用,无需软件判定中断源,为缩短中断延时做出了非常重要的贡献。

SysTick 定时器: 系统滴答定时器是一个非常基本的倒计时定时器,用于在每隔一定的时间产生一个中断,即使是系统在睡眠模式下也能工作。它使得 OS 在各 Cortext-M3 器件之间的移植中不必修改系统定时器的代码,移植工作一下子容易多了。SysTick 定时器也是作为 NVIC 的一部分实现的。

存储器保护单元: MPU 是一个选配的单元,有些 Cortext-M3 芯片可能没有配备此组件。如果有,则它可以把存储器分成一些 regions,并分别予以保护。例如,它可以让某些 regions 在用户级下变成只读,从而阻止了一些用户程序破坏关键数据。

BusMatrix: BusMatrix 是 Cortext-M3 内部总线系统的核心。它是一个 AHB 互连的网络,通过它可以让数据在不同的总线之间并行传送——只要两个总线主机不试图访问同一块内存区域。BusMatrix 还提供了附加的数据传送管理设施,包括一个写缓冲以及一个按位操作的逻辑( 位带(bit‐band) )

AHB to APB: 它是一个总线桥,用于把若干个 APB 设备连接到 Cortext-M3 处理器的私有外设总线上(内部的和外部的)。这些 APB 设备常见于调试组件。Cortext-M3 还允许芯片厂商把附加的 APB 设备挂在这条 APB 总线上,并通过 APB 接入其外部私有外设总线。

典型总线连接

Cortext-M3中有若干个总线接口,初学者很容易混淆,也不太容易弄清楚它们是怎样与其它设备和存储器连接的。这里给出一个典型的连接实例:

Cortex‐M3 总线连接范例 Cortex‐M3 总线连接范例

异常/中断

Cortex‐M3 在内核水平上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。其中,编号为 1-15 的对应系统异常,大于等于 16 的则全是外部中断。除了个别异常的优先级被定死外,其它异常的优先级都是可编程的(所有能打断正常执行流的事件都称为异常)。

系统异常清单:

编号类型优先级简介
0N/AN/A没有异常在运行
1复位-3(最高)复位
2NMI-2不可屏蔽中断(来自外部 NMI 输入脚)
3硬(hard)fault-1所有被除能的 fault,都将“上访”(escalation)成硬 fault。
只要FAULTMASK 没有置位,硬 fault 服务例程就被强制执行。
Fault被除能的原因包括被禁用,或者 FAULTMASK 被置位。
4MemManage fault可编程存储器管理 fault,MPU 访问犯规以及访问非法位置均可引发。
企图在“非执行区”取指也会引发此 fault
5总线 fault可编程从总线系统收到了错误响应,原因可以是预取流产(Abort)或数据流产,
或者企图访问协处理器
6用法(usage)Fault可编程由于程序错误导致的异常。通常是使用了一条无效指令,或者是非法
的状态转换,例如尝试切换到 ARM 状态
7-10保留N/AN/A
11SVCall可编程执行系统服务调用指令(SVC)引发的异常
12调试监视器可编程调试监视器(断点,数据观察点,或者是外部调试请求
13保留N/AN/A
14PendSV可编程为系统设备而设的“可悬挂请求”(pendable request)
15SysTick可编程系统滴答定时器(也就是周期性溢出的时基定时器——译注)
16IRQ #0可编程外中断#0
17IRQ #1可编程外中断#1
255IRQ #239可编程外中断#239

SysTick 定时器

SysTick 定时器被捆绑在 NVIC 中,用于产生 SYSTICK 异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如, 为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时 器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

Cortex‐M3 处理器内部包含了一个简单的定时器。因为所有的 Cortext-M3 芯片都带有这个定时器,软件在不同 Cortext-M3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,Cortext-M3上的自由运行时钟),或者是外部时钟( Cortext-M3 处理器上的 STCLK 信号)。不过,STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。

存储保护单元 MPU

在 Cortex‐M3 处理器中可以选配一个存储器保护单元(MPU),它可以实施对存储器(主要是内存和外设寄存器)的保护,以使软件更加健壮和可靠。在使用前,必须根据需要对其编程。如果没有启用MPU,则等同于系统中没有配 MPU。MPU 有如下的能力可以提高系统的可靠性:

  • 阻止用户应用程序破坏操作系统使用的数据
  • 阻止一个任务访问其它任务的数据区,从而把任务隔开。
  • 可以把关键数据区设置为只读,从根本上消除了被破坏的可能。
  • 检测意外的存储访问,如,堆栈溢出,数组越界。
  • 此外,还可以通过MPU设置存储器regions的其它访问属性,比如,是否缓区,是否缓冲等。

MPU在执行其功能时,是以所谓的 “region” 为单位的。一个 region 其实就是一段连续的地址,只是它们的位置和范围都要满足一些限制(对齐方式,最小容量等)。CM3 的 MPU 共支持 8 个 regions。每个 region 可以进一步划分成更小的 “子region”。还允许启用一个 “背景region”(即没有MPU时的全部地址空间),不过它是只能由特权级享用。在启用 MPU 后,就不得再访问定义之外的地址区间,也不得访问未经授权的 region。否则,将以“访问违例”处理,触发 MemManage fault。

MPU定义的regions可以相互交迭。如果某块内存落在多个region中,则访问属性和权限将由编号最大的region来决定。比如,若1号region与4号region交迭,则交迭的部分受4号region控制。

MPU 的寄存器组

操作 MPU 是通过访问它的若干寄存器来实现的,如下表所示。

名字访问地址初值
MPU类型寄存器 MPUTRRO0xe000,ed90A
MPU控制寄存器 MPUCRRW0xe000,ed940x0000,0000
MPU region号寄存器MPURNRRW0xe000,ed98-
MPU region基址寄存器MPURBARRW0xe000,ed9c-
MPU region属性及容量寄存器(s) MPURASRRW0xed00,eda0-
MPU region基址寄存器的别名1D9C的别名0xed00,eda4-
MPU region属性及容量寄存器的别名1DA0的别名0xed00,eda8-
MPU region基址寄存器的别名2D9C的别名0xed00,edac-
MPU region属性及容量寄存器的别名2DA0的别名0xed00,edb0-
MPU region基址寄存器的别名3D9C的别名0xed00,edb4-
MPU region属性及容量寄存器的别名3DA0的别名0xed00,edb8-

MPU 类型寄存器 MPUTR

位段名称类型复位值描述
23:16IREGIONR0MPU 支持的指令 region 数量。因为 ARMv7‐M
只使用单个统一的 MPU,此位段永远为零
15:8DREGIONR0MPU 支持的数量。若系统中配了 MPU 则为 8,否则为零
0SEPARATER0固定为零

从表中我们可以看出,通过读取DREGION的值,能够判断芯片中是否配了MPU。

MPU 控制寄存器 MPUCR

位段名称类型复位值描述
2PRIVDEFENARW0是否为特权级打开缺省存储器映射(即背景region)。
1=特权级下打开背景 region
0=不打开背景 region。任何访问违例以及对 region
外地址区的访问都将引起 fault
1HFNMIENARW01=在 NMI 和硬 fault 服务例程中不强制除能 MPU
0=在 NMI 和硬 fault 服务例程中强制除能 MPU
0ENABLERW0使能 MPU

通过把PRIVDEFENA置位,可以在没有建立任何region就使能MPU的情况下,依然允许特权级程序访问所有地址,而只有用户级程序被卡死。然而,如果设置了其它的region并且使 能了MPU,则背景region与这些region重合的部分,就要受各region的限制。为了方便理解,让我们作一个对比,看看PRIVDEFENA在置位与清零时,系统对访问的限制有何不同,如图所示。

PRIVDEFENA的影响 PRIVDEFENA的影响