尝试读取 STM32F4 上未对齐的 DMA 寄存器地址时出现硬故障
Hardfault when attempting to read unaligned DMA register address on STM32F4
我正在 STM32F4 上实现外设转储。我正在逐字节读取大多数外设寄存器并通过 UART 接口刷新它。它几乎适用于所有外围设备。
当我尝试读取 DMA1 (0x40026000...) 或 DMA2 (0x40026400...) 寄存器时 逐字节 它因精确总线错误而失败在 0x40026401。
当我尝试读取对齐到 4 字节的字时,它工作正常。
我的问题是:为什么它在 DMA 上失败,而所有其他外设(如 SCB、RCC、SPI、UART、TIM 等)允许我这样做?这有什么具体原因吗?
我的猜测是 CPU 和 DMA 控制器之间的总线只允许 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资料sheet:
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 从编程接口的限制。
DM00031020章节10.2 DMA主要特点写的很清楚"AHB slave programming interface supporting only 32-bit accesses"。相反,例如DMA2D支持8位、16位和32位访问,可以逐字节访问,不会引起总线故障。
我正在 STM32F4 上实现外设转储。我正在逐字节读取大多数外设寄存器并通过 UART 接口刷新它。它几乎适用于所有外围设备。
当我尝试读取 DMA1 (0x40026000...) 或 DMA2 (0x40026400...) 寄存器时 逐字节 它因精确总线错误而失败在 0x40026401。
当我尝试读取对齐到 4 字节的字时,它工作正常。
我的问题是:为什么它在 DMA 上失败,而所有其他外设(如 SCB、RCC、SPI、UART、TIM 等)允许我这样做?这有什么具体原因吗?
我的猜测是 CPU 和 DMA 控制器之间的总线只允许 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资料sheet:
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 从编程接口的限制。
DM00031020章节10.2 DMA主要特点写的很清楚"AHB slave programming interface supporting only 32-bit accesses"。相反,例如DMA2D支持8位、16位和32位访问,可以逐字节访问,不会引起总线故障。