存储系统功能
- 它的存储器映射是预定义的,并且还规定好了哪个位置使用哪条总线。
- CM3 的存储器系统支持所谓的“位带”(bit-band)操作。通过它,实现了对单一比特的原子操作。
- CM3 的存储器系统支持非对齐访问和互斥访问。
- CM3 的存储器系统支持 both 小端配置和大端配置。
存储器映射
寄存器映射概念
在嵌入式系统中,外设(如 UART、GPIO、定时器等)通常由硬件寄存器控制。这些寄存器用于配置外设、控制其行为、读取其状态和数据。
寄存器映射指的是将这些外设的控制寄存器通过内存地址空间映射,使得处理器可以通过读写内存地址的方式来访问这些寄存器。
寄存器映射的工作原理就是将每个外设的寄存器分配给一个特定的内存地址范围。
比如说,假设我们有一个 GPIO 外设,这个外设有几个寄存器用于配置其引脚模式、输出状态和输入状态。每个寄存器都会被映射到处理器的内存地址空间中的某个地址范围内,处理器可以通过读取或写入这些内存地址来读取或者控制其行为。
存储器映射总览
CM3 只有一个单一固定的存储器映射。这一点极大地方便了软件在各种 CM3 单片机间的移植。
CM3 的地址空间是 4GB,示意图如下,
下面对各个区进行详细介绍:
代码区:
- 代码区映射的地址是0x0000_0000 到 0x1FFF_FFFF,大小是512MB,通常映射到片内的闪存(Flash)或只读存储器(ROM) 中,用于存储程序代码。
- 代码区与数据区(如 SRAM)不同,代码区通常是只读存储器(ROM 或 Flash),这意味着一旦程序被写入代码区,除非进行固件升级或重写操作,否则代码不会被修改。
- 在 Cortex-M3 系统中,中断向量表 通常位于代码区的起始地址(0x0000 0000)。
- 代码区主要存储程序指令包括:主程序代码,函数和库代码,中断向量表,嵌入式操作系统代码。
- 代码区保存了程序的机器指令。处理器通过程序计数器(PC,R15) 来从代码区加载指令并执行它们。
片上SRAM:
- 片上SRAM映射地址是0x2000_0000 – 0x3FFF_FFFF,大小512MB,通常映射到一个固定的内存地址范围(如上)。
- 片上SRAM通常用于存储运行时数据,例如全局变量、堆栈(进程堆栈(PSP)和异常处理中使用的主堆栈(MSP))、以及动态分配的内存(如malloc或操作系统的内存管理)。
- SRAM 是一种易失性存储器,这意味着一旦系统掉电或重启,存储在 SRAM 中的数据将会丢失。
- 片上SARM区的下部,有一个 1MB 的区间,被称为“位带区”,该位带区还有一个对应的、 32MB 的 “位带别名(alias) 区”,可以容纳了 8M 个“位变量”。(位带区后续介绍)
片上外设区:
- 片上外设区映射地址是0x4000_0000 – 0x5FFF_FFFF,大小512MB,表示将外设的控制寄存器映射到特定的内存地址范围内。
- 处理器通过访问片上外设区中的寄存器来配置和控制外设。每个外设通常会映射一组控制寄存器,这些寄存器具有特定的功能,比如启动、停止、设置参数或读取状态。
- 片上外设区中也有一条 32MB 的位带别名,以便于快捷地访问外设寄存器,用法与内部 SRAM 区中的位带相同。
片外RAM区:
- 片外RAM区映射地址是0x6000_0000 – 0x9FFF_FFFF,大小1GB。
- 外部 RAM 是指通过外部总线连接到处理器的物理 RAM,通常用于补充处理器的内部 RAM。
- CM3最大的外部RAM就是1GB。
片外外设区:
- 片外RAM区映射地址是0xA000_0000 – 0xDFFF_FFFF,大小1GB。
- 对于外部连接的外设,它们的寄存器会被映射到处理器的片外外设区。这个区域用于连接处理器芯片外部的外设,而不是处理器片内集成的外设。
系统区:
- 系统区映射地址是0xE000_0000 – 0xFFFF_FFFF,大小512MB,此区不可执行代码。
- 系统区包括了系统级组件,内部私有外设总线 s,外部私有外设总线 s,以及由提供者定义的系统外设。
备注:Cortex-M3架构采用的是指令总线和数据总线分离的哈佛(Harvard)架构,为了充分利用 Harvard 架构的优势,最理想的方案是将程序(指令)放置在代码区(通常是 Flash 或 ROM),将数据放在 SRAM(内部或外部 RAM) 中。这样可以让取指令和数据访问分别通过指令总线和数据总线进行并行操作,从而最大限度提高系统效率。
存储器默认访问许可
CM3 有一个默认的存储访问许可,它能防止使用户代码访问系统控制存储空间,如下表,
位带操作
在上面的映射示意图我们可以看到, CM3 中,有两个区中实现了位带操作。
其中一个是SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低1MB范围。
位带操作的意义是,可以使用普通的加载/存储指令来对单一的比特进行读写。
每一个位带区都有一个32MB的位带别名区。
位带区和位带别名区对照关系如下图,
其实位带操作很好理解,就是把位带区的每一个字节的每一位都用位带别名区的一个地址表示,然后我们要控制位带区的某一位的时候,就直接操作位带别名区的一个地址就可以了。
由于别名区地址对应的也是一个32位的字节,所以这个32位字节只有最低位(LSB)才有效。
在进行读操作时,处理器实际上会将这个别名地址转换为原始的位带地址,并从位带区中读取一个完整的字,处理器会根据别名地址中的位号,右移该字中的某个位到最低有效位(LSB),将这个LSB 的值返回给你。
以下是书上的一个例子,(建议对照上述的图理解)
以下是位带区到别名区的映射公式,
bit_word_addr = bit_band_base + (byte_offset × 32) + (bit_number × 4)
bit_word_addr
:位带别名区中的某个地址。bit_band_base
:位带别名区的起始地址(SRAM 位带别名区的起始地址是0x2200 0000
,外设位带别名区的起始地址是0x4200 0000
)。byte_offset
:你想要控制的字节相对于位带区起始地址的偏移。bit_number
:你想要控制的字节中的位号(0~7)
互斥访问
互斥访问(Mutual Exclusion Access)是指在多任务、多线程或多处理器系统中,保证对共享资源(如内存、变量、外设等)的访问时,只有一个任务或线程能够在某一时刻访问该资源,而其他任务或线程在此时必须等待。
一个例子如下,
假设有两个任务同时修改一个共享变量 x,并且操作的流程是读取变量 x、对其进行加法操作、然后将结果写回变量 x。如果这两个任务同时运行,竞态条件可能会导致以下情况,
- 任务 1:读取变量
x
的值(例如,读取值为 5)。 - 任务 2:读取变量
x
的值(同样是 5,因为任务 1 还没有完成)。 - 任务 1:将 x 的值加 1,然后写回
x
(值为 6)。 - 任务 2:将
x
的值加 1,然后写回x
(值为 6,而不是期望的 7,因为任务 2 覆盖了任务 1 的结果)。
为了解决这个问题,必须确保对 x
修改时不会被其他任务打断,这就需要互斥访问。
端模式
CM3 支持 both 小端模式和大端模式。
- 小端模式(Little Endian):低位字节存储在内存的低地址, 高位字节存储在高地址。
- 大端模式(Big Endian):高位字节存储在内存的低地址,低位字节存储在高地址。
CM3 处理器主要采用小端模式(Little Endian)作为默认的内存存储方式。在这种模式下,处理器以小端格式处理多字节数据,如 16 位或 32 位的整数。
CM3 处理器也支持大端模式(Big Endian),我们可以通过配置来选择大端模式。
CM3的小端模式和ARM7中定义相同,大端模式不同。
在AHB上的数据如下,
ARM7 的字不变大端,在 AHB 上的数据如下,
Cortex-M3 提供了一个名为系统控制块(System Control Block, SCB)中的AIRCR 寄存器,其中的 Endianess 字段用于配置处理器的端模式。
- SCB_AIRCR 寄存器地址:
0xE000ED0C
- Endianess 位:SCB_AIRCR 寄存器的 15 位控制系统是大端模式还是小端模式。
- 当 bit[15] = 0 时,处理器工作在小端模式(默认模式)。
- 当 bit[15] = 1 时,处理器工作在大端模式。