Arm_Cortex-M3权威指南
这本权威指南只是对应某一种具体的处理器内核深入一种处理器内核对于我们理解整个ARM架构大有帮助书籍资源在下面的链接Arm_Cortex-M3权威指南第2章 Cortex-M3概览简介Cortex-M3是一个32位处理器内核。内部的数据路径是32位寄存器是32位存储器接口也是32位。并且CM3拥有独立的指令总线和数据总线也就是取指与数据访问是独立开来的R0-R12都是32位通用寄存器用于数据操作但是注意绝大多数 16 位 Thumb 指令只能访问 R0‐R7而 32 位 Thumb‐2 指令可以访问所有寄存器R13是两个堆栈指针MSP是主堆栈指针用于操作系统内核以及异常处理例程包括中断服务例程PSP是进程堆栈指针由用户的应用程序代码使用。这里我们要注意这两个堆栈指针任一时刻只能使用其中一个并且堆栈指针的最低两位永远是0这意味着堆栈总是4字节对齐的R14是连接寄存器作用是当呼叫一个子程序时由R14存储返回地址。为什么要这样设计呢因为ARM访问内存的次数往往要3个以上指令周期。把返回地址直接存储在寄存器中这样已经足够很多只有1级子程序调用的代码无需访问内存从而提高了程序调用的效率R15是程序计数寄存器它指向当前的程序地址如果修改它的值就能改变程序的执行流还有一些特殊功能的寄存器操作模式和特权级别Cortex-M3处理器支持两种处理器的操作模式还支持两级特权操作。两种处理器操作模式分为处理者模式和线程模式两种特权级别分别为特权级和用户级在特权级下程序可以访问所有范围的存储器如果有MPU还是不能访问MPU禁止的区域并且可以执行所有指令事实上从用户级到特权级别的唯一途径就是异常如果在重新执行过程中触发了一个异常处理器总是先切换入特权级并且在异常服务例程执行完毕退出时返回先前的状态也可以手工指定返回的状态通过引入特权级和用户级可以提高系统安全性例如在操作系统开启了一个用户程序后通常会让它在用户级下执行从而使系统不会因某个程序的崩溃或恶意破坏而受损内建的嵌套向量中断控制器嵌套向量中断控制器NVIC提供如下的功能可嵌套中断支持。系统的异常可以被赋予不同的优先级。当前优先级被存储在xPSR的专用字段中。当一个异常发生时硬件会自动比较该异常的优先级是否比当前的异常优先级更高如果高的话立刻抢占向量中断支持。当开始响应一个中断后CM3会自动定位一张向量表并且根据中断号从表中找出ISR的入口地址然后跳过去执行动态优先级调整支持。软件可以在运行时期更改中断的优先级如果在某 ISR 中修改了自己所对应中断的优先级而且这个中断又有新的实例处于悬起中pending也不会自己打断自己从而没有重入(reentry)。因为如果能打断自己的话可能会有一种极端情况让栈爆掉如果在ISR中提高了A中断的优先级然后其它任务触发了A中断那么这时A中断会被打断执行一次更高优先级的A中断然后中断里再改优先级改的更高如果又有任务触发了这个A中断那么又会抢占这样下去栈里全是A中断的现场直接爆了所以我们不允许自己打断自己从而没有重入中断延迟大大缩短。因为Cortex-M3为了缩短中断延迟引入了好几个新特性这个后续再讲中断可屏蔽。既可以屏蔽优先级低于某个阈值的中断/异常也可以全体封杀。这是为了让时间关键的任务能在死线到来前完成而不被干扰存储器映射这里我就详细讲一下中断的流程可能很多人不懂中断向量表存在哪里面是什么具体的中断处理函数存在哪以及怎么触发中断的中断相关寄存器的干啥的中断向量表里面存的是中断处理函数的地址也就是说中断向量表只存了地址然后找到对应的中断跳到具体的处理函数去执行中断向量表存在代码区一般是0x00000000地址开始具体的中断处理函数也是存在代码区因为中断向量表里面存了处理函数的地址于是找到具体中断就可以通过地址跳到中断处理函数去执行中断的触发一般是由硬件触发硬件检测到某种情况然后可能就会触发中断比如在stm32中的gpio中断我们可以配置下降沿触发当电平为下降沿时GPIO会自动触发中断然后CPU这个硬件会自动去查这个中断是第几号并且计算地址然后去这个地址读出函数地址然后PC指针直接跳过去中断相关寄存器是配置某种中断是否打开因为一开始所有外设的中断都是关着的屏蔽的我们配置寄存器本质就是告诉硬件允许这个中断触发中断处理流程是这样的代码跑着 → 中断硬件触发 → CPU 自动暂停 → 自动去 0x00000000 查表 → 自动跳到中断函数 → 执行完自动回来。哪如何访问外设控制外设比如ADCGPIO这种外设呢。通过把片上外设的寄存器映射到外设区就可以简单地以访问内存的方式来访问这些外设的寄存器从而控制外设的工作总线接口Cortex-M3内部有若干个总线接口以使CM3能同时取址和访存分别是指令存储区总线两条系统总线私有外设总线指令存储区的两条总线分别是 I‐Code 总线和 D‐Code 总线前者用于取指后者用于查表等操作它们按最佳执行速度进行优化系统总线用于访问内存和外设覆盖的区域包括 SRAM片上外设片外 RAM片外扩展设备以及系统级存储区的部分空间。私有外设总线负责一部分私有外设的访问主要就是访问调试组件。它们也在系统级存储区。存储器保护单元MPU使用MPU就是进一步增加系统的安全性。Cortex‐M3 有一个可选的存储器保护单元。配上它之后就可以对特权级访问和用户级访问分别施加不同的访问限制。当检测到犯规violated时MPU 就会产生一个 fault 异常可以由 fault异常的服务例程来分析该错误并且在可能时改正它最常见的用法的就是由操作系统使用MPU以使特权级代码的数据包括操作系统本身的数据不被其它用户程序弄坏。它可以把某些内存区域设置成只读从而避免了那里的内容意外被更高还可以在多任务系统中把不同任务之间的数据区隔离指令集在过去做ARM开发必须处理好两个状态32位的ARM状态和16位的Thumb状态。先讲一下为什么使用这两种不同的指令集因为当年的硬件不像现在性能很强而是有限制的Flash又小又贵如果全用arm指令代码体积大Flash不够用芯片成本会很高。如果全用Thumb指令性能又不够跑不动复杂算法中断响应慢。所以才有了混合使用这种方法主程序用Thumb省空间关键代码用ARM提性能但是使用两种指令集的缺点也很明显会有额外开销并且ARM代码和Thumb代码需要以不同的方式编译这也增加了软件开发管理的复杂度事实上Cortex‐M3 内核干脆都不支持 ARM 指令中断也在 Thumb 态下处理以前的 ARM 总是在 ARM 状态下处理所有的中断和异常。这里我要说明的是Thumb-2指令集也有32位指令但是这个32位指令不是原原本本的AMR指令我们可以将其对Thumb16位指令的扩展所以这个芯片从硬件上就砍掉了ARM指令集所以它才不需要切换状态因为本身就是Thumb指令集中断和异常ARMv7‐M 开创了一个全新的异常模型CM3 采用了它。这两种模式的机制是下面这样传统 ARMARM7/ARM9用 7 种模式 IRQ/FIQ 双中断 软件手动压栈 强制 ARM 状态的复杂模型适合高性能处理器Cortex-M3ARMv7-M彻底推翻传统用 2 种模式 统一 NVIC 硬件自动压栈 全程 Thumb 状态的极简模型专门为 MCU 设计中断响应更快、更稳定、更安全彻底解决了传统模型的所有痛点虽然 CM3 是支持 240 个外中断的但具体使用了多少个是由芯片生产商决定。CM3 还有一个NMI不可屏蔽中断输入脚。当它被置为有效assert时NMI 服务例程会无条件地执行。调试支持这个地方其实我没怎么懂对这方面几乎没有了解所以先不说了等到以后我自己学东西拓展到这里时再补上Cortex-M3 的品性简评这里我直接粘贴原文了高性能许多指令都是单周期的——包括乘法相关指令。并且从整体性能上Cortex‐M3 比得过绝大多数其它的架构。指令总线和数据总线被分开取值和访内可以并行不悖Thumb‐2 的到来告别了状态切换的旧世代再也不需要花时间来切换于 32 位 ARM 状态和16 位 Thumb 状态之间了。这简化了软件开发和代码维护使产品面市更快。Thumb‐2 指令集为编程带来了更多的灵活性。许多数据操作现在能用更短的代码搞定这意味着 Cortex‐M3 的代码密度更高也就对存储器的需求更少。取指都按 32 位处理。同一周期最多可以取出两条指令留下了更多的带宽给数据传输。 Cortex‐M3 的设计允许单片机高频运行现代半导体制造技术能保证 100MHz 以上的速度。即使在相同的速度下运行CM3 的每指令周期数(CPI)也更低于是同样的 MHz 下可以做更多的工作另一方面也使同一个应用在 CM3 上需要更低的主频。先进的中断处理功能内建的嵌套向量中断控制器支持多达 240 条外部中断输入。向量化的中断功能剧烈地缩短了中断延迟因为不再需要软件去判断中断源。中断的嵌套也是在硬件水平上实现的不需要软件代码来实现。Cortex‐M3 在进入异常服务例程时自动压栈了 R0‐R3, R12, LR, PSR 和 PC并且在返回时自动弹出它们这多清爽既加速了中断的响应也再不需要汇编语言代码了第 8 章有详述。NVIC 支持对每一路中断设置不同的优先级使得中断管理极富弹性。最粗线条的实现也至少要支持 8 级优先级而且还能动态地被修改。优化中断响应还有两招它们分别是“咬尾中断机制”和“晚到中断机制”。有些需要较多周期才能执行完的指令是可以被中断继续的——就好比它们是一串指令一样。这些指令包括加载多个寄存器LDM存储多个寄存器STM多个寄存器参与的 PUSH以及多个寄存器参与的 POP。除非系统被彻底地锁定NMI不可屏蔽中断会在收到请求的第一时间予以响应。对于很多安全‐关键(safety‐critical)的应用NMI 都是必不可少的如化学反应即将失控时的紧急停机。低功耗Cortex‐M3 需要的逻辑门数少所以先天就适合低功耗要求的应用功率低于 0.19mW/MHz在内核水平上支持节能模式SLEEPING 和 SLEEPDEEP 位。通过使用“等待中断指令WFI”和“等待事件指令WFE”内核可以进入睡眠模式并且以不同的方式唤醒。另外模块的时钟是尽可能地分开供应的所以在睡眠时可以把 CM3 的大多数“官能团”给停掉。CM3 的设计是全静态的、同步的、可综合的。任何低功耗的或是标准的半导体工艺均可放心饮用。系统特性系统支持“位寻址带”操作8051 位寻址机制的“威力大幅加强版”字节不变的大端模式并且支持非对齐的数据访问。拥有先进的 fault 处理机制支持多种类型的异常和 faults使故障诊断更容易。通过引入 banked 堆栈指针机制把系统程序使用的堆栈和用户程序使用的堆栈划清界线。如果再配上可选的 MPU处理器就能彻底满足对软件健壮性和可靠性有严格要求的应用。调试支持在支持传统的 JTAG 基础上还支持更新更好的串行线调试接口。基于 CoreSight 调试解决方案使得处理器哪怕是在运行时也能访问处理器状态和存储器内容。内建了对多达 6 个断点和 4 个数据观察点的支持。可以选配一个 ETM用于指令跟踪。数据的跟踪可以使用 DWT在调试方面还加入了以下的新特性包括 fault 状态寄存器新的 fault 异常以及闪存修补 patch操作使得调试大幅简化。可选 ITM 模块测试代码可以通过它输出调试信息而且“拎包即可入住”般地方便使用。第3章 Cortex-M3基础寄存器组R0-R7也被称为低组寄存器。所有指令都能访问它们。它们的字长全是32位复位后的初始值是不可预料的R8-R12 也被称为高组寄存器这是因为只有很少的16位Thumb指令能访问它们32位的指令则不受限制R13是堆栈指针。当引用R13是我们引用到的是当前正在使用的那一个另一个必须用特殊的指令来访问。这两个堆栈指针分别是主堆栈指针进程堆栈指针。需要注意的是并不是没有应用都必须用齐两个堆栈指针。简单的应用程序只使用MSP就够了。堆栈指针用于访问堆栈并且PUSH指令和POP指令默认使用SP寄存器的PUSH和POP操作永远都是4字对齐的-也就是说他们的地址必须是0x4,0x8,0xc。这样一来R13的最低两位被硬件连接到0并且总是读出0R14是连接寄存器LR。LR用于在调用子程序时存储返回地址。例如我们在使用BL指令时就自动填充LR的值。尽管PC的LSB总是0LR的LSB却是可读可写的。这是历史遗留的产物R15是程序计数器在汇编代码中我们也可以使用名字PC来访问它。如果向PC写数据那么CPU会立刻跳到这个地址去执行但不会吧当前返回地址存到LR寄存器。普通函数调用BL指令会自动把下一条指令地址存到LR方便返回。直接写PC就是只跳转不存LR跳过去就回不来了因为CM3指令半字对齐PC的LSB读回总是0。硬件保证指令不会存在奇数地址所以读PC时LSB固定为0当我们要跳到某个地址执行给PC写的地址必须是奇数用来告诉CPU我要在Thumb指令集下执行因为CM3不支持ARM指令集。实际执行时CPU会自动把LSB清0拿到真实的偶数地址比如我们写0x08000005实际跳去0x08000004既满足了标识要求由保证了指令对齐。如果我们给CP写了一个偶数地址也就是LSB0CPU会认为我们要切换到ARM模式但CM3根本不支持ARM模式直接触发硬件fault异常系统直接死机特殊功能寄存器组Cortex‐M3 中的特殊功能寄存器包括程序状态寄存器组PSRs 或曰 xPSR中断屏蔽寄存器组PRIMASK, FAULTMASK,以及 BASEPRI控制寄存器CONTROL这几个寄存器只能被专用的MSR和MRS指令访问而且它们也没有存储地址。书中介绍这几个寄存器的内容就是一些定义的东西就是告诉我们每个位的作用是啥我就直接截图书上的内容了操作模式当处理器处在线程状态下时既可以使用特权级也可以使用用户级另一方面handler模式总是特权级的。在复位后处理器进入线程模式特权级在线程模式用户级下对系统控制空间SCS的访问将被阻止并且还禁止使用MSR访问刚才讲到的特殊功能寄存器。这里我提一下系统控制空间其实包括了一堆的寄存器这些寄存器的地址是映射在4GB地址空间里的这些寄存器只包括了系统最关键最基本的东西比如NVIC中断SysTick系统时钟至于为什么有些寄存器比如我们的通用寄存器则不是映射的而是直接引用的这是因为SCS里的寄存器数量上百个功能复杂还需要和CPU其它外设协同工作根本不可能用CPU的方式实现在特权级下的代码可以通过置位 CONTROL[0]来进入用户级。而不管是任何原因产生了任何异常处理器都将以特权级来运行其服务例程异常返回后将回到产生异常之前的特权级。用户级下的代码不能再试图修改 CONTROL[0]来回到特权级。它必须通过一个异常 handler由那个异常 handler 来修改 CONTROL[0]才能在返回到线程模式后拿到特权级异常和中断CM3支持大量异常包括11个系统异常和最多240个外部中断–简称IRQ。具体使用了这240个中断源中的多个个则由芯片制造商决定。由外设产生的中断信号除了SysTick的之外全都连接到NVIC的中断输入信号线作为中断功能的强化NVIC 还有一条 NMI 输入信号线。NMI 究竟被拿去做什么还要视处理器的设计而定。向量表s当一个发生的异常被 CM3 内核接受对应的异常 handler 就会执行。为了决定 handler 的入口地址CM3 使用了“向量表查表机制”。这里使用一张向量表。向量表其实是一个 WORD32 位整数数组每个下标对应一种异常该下标元素的值则是该异常 handler 的入口地址。向量表的存储位置是可以设置的通过 NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后该寄存器的值为 0。因此在地址 0 处必须包含一张向量表用于初始时的异常分配。栈内存操作这里我就直接复制书上的内容了因为这个没有特别复杂我们在学算法和数据结构时也接触过笼统地讲堆栈操作就是对内存的读写操作但是其地址由 SP 给出。寄存器的数据通过 PUSH 操作存入堆栈以后用 POP 操作从堆栈中取回。在 PUSH 与 POP 的操作中SP 的值会按堆栈的使用法则自动调整以保证后续的 PUSH 不会破坏先前 PUSH 进的内容。堆栈的功能就是把寄存器的数据放入内存以便将来能恢复之——当一个任务或一段子程序执行完毕后恢复。正常情况下PUSH 与 POP 必须成对使用而且参与的寄存器不论是身份还是先后顺序都必须完全一致。当 PUSH/POP 指令执行时SP 指针的值也根着自减自增。Cortex-M3 堆栈的实现Cortex‐M3 使用的是“向下生长的满栈”模型。堆栈指针 SP 指向最后一个被压入堆栈的 32位数值。在下一次压栈时SP 先自减 4再存入新的数值在进入 ISR 时CM3 会自动把一些寄存器压栈这里使用的是进入 ISR 之前使用的 SP指针MSP 或者是 PSP。离开 ISR 后只要 ISR 没有更改过 CONTROL[1]就依然使用先前的 SP 指针来执行出栈操作。复位序列在离开复位状态后CM3 做的第一件事就是读取下列两个 32 位整数的值从地址 0x0000,0000 处取出 MSP 的初始值。从地址 0x0000,0004 处取出 PC 的初始值——这个值是复位向量LSB 必须是 1。然后从这个值所对应的地址处取指。请注意这与传统的 ARM 架构不同——其实也和绝大多数的其它单片机不同。传统的ARM 架构总是从 0 地址开始执行第一条指令。它们的 0 地址处总是一条跳转指令。在 CM3中0 地址处提供 MSP 的初始值然后就是向量表向量表在以后还可以被移至其它位置。向量表中的数值是 32 位的地址而不是跳转指令。向量表的第一个条目指向复位后应执行的第一条指令。因为 CM3 使用的是向下生长的满栈所以 MSP 的初始值必须是堆栈内存的末地址加 1。举例来说如果你的堆栈区域在 0x20007C00‐0x20007FFF 之间那么 MSP 的初始值就必须是0x20008000。向量表跟随在 MSP 的初始值之后——也就是第 2 个表目。要注意因为 CM3 是在 Thumb态下执行所以向量表中的每个数值都必须把 LSB 置 1也就是奇数。正是因为这个原因图 3.18 中使用 0x101 来表达地址 0x100。当 0x100 处的指令得到执行后就正式开始了程序的执行。在此之前初始化 MSP 是必需的因为可能第 1 条指令还没执行就会被 NMI 或是其它 fault 打断。MSP 初始化好后就已经为它们的服务例程准备好了堆栈。第4章 指令集其实这一张对于我们了解架构不是特别重要因为这部分更像是语法部分但是这部分语法也不是通用的就像C语言那样因为不同的汇编器会有一些不同的地方。这里我就讲一下我认为重要的EQU指示字这是方便我们定义常数然后再代码中使用它们例如NVIC_IRQ_SETEN0 EQU 0xE000E100NVIC_IRQ0_ENABLE EQU 0x1有的情况需要我们手工汇编查出该指令的确切二进制机器码然后使用DCI编译器指示字比如这样DCI0xBE00。我举个例子NOP ; 执行空操作NOP 的机器码是 0x46C0所以你可以写成DCI 0x46C0 ; 效果 执行 NOP类似地我们还可以使用DCB来定义一串字节常数–允许以字符串的形式的表达在stm32的启动文件中我们可以看到向量表里面就用了DCB__VectorsDCD __initial_sp ; 栈顶地址DCD Reset_Handler ; 复位函数地址DCD NMI_Handler ; NMI 地址DCD HardFault_Handler…在这里__Vectors就相当于一个数组这些DCD定义的字符串相当于数组的元素__VectorsDCD __initial_sp ; 地址 __Vectors 0DCD Reset_Handler ; 地址 __Vectors 4DCD NMI_Handler ; 地址 __Vectors 8当然我们还可以这样写那么这里是MY_NUMBER对应一个元素就相当于我们让a1一样而不是前面那样像数组一样这一章大部分都是讲了一些语法和使用注意事项对于我们了解整个架构帮助不是很大所以先跳过存储系统功能概览CM3 的存储器系统与从传统 ARM 架构的相比已经脱胎换骨了第一 它的存储器映射是预定义的并且还规定好了哪个位置使用哪条总线。第二 CM3 的存储器系统支持所谓的“位带”bit‐band操作。通过它实现了对单一比特的原子操作。位带操作仅适用于一些特殊的存储器区域中见本章论述。第三 CM3 的存储器系统支持非对齐访问和互斥访问。这两个特性是直到了 v7M 时才出来的。最后CM3 的存储器系统支持 both 小端配置和大端配置。存储器映射我在这里说明一个事情这4GB并不是所有空间都是真实存在的也就是说M3内核芯片相关的单片机并没有一个真实的4GB容量我当时看到这个图以为M3型号的单片机有一个类似于4GB空间的磁盘实际上没有STM32 实际物理存储一般只有Flash几十 KB ~ 2MBSRAM几 KB ~ 256KB所以这4GB指的CPU能够寻址到的地址空间因为我们的地址线是32位所以有4GB的寻址范围至于我们后面看到的别名区地址往别名区地址里面写数据其实不是真实的写数据而是我们执行这个操作时CPU会去自动判断我们往这个地址写东西的含义是什么你访问别名区地址时硬件直接 “翻译” 成去改 SRAM 里的某一个 bit所以stm32真正的存储容量其实很少我感觉给这4GB划分是为了方便判断我们要执行什么操作而不是让我们真正的往里面写东西内部 SRAM 区的大小是 512MB用于让芯片制造商连接片上的 SRAM这个区通过系统总线来访问。在这个区的下部有一个 1MB 的位带区该位带区还有一个对应的 32MB 的 “位带别名(alias)区”容纳了 8M 个“位变量”对比 8051 的只有 128 个位。位带区对应的是最低的 1MB 地址范围而位带别名区里面的每个字对应位带区的一个比特。位带操作只适用于数据访问不适用于取指。假设有个寄存器处于位带区这个寄存器是32位的然后如果我们要向寄存器中写入我们的数据。一般来说我们如果像修改某一个位是这样写的GPIOA-ODR | (15);看起来只有一行对吧实际上这一行会被拆解为三个指令也就是读-改-写三步曲这不是原子的也就是一旦被中断打断我们修改的过程可能会造成某种严重错误所以才有了位带区别名修改某一位比如位带区里有一个字节0x20000000值是0b10100101bit01 → 别名地址0x22000000bit10 → 别名地址0x22000004bit21 → 别名地址0x22000008那我们想修改的话只需要往别名地址写就可以了这个操作是原子的所以可以保障安全性地址空间的另一个 512MB 范围由片上外设的寄存器使用。这个区中也有一条 32MB的位带别名以便于快捷地访问外设寄存器。例如可以方便地访问各种控制位和状态位。要注意的是外设内不允许执行指令。还有两个 1GB 的范围分别用于连接外部 RAM 和外部设备它们之中没有位带。两者的区别在于外部 RAM 区允许执行指令而外部设备区则不允许。最后还剩下 0.5GB 的隐秘地带CM3 内核的闺房就在这里面包括了系统级组件内部私有外设总线 s外部私有外设总线 s以及由提供者定义的系统外设。私有外设总线有两条AHB 私有外设总线只用于 CM3 内部的 AHB 外设它们是NVIC, FPB, DWT 和 ITM。APB 私有外设总线既用于 CM3 内部的 APB 设备也用于外部设备这里的“外部”是对内核而言。CM3 允许器件制造商再添加一些片上 APB 外设到 APB 私有总线上它们通过 ABP 接口来访问。NVIC 所处的区域叫做“系统控制空间SCS”在 SCS 里的还有 SysTick、MPU 以及代码调试控制所用的寄存器如图 5.2 所示最后未用的提供商指定区也通过系统总线来访问但是不允许在其中执行指令。CM3 中的 MPU 是选配的由芯片制造商决定是否配上。上述的存储器映射只是个粗线条的模板半导体厂家会提供更展开的图示来表明芯片中片上外设的具体分布RAM 与 ROM 的容量和位置信息。存储器访问属性sCM3 在定义了存储器映射之外还为存储器的访问规定了 4 种属性分别是可否缓冲(Bufferable)可否缓存(Cacheable)可否执行(Executable)可否共享(Sharable)我在这里讲一下这个属性和MPU的联系MPU我们是规定哪部分地址可以访问而属性则是在可以访问的前提下有什么具体的性质。CM3 的 MPU 支持最多 8 个独立区域其实就是前面的内存映像图划分出来的八个区域每个区域都有自己完整的属性配置只是通过「选区域」的方式复用同一组寄存器来读写。如果我们要在一个区域的两个不连续地方去设置属性是不行的比如说我们想在SRAM区的0x40000000-040000010和0x40000020-0x40000030这两个地方同时分别设置是不可能的因为我们只有一个寄存器去指定一段连续的地址是什么属性存储器的缺省访问许可CM3有一个缺省的存储访问许可它能防止使用户代码访问系统控制存储空间保护NVICMPU等关键部件缺省访问许可在下列条件时生效没有配备MPU配备了MPU但是没有启用MPU功能也就是被除能如果启用了MPU则MPU可以在地址空间中划出若干个regions并为不同的region规定不同的访问许可权限存储器访问许可如下表所示位带操作在位带区中每个比特都映射到别名地址区的一个字——这是只有 LSB 有效的字。当一个别名地址被访问时会先把该地址变换成位带地址。对于读操作读取位带地址中的一个字再把需要的位右移到 LSB并把 LSB 返回。对于写操作把需要写的位左移至对应的位序号处然后执行一个原子的“读改写”过程。我来讲一下这里位带映射的逻辑我们别名地址最低两位都是0也就是我们的别名地址都是4的倍数我这里提醒一下这里的.0不是实际的地址.0前面的才是我们实际的地址就拿0x22000004来说最低位4翻译为二进制位0100这时候我们右移两位就变成01表示位带区对应寄存器的第一个bit位如果为1000右移两位为10就表示第二个bit位所以我们的别名区地址最低两位都是0就是方便硬件移位和计算第三个bit位的别名地址为0x2200000A最低位就是1100右移两位后为11就表示为第三个bit这就是我们的映射规则这样设计是为了方便硬件计算因为只需要移位就可以判断修改第几个bit所以才有了我们下面的公式我们写某一个位的操作流程是这样的当 CPU 发起一次写操作*(0x22000008) 1;CPU 只做了1 件事给总线发一个「写 0x22000008 地址数据为 1」的请求。然后剩下的就是硬件自动去解码和用电路将对应寄存器的某一个bit位去修改所以位带操作需要硬件的支持不然不可能为原子操作关于位带操作的优越性在书上讲了很多我认为使用位带操作是为了避免竞态问题也就是当前指令正在修改寄存器但是还没有修改完然后中断来了也修改这个寄存器这就导致执行完中断后我们原来的指令把中断修改的结果给覆盖了这就会带来问题位带操作其实是为了避免这种问题感兴趣的可以去书上看看非对齐数据传送关于非对齐传送书上给了好几个例子在 CM3 中非对齐的数据传送只发生在常规的数据传送指令中如 LDR/LDRH/LDRSH还有对应的写指令SRT/SRTH。其它指令则不支持包括多个数据的加载/存储(LDM/STM)堆栈操作 PUSH/POP互斥访问(LDREX/STREX)。如果非对齐会导致一个用法 fault位带操作。因为只有 LSB 有效非对齐的访问会导致不可预料的结果。我们可以看到其实支持非对齐数据传送的指令其实很少因为非对齐对cpu去读取和写数据不友好事实上在内部是把非对齐的访问转换为若干个对齐的访问的这种转换由处理器总线单元来完成互斥访问互斥 访 问 分 为 加 载 和 存 储 相 应 的 指 令 对 子 为 LDREX/STREX, LDREXH/STREXH,LDREXB/STREXB分别对应于字/半字/字节。为了介绍方便以 LDREX/STREX 为例讲述它们的使用方式。LDREX的语法和LDR相同不再过多赘述。而STREX则不同。STREX指令的执行是可以被驳回的。驳回的规则可宽和严最严格的规则是当遇到 STREX 指令时仅当在这之前执行过 LDREX 指令且在 LDREX 指令执行后没有执行过其它的 STR/STREX 指令才允许执行 STREX 指令——也就是说只有在 LDREX 执行后最近的一条 STREX 才能成功执行。其它情况下驳回此 STREX。包括中途有其它的 STR 指令执行中途有其它的 STREX 指令执行。在使用互斥访问时LDREX/STREX 必须成对使用。书上讲了为什么这种有条件的驳回可以避免紊乱危象感兴趣的可以自己去看对于第一个执行到的STR/STREX 指令只要其存储的地址落在标记范围内就会清除此标记对于整个 4GB 地址都被标记的情况则任何存储指令都会清除此标记。如果先后执行了两次 LDREX则以后一个 LDREX 标记的地址为准。执行STREX时会先检查有没有做出过标记如果有还要检查存储地址是否落在标记范围内。只有通过了这两个关卡STREX 才会执行。否则就驳回 STREX端模式CM3 支持 both 小端模式和大端模式。CM3中对大端模式的定义还与ARM7的不同。在ARM7中大端的方式被称为字不变大端而在CM3中使用的是字节不变大端如下表所示实现Cortex-M3的整体风景流水线当运行的指令大多数都是16位时你会发现处理器会每隔一个周期做一次取指。这是因为CM3有时可以一次取多两条指令来32位因此在第一条指令取来时也顺带着把第二条指令取来了。此时总线接口就可以在下次再取指。或者如果缓冲区是满的总线接口干脆就空闲下来了。有些指令的执行需要多个周期在这期间流水线就会暂停当执行到跳转指令时需要清洗流水线处理器会不得不从跳转目的地重新取指。为了改善这种情况CM3支持一定数量的v7M新指令可以避免很多短程跳转如第4章讲到的IF‐THEN语句块。由于流水线的存在以及出于对Thumb代码兼容的考虑读取PC会返回当前指令地址4的值。这个偏移量总是4不管是执行16位指令还是32位指令这就保证了在Thumb和Thumb2之间的一致性在处理器内核的预取单元中也有一个指令缓冲区它允许后续的指令在执行前先在里面排队也能在执行未对齐的32位指令时避免流水线“断流”。不过该缓冲区并不会在流水线中添加额外的级数因此不会恶化跳转导致的性能下降penalty。详细的框图虚线框住的MPU和ETM是可选组件不一定回包含在每一个CM3的MCU中书上关于这里的每一个组件都做了进一步的说明下面是原文可见Cortex‐M3 处理器是以一个“处理器子系统”呈现的其 CPU 内核本身与 NVIC和一系列调试块都亲密耦合CM3CoreCortex‐M3 处理器的中央处理核心嵌套向量中断控制器 NVICNVIC 是一个在 CM3 中内建的中断控制器。中断的具体路数由芯片厂商定义。NVIC 是与 CPU 紧耦合的它还包含了若干个系统控制寄存器。因为 NVIC 支持中断嵌套使得在 CM3 上处理嵌套中断时清爽而强大。它还采用了向量中断的机制。在中断发生时它会自动取出对应的服务例程入口地址并且直接调用无需软件判定中断源为缩短中断延时做出了非常重要的贡献。SysTick 定时器系统滴答定时器是一个非常基本的倒计时定时器用于在每隔一定的时间产生一个中断即使是系统在睡眠模式下也能工作。它使得 OS 在各 CM3器件之间的移植中不必修改系统定时器的代码移植工作一下子容易多了。SysTick定时器也是作为 NVIC 的一部分实现的。存储器保护单元MPU 是一个选配的单元有些 CM3 芯片可能没有配备此组件。如果有则它可以把存储器分成一些 regions并分别予以保护。例如它可以让某些 regions 在用户级下变成只读从而阻止了一些用户程序破坏关键数据。BusMatrixBusMatrix 是 CM3 内部总线系统的核心。它是一个 AHB 互连的网络通过它可以让数据在不同的总线之间并行传送——只要两个总线主机不试图访问同一块内存区域。BusMatrix 还提供了附加的数据传送管理设施包括一个写缓冲以及一个按位操作的逻辑 位带(bit‐band) 。AHB to APB它是一个总线桥用于把若干个 APB 设备连接到 CM3 处理器的私有外设总线上内部的和外部的。这些 APB 设备常见于调试组件。CM3 还允许芯片厂商把附加的 APB 设备挂在这条 APB 总线上并通过 APB 接入其外部私有外设总线。框图中其它的组件都用于调试通常不会在应用程序中使用它们。SW‐DP/SWJ‐DP串行线调试端口SW‐DP/串口线 JTAG 调试端口SWJ‐DP都与 AHB访问端口AHB‐AP协同工作以使外部调试器可以发起 AHB 上的数据传送从而执行调试活动。在处理器核心的内部没有 JTAG 扫描链大多数调试功能都是通过在 NVIC 控制下的AHB 访问来实现的。SWJ‐DP 支持 both 串行线协议和 JTAG 协议而 SW‐DP 只支持串行线协议。AHB‐AP AHB 访问端口通过少量的寄存器提供了对全部 CM3 存储器的访问机能。该功能块由 SW‐DP/SWJ‐DP 通过一个通用调试接口DAP来控制。当外部调试器需要执行动作的时候就要通过 SW‐DP/SWJ‐DP 来访问 AHB‐AP从而产生所需的 AHB 数据传送。嵌入式跟踪宏单元 ETMETM 用于实现实时指令跟踪但它是一个选配件所以不是所有的 CM3 产品都具有实时指令跟踪能力。ETM 的控制寄存器是映射到主地址空间上的因此调试器可以通过 DAP 来控制它。数据观察点及跟踪单元通过 DWT可以设置数据观察点。当一个数据地址或数据的值匹配了观察点就产生了一次匹配命中事件。匹配命中事件可以用于产生一个观察点事件后者能激活调试器以产生数据跟踪信息或者让 ETM 联动以跟踪在哪条指令上发生了匹配命中事件——译者注。指令跟踪宏单元 ITMITM 有多种用法。软件可以控制该模块直接把消息送给 TPIU类10似 printf 风格的调试还可以让 DWT 匹配命中事件通过 ITM 产生数据跟踪包并把它输出到一个跟踪数据流中。跟踪端口的接口单元 TPIUTIPU 用于和外部的跟踪硬件如跟踪端口分析仪交互。在 CM3 的内部跟踪信息都被格式化成“高级跟踪总线ATB包”TPIU 重新格式化这些数据从而让外部设备能够捕捉到它们。FPBFPB提供flash地址重载和断点功能。Flash地址重载是指当CPU访问的某条指令匹配到一个特定的flash地址时将把该地址重映射到SRAM中指定的位置从而取指后返回的是另外的值。此外匹配的地址还能用来触发断点事件。Flash地址重载功能对于测试工作太有用了。例如通过使用FPB来改变程序流程就可以给那些不能在普通情形下使用的设备添加诊断程序代码such as adding diagnosis program code to a device that cannot be usedin normal situations unless the FPB is used to change the program control.。ROM 表它只是一个简单的查找表提供了存储器映射信息这些信息供包括了多种系统设备和调试组件。当调试系统定位各调试组件时它需要找出相关寄存器在存储器的地址这些信息由此表给出。绝大多数情况下因为 CM3 有固定的存储器映射所以各组件都对号入座——拥有一致的起始地址。但是因为有些组件是可选的还有些组件是可以由制造商另行添加的各芯片制造商可能需要定制他们芯片的调试功能。林子大了什么鸟都有在这种情况下必须在 ROM 表中给出这些“另类”的信息这样调试软件才能判定正确的存储器映射进而可以检测可用的调试组件是何种类型。Cortex-M3的总线接口总的来说指令总线和数据总线是给CPU核心内部高速访问用的系统总线是给外部全局资源用的我们添加的很多外设比如GPIOADC是通过系统总线去访问到内部的。Cortex-M3 的其它接口除了总线接口之外CM3还有若干个用于其它目的的接口这些接口的信号都不大可能会引出到引脚上而只用于连接SoC不同的部分或者干脆就没有使用下表给出了它们中一些信号的简短小结外部私有外设总线典型的连接方式这个图只是一个很简单的示范芯片设计师也可以选择其它的总线连接方案。如果只是对于软件/固件的开发不需要了解这么多细节只需要知道详细的存储器映射就够了。这个框架只是一个大概的框架不同型号的设备这个图会不同我这里放一个stm32f10系列的图复位信号异常
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2493810.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!