
1. ARM926EJ-S一个经典嵌入式内核的深度解剖在嵌入式系统开发领域尤其是十多年前的工控、消费电子和网络设备中如果你拆开一块电路板有很大概率会看到一颗基于ARM9系列内核的芯片。而ARM926EJ-S无疑是这个家族中最具代表性、应用最广泛的成员之一。它不像今天的Cortex-A系列那样追求极致的性能与能效比而是在一个恰到好处的平衡点上拥有足够支撑复杂操作系统如Linux、WinCE的内存管理单元MMU和缓存Cache同时又保持了相对简单的流水线和可预测的时序这对于许多实时性要求高的工业场景至关重要。我经手过不少基于TI AM1808/AM1810这类芯片的项目其核心正是ARM926EJ-S。今天我们就抛开枯燥的数据手册从一线工程师的视角深入聊聊这个经典内核的架构精髓特别是MMU、Cache以及它们如何与整个系统互联架构协同工作构成一个稳定可靠的片上系统SoC。2. 核心架构与设计哲学解析ARM926EJ-S属于ARMv5TEJ架构这是一个承上启下的关键版本。它继承了早期ARM内核的简洁高效又为运行现代操作系统做好了硬件准备。理解它的设计首先要抓住几个关键点。2.1 哈佛架构与双AHB总线与许多简单的微控制器采用的冯·诺依曼架构指令和数据共享总线不同ARM926EJ-S采用了经典的哈佛架构。这意味着它内部有独立的指令总线I-AHB和数据总线D-AHB。这个设计带来的最直接好处是CPU可以同时进行指令取指和数据存取极大地减少了总线冲突提升了流水线的效率。在AM1808的芯片内部你会看到ARM核心通过这两条总线连接到不同的交换中心资源SCR上从而可以同时访问片内RAM、外设和外部存储器这是实现高实时吞吐量的基础。在实际调试中这个分离的总线设计有时会带来一些有趣的现象。例如当你配置一段内存区域为“非缓存Non-cacheable”且“非缓冲Non-bufferable”时对它的数据写入会立刻体现在总线上方便你用逻辑分析仪抓取而指令取指则走另一条路。这种清晰的分离为性能优化和问题定位提供了便利。2.2 ARM与Thumb双指令集状态ARM926EJ-S支持ARM32位和Thumb16位两种指令集状态可以通过BX指令灵活切换。这不是简单的“兼容模式”而是一种深度的代码密度与性能的权衡艺术。ARM状态32-BIS每条指令32位功能强大能完成复杂操作单条指令效率高但占用的程序存储空间大。在AM1808的64KB Boot ROM里如果全用ARM指令能放的代码量就很有限。Thumb状态16-BIS每条指令16位代码密度接近ARM指令的65%这意味着在同样的Flash容量下你能塞进更多功能。虽然有些操作需要多条Thumb指令来完成但在连接16位或32位低速存储器时由于总线宽度利用更充分实际性能可能达到同等32位处理器连接16位内存系统的160%。我的一个实战经验是在资源紧张的场合我会用Thumb指令编写大部分应用程序代码以节省Flash空间。而对于性能关键的底层驱动如中断服务程序、高频调用的算法循环则用ARM指令编写并用BX指令切换过去。编译器如GCC的-mthumb和-marm选项可以很好地协助你完成这项工作。这种“关键路径用ARM其余用Thumb”的策略是榨干ARM926EJ-S性能的常用技巧。2.3 处理器操作模式与状态寄存器ARM926EJ-S有7种操作模式这不仅是软件概念更是硬件级别的隔离与保护机制用户模式USR大部分应用程序运行于此权限最低。特权模式包括快速中断FIQ、中断IRQ、管理模式SVC、中止模式ABT、未定义模式UND和系统模式SYS。操作系统内核和异常处理程序运行在这些模式下。模式切换通常由异常触发如中断、SWI指令。每种模式都有自己独立的堆栈指针SP和备份寄存器。例如FIQ模式有专用的R8-R14寄存器这允许进入FIQ中断时无需保存通用寄存器实现了极速响应。在编写启动代码或操作系统移植时必须在每种模式初始化前正确设置其SP否则程序会立刻跑飞。控制这一切的是当前程序状态寄存器CPSR。它的低8位尤为关键M[4:0]模式位决定了当前处于上述7种模式中的哪一种。T位0表示ARM状态1表示Thumb状态。I位和F位分别控制IRQ和FIQ中断的全局开关。在进入关键代码段或某些初始化流程时需要小心地操作这两位来屏蔽中断。注意在修改CPSR以切换模式或修改中断使能时务必使用MSR指令或类似的原子操作并确保你知道当前处理器的状态。错误地修改CPSR是导致系统“死锁”的常见原因之一。3. 内存管理单元MMU详解虚拟内存的基石MMU是ARM926EJ-S从单片机升级为可运行高级操作系统核心处理器的标志。它的核心职责是完成虚拟地址VA到物理地址PA的转换并提供内存访问保护。3.1 地址转换流程与TLB当CPU发出一个指令取指或数据访问请求时地址的旅程如下虚拟地址VA由ARM核心发出是程序员看到的地址。修改后虚拟地址MVA在支持多进程的系统中MMU会将进程ID与VA结合生成MVA以区分不同进程的地址空间。在AM1808这类单应用为主的系统中MVA通常等于VA。物理地址PAMMU通过查表将MVA转换得到的最终实际内存地址。这个转换表页表存储在系统主存如DDR中。如果每次访问都去主存查表速度将无法忍受。因此MMU内部集成了一个转换旁路缓存TLB。TLB是一个小容量但极快的缓存存放最近使用过的页表项。当CPU发出VA时MMU首先在TLB中查找匹配项TLB命中瞬间完成转换。如果TLB未命中则需发起一次“页表遍历”从主存中加载对应的页表项到TLB这个过程较慢。ARM926EJ-S的MMU支持多种页大小1MB段、64KB大页、4KB小页和1KB极小页。Linux通常使用4KB页提供了灵活的内存分配粒度。MMU还支持“域”和“子页权限”等高级特性允许对内存区域进行精细的读写执行权限控制。3.2 实战中的MMU配置与问题排查在裸机开发或移植Bootloader时你可能需要手动初始化MMU。这个过程大致是在内存中建立页表一个巨大的数组每个条目描述一段VA到PA的映射及权限。将页表的基地址写入CP15的寄存器2TTB。使能MMU设置CP15寄存器1的某个控制位。一个常见的坑是缓存与MMU的使能顺序。在MMU开启前CPU使用物理地址访问缓存。MMU开启后则使用虚拟地址MVA。如果顺序不当会导致缓存中数据错乱。安全的做法是先建立初始映射通常是一段1:1的恒等映射保证开启MMU瞬间代码还能正确执行然后无效化Invalidate整个指令和数据Cache再开启MMU。当系统出现“数据中止”或“预取中止”异常时很可能是MMU配置问题。你需要检查访问的地址是否在页表中有效映射当前CPU模式用户/特权是否具有该地址的读写/执行权限是否尝试向只读区域写入数据通过读取CP15的故障地址寄存器FAR和故障状态寄存器FSR可以精确定位问题。4. 高速缓存Cache与写缓冲器性能加速器ARM926EJ-S集成了独立的16KB指令CacheI-Cache和16KB数据CacheD-Cache以及一个写缓冲器Write Buffer。这是提升系统性能最关键的特性之一。4.1 Cache工作原理与策略Cache可以理解为CPU和慢速主存之间的一个高速缓冲区。其基本单位是“行Line”ARM926EJ-S的Cache行是8个字32字节。它是四路组相联的这是一种在硬件复杂度、命中率和冲突概率之间取得平衡的经典设计。读操作CPU要读一个数据首先根据地址在Cache中查找。如果找到命中几个时钟周期内就能返回数据如果未命中则需要从主存中读取整个Cache行32字节填充到Cache中再返回所需数据。这个过程体现了“空间局部性”原理。写操作策略更复杂主要有两种写通Write-Through数据同时写入Cache和主存。简单可靠但总线压力大。写回Write-Back/Copy-Back数据只写入Cache并将该Cache行标记为“脏Dirty”。只有当该行被新的数据替换出去时才一次性写回主存。效率高但存在数据不一致的风险Cache中的数据是最新的主存中是旧的。在ARM926EJ-S中通过MMU页表条目中的CCacheable和BBufferable位来控制每块内存区域的Cache和写缓冲策略。例如对于映射外设寄存器的内存区域必须设置为“非缓存、非缓冲”否则你无法读到外设实时更新的状态。4.2 写缓冲器的作用写缓冲器是D-Cache的搭档。当CPU向一个“可缓冲”的内存区域写入数据时数据并非立刻发往总线而是先进入这个深度为16个字的写缓冲器。CPU可以立即继续执行下一条指令由写缓冲器在后台完成与主存的同步。这极大地隐藏了写操作的延迟。对于“可缓存、可缓冲、写回”的区域D-Cache自身还有一个8个字的写回缓冲专门用于处理脏行被替换时的回写操作。4.3 Cache一致性与维护操作Cache带来了性能也带来了最大的麻烦一致性问题。当多个主设备如ARM CPU和DMA控制器访问同一块物理内存时如果CPU Cache中有该数据的副本而DMA直接将新数据写入主存那么CPU后续读到的将是Cache中的旧数据导致程序错误。在AM1808这类多主系统中维护一致性是软件的责任。ARM提供了通过CP15协处理器指令来管理Cache的机制清理Clean将指定Cache行中已修改脏的数据写回主存但该行仍保留在Cache中。无效化Invalidate丢弃指定Cache行中的数据下次访问将导致未命中。清理并无效化Clean and Invalidate先写回再丢弃是最彻底的操作。实战心得在启动DMA传输前如果DMA要从某块内存读取数据由CPU准备你需要先清理对应内存区域的D-Cache确保CPU写入的数据已同步到主存。在DMA传输完成后如果CPU要读取DMA写入的数据你需要先无效化对应内存区域的D-Cache迫使CPU从主存读取最新数据。忘记这些操作是嵌入式系统中最隐蔽的Bug来源之一。5. 系统互联与内存保护SoC的骨架与卫兵一个处理器核心再强大也需要与内存、外设高效、安全地通信。AM1808的系统互联架构和内存保护单元MPU就扮演了骨架和卫兵的角色。5.1 交换中心资源SCR架构从提供的框图可以看出AM1808的互联不是简单的共享总线而是一个由多个交换中心资源SCR和桥接器Bridge构成的“交换 fabric”。你可以把它想象成一个微型的高速交换网络SCR作为交叉开关连接多个主设备Master如ARM、EDMA、USB和从设备Slave如内存、外设。它支持基于优先级的仲裁允许不同主从对之间并发传输。例如ARM通过SCR0访问片内RAM的同时EDMA可以通过SCR1访问EMIFA接口上的Flash互不阻塞。桥接器主要用于不同时钟域或总线宽度之间的转换。例如ARM和高速外设可能运行在较快的时钟域而某些低速外设在另一个慢速时钟域桥接器负责同步它们之间的通信。这种架构避免了传统共享总线的瓶颈是实现高带宽、低延迟多数据流并发的关键。在规划软件数据流时理解这个矩阵如表3-1很有帮助你可以有意地将频繁通信的主从设备安排到通过不同SCR连接的路径上以减少冲突。5.2 内存保护单元MPU实战MMU为操作系统提供了进程间的内存保护和虚拟化而MPU则是在SoC级别为不同的硬件主设备设定访问规则。在AM1808中MPU1保护128KB片内RAMMPU2保护DDR2/mDDR SDRAM。MPU的工作原理它为受保护的内存区域定义了一系列可编程的“范围Range”每个范围规定了哪些主设备通过其特权ID可以访问以及可以进行何种操作读、写、执行。例如你可以配置一段存放关键代码的DDR区域只允许ARM以“执行”权限访问禁止EDMA或USB控制器读取防止代码被窃取或意外篡改。一段作为视频缓冲区的片内RAM允许ARM和显示控制器LCDC读写但禁止其他主设备访问保证显示数据的完整性。当违规访问发生时MPU会阻止该次访问并触发一个可配置的中断地址错误或保护错误同时在寄存器中记录违规的地址、主设备ID和访问类型极大地方便了系统调试和故障隔离。配置示例与避坑指南 假设我们要保护DDR中0xC3000000开始的1MB区域只允许ARM和EDMA0访问且EDMA0只能写ARM可读可写。确定主设备ID查表可知ARM数据访问ID0EDMA3_0_TC0 ID需根据其通道配置继承自其控制器EDMA3_0_CC0。配置MPU2范围寄存器设置起始地址MPSAR为0xC3000000结束地址MPEAR为0xC30FFFFF。配置页属性寄存器MPPAAID0对应ARM ID置1AID?对应EDMA0的ID置1其他AID位清0。权限位SR1特权读SW1特权写SX0禁止执行因是数据区UR/UW/UX根据需求设置通常用户模式无权访问关键数据区可设为0。这里需要注意MPU不区分主设备是读还是写它只区分“特权/用户”模式的读写。如果要实现“EDMA只能写”需要在软件层面通过配置EDMA通道的源/目标地址来间接控制或者结合其他硬件机制。重要提示MPU的默认模式是“假设允许ASSUME_ALLOWED”即未在范围内明确禁止的访问都被允许。在安全至上的系统中强烈建议将其改为“假设禁止”然后显式地开放每一个需要的区域遵循最小权限原则。另外一定要保护好MPU自身的配置寄存器防止被恶意修改。6. 协处理器CP15系统控制的总开关CP15是ARM架构中用于系统控制的协处理器在ARM926EJ-S中它是配置和管理MMU、Cache、TLB、访问权限等所有核心功能的唯一入口。所有操作都通过MRC从CP15读到ARM寄存器和MCR从ARM寄存器写到CP15这两条指令在特权模式下完成。关键寄存器组概览寄存器1控制寄存器包含MMU使能位、Cache使能位、地址对齐检查位等全局开关。系统上电初始化流程中操作这个寄存器需要格外小心。寄存器2转换表基址寄存器TTB存放第一级页表的物理基地址。在开启MMU前必须正确设置。寄存器7Cache操作寄存器用于执行我们前面提到的Cache清理、无效化等维护操作。你需要向这个寄存器写入特定的命令格式来指定操作类型和地址范围。寄存器8TLB操作寄存器用于无效化整个TLB或单个TLB条目。在修改页表后必须无效化对应的TLB条目否则CPU可能继续使用旧的转换结果。寄存器13进程ID寄存器在支持地址空间标识符ASID的系统中用于快速切换不同进程的地址空间而不必每次无效化整个TLB。操作CP15寄存器是底层开发中最“硬核”的部分之一。一个错误的值就可能导致系统立即锁定。我的习惯是在编写这些代码时大量使用宏定义来封装操作并添加详尽的注释因为几个月后回头看很容易忘记某个魔数的含义。7. 异常与中断处理系统的应急机制异常是处理器正常执行流的打断。ARM926EJ-S的异常向量表固定位于0xFFFF0000通过VINITHI信号配置AM1808中映射到8KB ARM本地RAM的起始处。每个异常入口只有4字节通常存放一条跳转指令。异常优先级与现场保护 异常按优先级处理复位 数据中止 FIQ IRQ 预取中止 未定义指令/SWI。高优先级异常可以打断低优先级异常的处理。 进入异常模式后硬件会自动将返回地址保存到该模式下的LR寄存器R14并将CPSR保存到SPSR中。软件的责任是进一步保存其他可能被破坏的通用寄存器到当前模式的堆栈中现场保护。处理异常。恢复通用寄存器。使用一条特殊的指令如SUBS PC, LR, #4同时恢复PC和CPSR返回原程序。FIQ与IRQ的抉择 FIQ之所以“快”除了有专用寄存器R8-R14_fiq避免保存开销其向量位于异常表末尾0x1C允许将处理程序直接放在那里省去一次跳转。对于最苛刻的实时中断如电机控制PWM应分配给FIQ。IRQ则用于一般的外设中断。在AM1808中需要通过ARM中断控制器AINTC来管理和配置这些中断源。8. 常见问题排查与调试技巧实录基于ARM926EJ-S的系统调试核心在于理解其架构并善用工具。问题一系统随机死机或数据错误。排查思路Cache一致性首先怀疑DMA与CPU共享内存区域时的Cache问题。检查在DMA启动前和完成后是否进行了正确的Cache清理和无效化操作。MMU配置错误检查页表映射是否正确特别是设备寄存器等非缓存区域的属性必须为Non-cacheable, Non-bufferable。堆栈溢出检查各模式下的堆栈指针是否设置合理是否发生了溢出并破坏了关键数据。中断嵌套与优先级检查是否在中断服务程序中误开启了中断导致重入和堆栈混乱。确认FIQ/IRQ的优先级配置是否符合预期。问题二性能不达预期。优化方向Cache命中率使用性能分析工具或通过测量指令周期分析关键循环的Cache命中率。尝试调整数据结构对齐方式32字节对齐利于Cache行填充或使用preload指令预取数据。Thumb/ARM指令集对性能热点函数尝试用ARM指令集重写对比效果。总线竞争分析系统互联矩阵将高带宽的主从设备对如视频处理DMA与DDR安排到不同的SCR路径上减少仲裁等待。问题三调试MMU/Cache相关疑难杂症。工具与方法利用CP15故障寄存器在数据/预取中止异常处理程序中读取FAR和FSR能直接告诉你故障地址和原因权限错误、转换错误等。分阶段使能在Bring Up阶段先不开启MMU和Cache让系统在最简单的状态下跑通。然后逐步使能先使能MMU并建立恒等映射再使能D-Cache最后使能I-Cache。每步都进行充分测试。写缓冲器排空在修改关键配置如切换页表或进入低功耗模式前使用CP15的“排空写缓冲器”命令MCR p15, 0, Rd, c7, c10, 4确保所有缓冲写操作已完成避免数据丢失。问题四MPU配置后外设DMA失败。检查清单确认主设备ID确保你在MPPA中允许的AID位确实对应了发起访问的那个DMA控制器或外设。不同EDMA传输控制器的ID可能不同。检查权限粒度MPU1的保护粒度是1KBMPU2是64KB。如果你的保护区域边界没有按粒度对齐配置可能不会按预期生效。检查“假设”模式确认CONFIG寄存器的ASSUME_ALLOWED位是否符合你的安全模型预期。ARM926EJ-S及其所在的SoC如AM1808是一个精密的系统。把它理解为一个由CPU核心、内存管理、缓存子系统和复杂互联网络构成的整体而不仅仅是看CPU的主频。掌握MMU、Cache和系统互联的细节不仅能帮你写出更高效、更稳定的代码更能让你在问题出现时拥有直指核心的排查能力。这份深入的理解是区分嵌入式工程师与单片机程序员的关键所在。