LV16-10-存储器系统-01-CortexM3
本文主要是Cortex-M3存储器系统的一些的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
- 通用
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.st.com/content/st_com/zh.html | ST官方网站,在这里我们可以找到STM32的相关文档 | |
https://www.stmcu.com.cn/ | 意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档 | |
http://elm-chan.org/fsw/ff/00index_e.html | FatFs文件系统官网 | |
教程书籍 | 《ARM Cortex-M3权威指南》 | ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩 |
《ARM Cortex-M0权威指南》 | ||
《ARM Cortex-M3与Cortex-M4权威指南》 | ||
开发论坛 | http://47.111.11.73/forum.php | 开源电子网,正点原子的资料下载及问题讨论论坛 |
https://www.firebbs.cn/forum.php | 国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT | |
https://www.amobbs.com/index.php | 阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。 | |
http://download.100ask.net/index.html | 韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。 | |
博客参考 | http://www.openedv.com/ | 开源网-原子哥个人博客 |
http://blog.chinaaet.com/jihceng0622 | 博主是原Freescale现NXP的现场应用工程师 | |
cortex-m-resources | 这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接) |
- STM32
STM32 | STM32 HAL库开发实战指南——基于F103系列开发板 | 野火STM32开发教程在线文档 |
STM32库开发实战指南——基于野火霸道开发板 | 野火STM32开发教程在线文档 |
- SD卡
SD Association | 提供了SD存储卡和SDIO卡系统规范 |
点击查看相关文件下载
STM32F103xx英文数据手册 | STM32F103xC/D/E系列的英文数据手册 |
STM32F103xx中文数据手册 | STM32F103xC/D/E系列的中文数据手册 |
STM32F10xxx英文参考手册(RM0008) | STM32F10xxx系列的英文参考手册 |
STM32F10xxx中文参考手册(RM0008) | STM32F10xxx系列的中文参考手册 |
Arm Cortex-M3 处理器技术参考手册-英文版 | Cortex-M3技术参考手册-英文版 |
STM32F10xxx Cortex-M3编程手册-英文版(PM0056) | STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版 |
SD卡相关资料——最新版本 | 有关SD卡的一些资料可以从这里下载 |
SD卡相关资料——历史版本 | 有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议 |
SD 2.0 协议标准完整版 | 这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看 |
本篇笔记主要来自于《Cortex-M3权威指南》的第五章存储器系统。其实有一部分概念在后边一篇笔记中才有所体现,比如什么是寄存器?。
一、存储器映射
CM3 只有一个单一固定的存储器映射。这一点极大地方便了软件在各种 CM3 单片机间的移植。举个简单的例子,各款 CM3 单片机的 NVIC 和 MPU 都在相同的位置布设寄存器,使得它们变得通用。尽管如此, CM3 定出的条条框框是粗线条的,它依然允许芯片制造商灵活地分配存储器空间,以制造出各具特色的单片机产品。存储空间的一些位置用于调试组件等私有外设,这个地址段被称为“ 私有外设区”。私有外设区的组件包括:
(1)闪存地址重载及断点单元(FPB)
(2)数据观察点单元(DWT)
(3)指令跟踪宏单元(ITM)
(4)嵌入式跟踪宏单元(ETM)
(5)跟踪端口接口单元(TPIU)
(6)ROM 表
1. 预定义的存储器映射
Cortex-M3预定义的存储器映射如下:
这个存储器映射只是个粗线条的模板,半导体厂家会提供更展开的图示,来表明芯片中片上外设的具体分布, RAM 与 ROM 的容量和位置信息。
2. 代码区域512M
CM3 的地址空间是 4GB, 程序可以在代码区,内部 SRAM 区以及外部 RAM 区中执行。但是因为指令总线与数据总线是分开的, 最理想的是把程序放到代码区, 从而使取指和数据访问各自使用自己的总线,并行不悖。
3. 内部SRAM区域512M
内部 SRAM 区的大小是 512MB,用于让芯片制造商连接片上的 SRAM,这个区通过系统总线来访问。在这个区的下部,有一个 1MB 的位带区:
该位带区还有一个对应的 32MB 的“位带别名(alias)区”,容纳了 8M 个“位变量”(对比 8051 的只有 128 个位)。位带区对应的是最低的 1MB 地址范围,而位带别名区里面的每个字对应位带区的一个比特。位带操作只适用于数据访问,不适用于取指。通过位带的功能,可以把多个布尔型数据打包在单一的字中,却依然可以从位带别名区中,像访问普通内存一样地使用它们。位带别名区中的访问操作是原子的,消灭了传统的“读-改-写”三步曲。位带操作的细节后边再说。
4. 片上外设区域 512M
地址空间的另一个 512MB 范围由片上外设(的寄存器)使用。这个区中也有一条 32MB的位带别名,以便于快捷地访问外设寄存器。例如,可以方便地访问各种控制位和状态位。要注意的是,外设内不允许执行指令。
5. 两个1GB
这两个 1GB 的范围,分别用于连接外部 RAM 和外部设备,它们之中没有位带。两者的区别在于外部 RAM 区允许执行指令,而外部设备区则不允许。
6. 最后的512M
最后还剩下 0.5GB 的隐秘地带, CM3 内核的闺房就在这里面,包括了系统级组件,内部私有外设总线 s,外部私有外设总线 s,以及由提供者定义的系统外设。
私有外设总线有两条:
AHB 私有外设总线,只用于 CM3 内部的 AHB 外设,它们是: NVIC, FPB, DWT 和 ITM。
APB 私有外设总线,既用于 CM3 内部的 APB 设备,也用于外部设备(这里的“外部”是对内核而言)。 CM3 允许器件制造商再添加一些片上 APB 外设到 APB 私有总线上,它们通过 ABP 接口来访问。
NVIC 所处的区域叫做“系统控制空间( SCS)”,在 SCS 里的还有 SysTick、 MPU 以及代码调试控制所用的寄存器:
最后,未用的提供商指定区也通过系统总线来访问,但是不允许在其中执行指令。CM3 中的 MPU 是选配的,由芯片制造商决定是否配上。
二、存储器访问属性
CM3 在定义了存储器映射之外,还为存储器的访问规定了 4 种属性,分别是:
(1)可否缓冲(Bufferable)
(2)可否缓存(Cacheable)
(3)可否执行(Executable)
(4)可否共享(Sharable)
如果配了 MPU,则可以通过它配置不同的存储区,并且覆盖缺省的访问属性。 CM3 片内没有配备缓存,也没有缓存控制器,但是允许在外部添加缓存。通常,如果提供了外部内存,芯片制造商还要附加一个内存控制器,它可以根据可否缓存的设置,来管理对片内和片外 RAM 的访问操作。
地址空间可以通过另一种方式分为 8 个 512MB 等份:
(1)代码区( 0x0000_0000‐ 0x1FFF_FFFF)。该区是可以执行指令的,缓存属性为 WT(“写通”,Write Through),即不可以缓存。此区亦可写数据。在此区上的数据操作是通过数据总线接口的(读数据使用 D‐Code,写数据使用 System),且在此区上的写操作是缓冲的。
(2)SRAM 区( 0x2000_0000 – 0x3FFF_FFFF)。此区用于片内 SRAM,写操作是缓冲的,并且可以选择 WB‐WA(Write Back, Write Allocated)缓存属性。此区亦可以执行指令,以允许把代码拷贝到内存中执行——常用于固件升级等维护工作。
(3)片上外设区(0x4000_0000 – 0x5FFF_FFFF)。该区用于片上外设,因此是不可缓存的,也不可以在此区执行指令(这也称为 eXecute Never, XN。 ARM 的参考手册大量使用此术语)。
(4)外部 RAM 区的前半段( 0x6000_0000 ‐ 0x7FFF_FFFF)。该区用于片外 RAM,可缓存(缓存属性为 WB‐WA),并且可以执行指令。
(5)外部RAM区的后半段(0x8000_0000 - 0x9FFF_FFFF)。除了不可缓存(WT)外,同前半段。
(6)外部外设区的前半段(0xA000_0000 - 0xBFFF_FFFF)。用于片外外设的寄存器,也用于多核系统中的共享内存(需要严格按顺序操作,即不可缓冲)。该区也是个不可执行区。
(7)外部外设区的后半段(0xC000_0000 - 0xDFFF_FFFF)。目前与前半段的功能完全一致。
(8)系统区(0xE000_0000 - 0xFFFF_FFFF)。此区是私有外设和供应商指定功能区。此区不可执行代码。系统区涉及到很多关键部位,因此访问都是严格序列化的(不可缓存,不可缓冲)。而供应商指定功能区则是可以缓存和缓冲的。
写通,写回,与写时申请:
写回(Write Back):写入的数据先逗留在缓存中,待到必要时再落实到最终目的地,这也是cache 的最基本职能,用于改善数据传送的效率。
写通(Write Through):写操作“穿透”中途的缓存,直接落入最终的目的地中。可见,写通操作架空了cache,但它使写操作的结果立即生效。这常用于和片上外设或其它处理器共享的内存中,如显卡的显存,片上外设寄存器,以及双核系统中的共享内存。写通操作和C中的“volatile””有密切的联系。
写时申请(Write Allocate):译者也不太清楚啦~
三、存储器的缺省访问许可
CM3有一个缺省的存储访问许可,它能防止使用户代码访问系统控制存储空间,保护NVIC、MPU等关键部件。缺省访问许可在下列条件时生效:
(1)没有配备MPU
(2)配备了MPU,但是MPU被除能
如果启用了MPU,则 MPU可以在地址空间中划出若干个regions,并为不同的 region规定不同的访问许可权限。缺省的存储器访问许可权限如下表:
当一个用户级访问被阻止时,会立即产生一个总线fault。
四、位带操作
1. 位带区与位带别名区关系
支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM3中,有两个区中实现了位带,其中一个是 SRAM 区的最低 1MB 范围 第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当通过位带别名区访问这些字时,就可以达到访问原始比特的目的 。
- 位带区与位带别名区的膨胀关系图
- 下图从另一个侧面演示比特的膨胀对应关系
2. 位带操作举例
2.1 位带写操作
举例:我们要是想要设置地址 0x2000_0000 中的比特 2,则使用位带操作的设置过程如下图所示:
对应的汇编如下:
2.2 位带读操作
位带读操作相对简单些
对应的汇编为:
3. 基本原理
位带操作的概念其实多年前就有了, 那还是8051单片机开创的先河。CM3 使用如下术语来表示位带存储的相关地址 :
- 位带区: 支持位带操作的地址区
- 位带别名: 对别名地址的访问最终作用到位带区的访问上(注意:这中间有一个地址映射过程)
在位带区中,每个比特都映射到别名地址区的一个字——这是只有LSB有效的字。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到LSB,并把 LSB返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读一改一写”过程。支持位带操作的两个内存区的范围是:
- 0x2000_0000‐0x200F_FFFF( SRAM 区中的最低 1MB)
对 SRAM 位带区的某个比特,记它所在字节地址为 A,位序号为n(0≤ n ≤ 7)则该比特位在别名区的地址为:
1 | // “*4”表示一个字为 4 个字节,“*8”表示一个字节中有 8 个比特。 |
- 0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB)
对 片上外设区的某个比特,记它所在字节地址为 A,位序号为n(0≤ n ≤ 7)则该比特位在别名区的地址为:
1 | // “*4”表示一个字为 4 个字节,“*8”表示一个字节中有 8 个比特。 |
4. 位带别名重映射
4.1 SRAM区
位带区 | 等效别名地址 |
---|---|
0x2000000.0 | 0x2200000.0 |
0x2000000.1 | 0x2200004.0 |
0x2000000.2 | 0x2200008.0 |
…… | …… |
0x2000000.31 | 0x220007C.0 |
0x2000004.0 | 0x2200080.0 |
0x2000004.1 | 0x2200084.0 |
0x2000004.2 | 0x2200088.0 |
…… | …… |
0x200FFFFC.31 | 0x23FFFFFC.0 |
4.2 片上外设区
位带区 | 等效别名地址 |
---|---|
0x4000000.0 | 0x4200000.0 |
0x4000000.1 | 0x4200004.0 |
0x4000000.2 | 0x4200008.0 |
…… | …… |
0x4000000.31 | 0x420007C.0 |
0x4000004.0 | 0x4200080.0 |
0x4000004.1 | 0x4200084.0 |
0x4000004.2 | 0x4200088.0 |
…… | …… |
0x400FFFFC.31 | 0x43FFFFFC.0 |
4.3 一个实例
(1)在地址0x20000000处写入0x3355AACC
(2)读取地址0x22000008。本次读访问将读取0x20000000,并提取比特2,值为1。
(3)往地址0x22000008处写0。本次操作将被映射成对地址0x20000000的“读一改一写”操作(原子的),把比特⒉清 0。
(4)现在再读取0x20000000,将返回0x3355AAC8 ( bit[2]已清零)。
位带别名区的字只有LSB有意义。另外,在访问位带别名区时,不管使用哪一种长度的数据传送指令(字/半字/字节),都把地址对齐到字的边界上,否则会产生不可预料的结果。
5. 位带操作的好处
位带操作有什么优越性呢?最容易想到的就是通过GPIO的管脚来单独控制每盏LED的点亮与熄灭。另一方面,也对操作串行接口器件提供了很大的方便(典型如74HC165,CD4094)。总之位带操作对于硬件I/O密集型的底层程序最有用处了。
CM3中还有一个称为“bit-bang”的概念,它通常是通过“bit-band”实现的,但是它俩在学术上是两个不同的概念。位带操作还能用来化简跳转的判断。当跳转依据是某个位时,以前必须这样做:(1)读取整个寄存器(2)掩蔽不需要的位(3)比较并跳转。现在只需:(1)从位带别名区读取状态位(2)比较并跳转。使代码更简洁 。
这只是位带操作优越性的初等体现,位带操作还有一个重要的好处是在多任务中,用于实现共享资源在任务间的“互锁”访问。多任务的共享资源必须满足一次只有一个任务访问它——亦即所谓的“原子操作”。以前的读一改一写需要3条指令,导致这中间留有两个能被中断的空当。于是可能会出现如下图所示的紊乱危象:
同样的紊乱危象可以出现在多任务的执行环境中。其实,上图所演示的情况可以看作是多任务的一个特例:主程序是一个任务, ISR 是另一个任务,这两个任务并发执行。
通过使用 CM3 的位带操作,就可以消灭上例中的紊乱危象。 CM3 把这个“读-改-写”做成一个硬件级别支持的原子操作,不能被中断,如下图:
6. 在C语言中使用位带
不幸的是,在 C 编译器中并没有直接支持位带操作。比如, C 编译器并不知道同一块内存能够使用不同的地址来访问,也不知道对位带别名区的访问只对 LSB 有效。欲在 C 中使用位带操作,最简单的做法就是#define 一个位带别名区的地址。例如:
1 |
|
为简化位带操作,也可以定义一些宏。比如,我们可以建立一个把”位带地址+位序号“转换成别名地址的宏,再建立一个把别名地址转换成指针类型的宏:
1 | //把“位带地址+位序号”转换成别名地址的宏 |
在此基础上,我们就可以如下改写代码:
1 | MEM_ADDR(DEVICE_REG0) = 0xAB; //使用正常地址访问寄存器 |
注意:当使用位带功能时,要访问的变量必须用 volatile 来定义。因为 C 编译器并不知道同一个比特可以有两个地址。所以就要通过volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的考虑,在中途使用寄存器来操作数据的复本,直到最后才把复本写回(这和 cache的原理是一样的)。