c - 尝试读取 STM32F4 上未对齐的 DMA 寄存器地址时出现硬故障

标签 c arm stm32 dma

我正在 STM32F4 上实现外设转储。我正在逐字节读取大多数外设寄存器,并通过 UART 接口(interface)刷新它。它几乎适用于所有外围设备。

当我尝试逐字节读取 DMA1 (0x40026000...) 或 DMA2 (0x40026400...) 寄存器时,它会失败,并在 0x40026401 处出现精确的总线错误。

当我尝试读取与 4 字节单词对齐的内容时,它工作正常。

我的问题是:为什么它在 DMA 上失败,而所有其他外设(如 SCB、RCC、SPI、UART、TIM 等)都允许我这样做?这有什么具体原因吗?

最佳答案

我的猜测是 CPU 和 DMA Controller 之间的总线仅允许 32 位访问操作。

您可以从硬故障中断内部打印(或转储到内存)。

您需要打印(或转储)的是 CPU 寄存器,特别是那些可以让您更好地了解问题所在的寄存器。

例如:

void HardFault_Handler(unsigned int* hardfault_args)
{
    printf("R0    = 0x%.8X\r\n",hardfault_args[0]);         
    printf("R1    = 0x%.8X\r\n",hardfault_args[1]);         
    printf("R2    = 0x%.8X\r\n",hardfault_args[2]);         
    printf("R3    = 0x%.8X\r\n",hardfault_args[3]);         
    printf("R12   = 0x%.8X\r\n",hardfault_args[4]);         
    printf("LR    = 0x%.8X\r\n",hardfault_args[5]);         
    printf("PC    = 0x%.8X\r\n",hardfault_args[6]);         
    printf("PSR   = 0x%.8X\r\n",hardfault_args[7]);         
    printf("BFAR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED38);
    printf("CFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED28);
    printf("HFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED2C);
    printf("DFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED30);
    printf("AFSR  = 0x%.8X\r\n",*(unsigned int*)0xE000ED3C);
    printf("SHCSR = 0x%.8X\r\n",SCB->SHCSR);                
    while (1);
}

或者您可以简单地停止在硬故障中断内,并在 IDE 中查看这些寄存器...

来自 STM32F4 数据表:

The MPU attributes don't affect DMA data accesses to the memory/peripherals address
spaces. therefore, in order to protect the memory areas against inadvertent DMA accesses,
the MPU must control the SW/CPU access to the DMA registers.

因此看起来在访问 DMA 寄存器方面存在一些具体限制。

<小时/>

OP根据PaulR的评论扩展答案:

文档挖掘证实原因是 DMA AHB 从机编程接口(interface)的限制。

在DM00031020章节10.2 DMA主要特性中明确写着“AHB从机编程接口(interface)仅支持32位访问”。相反,例如DMA2D支持8位、16位和32位访问,因此可以逐字节访问,不会导致总线故障。

关于c - 尝试读取 STM32F4 上未对齐的 DMA 寄存器地址时出现硬故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47439458/

相关文章:

创建新的 tcp 套接字 - 服务器端

c - "Cannot access memory at address 0x600b0c"& "No symbol "n "in current context."如果使用 gdb 编译时存在全局变量和局部变量

c++ - 跳过代码不使用状态变量,设想使用goto

c - AlchemyAPI C 无法在 Ubuntu 上编译 - 特别是 keywordspp

image-processing - 在 SIMD 中矢量化直方图的方法?

rust - "undefined reference to ` __stat_time64 '"在 musl 1.2.0 上交叉编译 Rust 项目时

gcc - arm gcc工具链为arm-elf或arm-none-eabi,有什么区别?

c - STM32创建RAM段

arm - 如何在STM32F0上初始化I2C?

c - 了解嵌入式 C 中命令 *__SIMD32(pIn)++ 的执行