arm 精准总线错误与非精准总线错误

一、总线错误

1.1 arm总线设计

要了解什么是总线错误,就要先了解arm的总线设计。

AMBA(Advanced Micro-Controller Bus Architecture)是由ARM Limited公司推出的On-Chip Bus片上总线规范,是目前芯片总线的主流标准(该标准在不断演进),常用的总线:高性能总线 (AdvancedHigh Performance Bus,AHB)、系统总线 (AdvancedSystem Bus,ASB)和外设总线(Advanced PeripheralBus,APB)。

ARM 处理器内核系列 典型内核型号 AMBA 版本 主要总线协议 应用场景
Cortex-M0/M0+ Cortex-M0, Cortex-M0+ AMBA 2.0 AHB-Lite, APB 低功耗、低成本微控制器
Cortex-M3/M4/M7 Cortex-M3, Cortex-M4, M7 AMBA 3.0 AHB-Lite, APB 主流嵌入式应用
Cortex-M23/M33/M55 Cortex-M23, Cortex-M33, M55 AMBA 4.0 AXI4, APB 安全关键型应用、IoT
Cortex-A 系列(早期) Cortex-A5, A7, A9 AMBA 3.0 AHB, AXI3 智能手机、平板电脑
Cortex-A 系列(现代) Cortex-A15, A53, A57, A72 AMBA 4.0 AXI4, ACE, ACE-Lite 高性能移动设备、服务器
Cortex-A 系列(最新) Cortex-A76, A78, X1 AMBA 5.0 CHI, AXI5 旗舰手机、数据中心
Cortex-R 系列 Cortex-R4, R5, R7, R8 AMBA 3.0/4.0 AXI3, AXI4 汽车电子、工业控制(实时应用)
ARM7/ARM9 系列(经典内核) ARM7TDMI, ARM926EJ-S AMBA 2.0 AHB, ASB, APB 传统嵌入式系统
Neoverse 系列(服务器) Neoverse N1, E1, V1 AMBA 5.0 CHI, AXI5 云计算、数据中心

ARM 系统总线 BUS从 CPU 内核开始。这是在 MMU 和 CPU 缓存单元之后,它连接到外围设备。此 CPU 总线由主时钟fclk ) 运行。这与高频时钟是同一个概念。对于内存和低速外围设备来说,这个时钟非常高。因此,有一个桥bridge将时钟除以 4 倍(hclk ),这用于高速外设。此总线也称为 AHB 或 ARM 高速总线 。内存和图形外设(Memory and Graphics peripherals)应连接到此总线。同样,这个 AHB 进入一个桥,以进一步将时钟除以 2。这用于低速外围设备。这称为 APB。ARM 外设总线 (APB)。低速外设(Low speed peripherals),如串行端口、I2C、SPI。

M0采用冯诺依曼结构,而M3,M4采用哈佛结构,具有独立的数据总线和指令总线。这种将数据总线和指令总线分开的结构,可以大大提高总线的数据存储量,消除瓶颈效应。

在上图中,对应总线矩阵(Bus Matrix), 总线矩阵中还有其他总线。需要注意的是,虽然M3,M4的数据总线和指令总线分开,两者的存储并没有分开。以M4内核为例,从官方参考手册(Documentation -- Arm Developer)上可以看出:

I-Code 总线

I-Code的作用是取指令&执行指令,只和指令有关,I-Code 总线是一条基于 AHB-Lite 总线协议的 32 位总线,负责在 0x0000_0000 -- 0x1FFF_FFFF 之间的取指操作。取指以字(32位)的长度执行,即使是对于 16 位指令也如此。因此 CPU 内核可以一次取出两条 16 位 Thumb 指令。

D-Code 总线

D-Code 的作用是对数据读写访问,只和数据有关,D-Code 总线也是一条基于 AHB-Lite 总线协议的 32 位总线,负责在 0x0000_0000 -- 0x1FFF_FFFF(与I-Code相同)之间的数据访问操作。尽管 CM3 支持非对齐访问,但你绝不会在该总线上看到任何非对齐的地址,这是因为处理器的总线接口会把非对齐的数据传送都转换成对齐的数据传送。因此,连接到 D-Code总线上的任何设备都只需支持 AHB-Lite 的对齐访问,不需要支持非对齐访问。

系统总线

系统总线也是一条基于 AHB-Lite 总线协议的 32 位总线,负责在 0x2000_0000 -- 0xDFFF_FFFF 和0xE010_0000 -- 0xFFFF_FFFF 之间的所有数据传送,取指和数据访问都算上。和 D-Code 总线一样,所有的数据传送都是对齐的

外设总线

这是一条基于 APB 总线协议的 32 位总线。此总线来负责 0xE004_0000 -- 0xE00F_FFFF 之间的私有外设访问。但是,由于此 APB 存储空间的一部分已经被 TPIU、 ETM 以及 ROM 表用掉了,就只留下了 0xE004_2000-E00F_F000 这个区间用于配接附加的(私有)外设。

调试访问端口总线

调试访问端口总线接口是一条基于"增强型 APB 规格"的 32 位总线,它专用于挂接调试接口,例如 SWJ-DP 和 SW-DP。

1.2 总线错误

当 AHB 接口上正在传送数据时,如果回复了一个错误信号(error response),则会产生总线 faults,产生的场合可以是:

  • 取指,通常被称作"预取流产"(prefetch abort)
  • 数据读/写,通常被称作"数据流产"(data abort)

哪些因素会导致 AHB 回复一个错误信号?

  1. 企图访问无效的存储器 region。常见于访问的地址没有相对应的存储器。
  2. 设备还没有作好传送数据的准备。比如,在尚未初始化 SDRAM 控制器的时候试图访问 SDRAM。
  3. 在企图启动一次数据传送时,传送的尺寸不能为目标设备所支持。例如,某设备只接受字型数据,却试图送给它字节型数据。
  4. 因为某些原因,设备不能接受数据传送。例如,某些设备只有在特权级下才允许访问,可当前却是用户级。

二、非精准总线错误的由来

非精准总线错误(Imprecise Bus Fault)的存在主要源于现代处理器为提高性能而采用的异步内存访问机制硬件优化设计。这类错误的核心特点是:内存访问失败与异常触发之间存在时间差,导致处理器无法精确定位错误发生点。以下是具体原因和场景分析:

1. 写缓冲(Write Buffer)机制

  • 原理:处理器为加速内存写入操作,会将写请求暂存到写缓冲中,继续执行后续指令而不必等待内存写入完成。若写缓冲在后续刷新到内存时失败(如地址未映射、总线断开),则触发非精准错误。

2. DMA(直接内存访问)操作

  • 原理:DMA 控制器直接访问系统总线进行数据传输,与处理器并行工作。若 DMA 访问内存失败(如地址冲突、外设故障),处理器无法立即感知,需等待 DMA 完成或错误检测机制触发。

  • 示例

    cpp 复制代码
    // 启动DMA传输(从外设到内存)
    DMA_StartTransfer(src_addr, dst_addr, size);
    
    // 处理器继续执行其他代码(不等待DMA完成)
    do_something_else();

    若 DMA 传输过程中dst_addr无效,错误会在 DMA 操作后期被检测到,此时处理器可能已执行多条指令。

3. 缓存(Cache)与预取(Prefetch)机制

  • 缓存失效:若缓存行失效后需要从主存重新加载数据,但主存地址不可访问,可能触发非精准错误。
  • 指令预取失败:处理器预取指令时若发生内存访问错误,可能继续执行已预取的后续指令,导致错误报告延迟。

4. 多周期内存访问

  • 突发传输(Burst Transfer):处理器进行连续内存访问时(如读取数组),可能采用突发模式。若传输过程中某地址出错,整个突发操作可能完成后才报告错误。

  • 示例

    cpp 复制代码
    // 连续读取数组(可能触发突发传输)
    for (int i = 0; i < 1000; i++) {
        sum += array[i];
    }

    array[500]地址无效,错误可能在循环结束后才被检测到。

5. 外设总线异步错误

  • 外设通信失败:如 SPI、I2C 等外设访问共享内存时发生错误,可能通过中断或状态标志异步通知处理器,导致错误与处理不同步。

  • 示例

    cpp 复制代码
    // 向外设发送数据(通过内存映射寄存器)
    PERIPHERAL_DATA_REG = data;
    
    // 继续执行其他代码(外设可能在后台处理数据)

    若外设访问内存时出错,处理器可能已执行到后续代码。

三、小结

特性 精准的总线错误 非精准的总线错误
错误发生与处理的关系 同步:指令执行立即暂停,异常立即触发 异步:指令继续执行,异常在后续阶段触发
错误定位精确性 精确:BFAR 寄存器保存错误地址 不精确:BFAR 通常无效,无法准确定位错误
LR 寄存器(链接寄存器)值 指向引发错误的指令 指向错误检测点之后的指令
BFAR 寄存器有效性 SCB->HFSR.BFARVALID = 1(有效) SCB->HFSR.BFARVALID = 0(无效)
典型触发场景 指令直接访问内存失败(如访问未映射地址) 外设或 DMA 异步操作导致的内存访问失败

触发条件对比

精准的总线错误
  • 内存访问未映射地址 :例如访问0xFFFFFFFF
  • 内存访问权限冲突:如向只读区域写入数据。
  • 非对齐访问:例如在不支持非对齐访问的架构上执行非对齐的字访问。
  • 指令预取失败:取指阶段访问指令存储器失败。
非精准的总线错误
  • DMA 操作错误:直接内存访问过程中发生总线故障。
  • 外设异步错误:如 SPI/I2C 传输时的 FIFO 溢出。
  • 缓存或写缓冲错误:写缓冲刷新到内存时失败。
  • 多周期内存访问:如突发传输(burst transfer)过程中出错。

四、调试与排查建议

场景 精准错误排查方法 非精准错误排查方法
错误地址定位 读取SCB->BFAR 分析上下文,检查 DMA / 外设操作
寄存器检查 SCB->HFSR.BFARVALID == 1 SCB->HFSR.BFARVALID == 0
典型代码问题 野指针、数组越界、错误的内存映射 DMA 配置错误、外设中断处理不当

ref:

HardFault错误信息分析定位_hardfault定位问题-CSDN博客

https://mbb.eet-china.com/forum/topic/114149_1_1.html

HardFault全解析:从寄存器诊断到精准定位-CSDN博客

Documentation -- Arm Developer

《ARMv7-M Architecture Reference Manual》

C 总线错误 (bus error) - 段错误 (segmentation fault)-CSDN博客

ARM异常处理(3):Bus faults、Memory management faults、Usage faults、Hard faults详解-CSDN博客

《Cortex‐M3 权威指南》 ,第七章,总线 Faults

AMBA -- Arm®

ARM bus hierarchy - ARM highspeed bus/AHB and ARM peripheral bus/APB

AMBA Specifications -- Arm®

嵌入式调试必修课11_MCU总线接口深度解析(Part I):I-Code/D-Code/S-Bus的工作原理_哔哩哔哩_bilibili

Cortex-M3 I-Code,D-Code,系统总线及其他总线接口_m3 编译区分 如何d总线,s总线-CSDN博客

相关推荐
森G10 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
VekiSon13 小时前
Linux内核驱动——杂项设备驱动与内核模块编译
linux·c语言·arm开发·嵌入式硬件
AI+程序员在路上14 小时前
Nand Flash与EMMC区别及ARM开发板中的应用对比
arm开发
17(无规则自律)20 小时前
深入浅出 Linux 内核模块,写一个内核版的 Hello World
linux·arm开发·嵌入式硬件
梁洪飞1 天前
内核的schedule和SMP多核处理器启动协议
linux·arm开发·嵌入式硬件·arm
代码游侠2 天前
学习笔记——Linux字符设备驱动
linux·运维·arm开发·嵌入式硬件·学习·架构
syseptember2 天前
Linux网络基础
linux·网络·arm开发
代码游侠3 天前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
程序猿阿伟3 天前
《Apple Silicon与Windows on ARM:引擎原生构建与模拟层底层运作深度解析》
arm开发·windows
wkm9563 天前
在arm64 ubuntu系统安装Qt后编译时找不到Qt3DExtras头文件
开发语言·arm开发·qt