我正在设置 ARMv8 嵌入式系统,并在尝试编译以下代码时偶然发现了一个硬故障:
void test_ram()
{
const uint8_t goldendata[16] = { 0xde, 0xad, 0xba, 0xbe, 0, 0x55, 0x55, 0xaa, 0xaa, 0, 0xff, 0xff };
(void) goldendata;
}
有趣的是,当数组初始化时,我遇到了硬故障(未对齐访问)。 GCC 显然甚至知道访问是未对齐的,正如在 godbolt:
上可以看到的那样使用 GCC 13.2 ARM 编译,选项
-std=c11 -ggdb -ffunction-sections -O0 -ggdb -ffunction-sections -O0 -Wall -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard
为什么 GCC 会生成导致硬故障的数组初始化?
我不确定未对齐的访问是否需要硬故障,因为我发现了冲突的arm文档(未对齐的访问总是错误与错误,如果设置了
UNALIGN_TRP
位):
Arm® v8-M 架构参考手册 DDI0553B.l B6.4 对齐行为
以下是未对齐的数据访问,总是会生成 对齐错误: • 非半字对齐 LDAH、LDREXH、LDAEXH、STLH、 STLEXH 和 STREXH。 • 非字对齐 LDREX、LDAEX、STLEX、STREX、 LDRD、LDMIA、LDMDB、POP(多个寄存器)、LDC、VLDR、VLDM、VPOP、 LDA、STL、STMIA、STMDB、PUSH(多寄存器)、STC、VSTR、VSTM、 VPUSG、VLLDM 和 VLSTM。适用于实施 Armv8.0-M 以后的架构
https://developer.arm.com/documentation/100235/0002/jds1485977091086
未对齐的访问通常比对齐的访问慢。在 此外,某些内存区域可能不支持未对齐访问。 因此,Arm 建议程序员确保访问是 对齐。要捕获意外生成的未对齐访问,请使用 配置和控制寄存器中的 UNALIGN_TRP 位。
我检查了 UNALIGN_TRP 位(位 3),它没有设置,但最终还是出现了错误。 (
gdb x/x 0xE000ED14
=> 0xe000ed14: 0x00000201
)
如果有什么区别的话,使用的 CPU 是 STM32U5 中的 CortexM33。
脚注:我发现可以通过将变量设置为静态(也称为不在堆栈上分配未对齐的数组)或通过向 gcc 传递
-mno-unaligned-access
选项来抑制该问题
事实证明@Nate Eldredge 是对的:
生成了使用CubeMX代码来启用MPU,出于某种原因,Cube选择将内部闪存和内部存储器标记为
Device
。修改手动初始化代码以将内存设置为普通内存修复了该问题。复制意大利面 CubeMX 代码的片段。只需添加属性的宏 INNER_OUTER
即可解决该问题。 (申请Flash和RAM)
HAL_MPU_Disable();
MPU_AttributesInit.Number = MPU_REGION_NUMBER1; // pretty sure this should be MPU_ATTRIBUTES_NUMBER1 but since attributes and region number are defined to the same values, we stick with ST's initialisation here...
MPU_AttributesInit.Attributes = INNER_OUTER( MPU_WRITE_BACK | MPU_TRANSIENT | MPU_RW_ALLOCATE );
HAL_MPU_ConfigMemoryAttributes(&MPU_AttributesInit);