Почему в компьютер загружается адрес, содержащий неопределенную инструкцию? - STM32H745
У меня проблема с включением MPU на MCU STM32H745. Я хотел просто отключить MPU, установить регион, а затем включить его. Однако появился HardFault. Думал, дело в неправильных настройках региона. Но после комментариев я заметил, что проблема возникает просто при включении MPU.
Код:
static syslog_status_t setMPU_sysLog(void)
{
[...]
ARM_MPU_Disable();
/* ARM_MPU_SetRegion(ARM_MPU_RBAR(0, (uint32_t)NON_CACHABLE_RAM4_D3_BASE_ADDR),
ARM_MPU_RASR(0UL, ARM_MPU_AP_FULL, 1UL, 0UL, 0UL, 1UL, 0x00UL, ARM_MPU_REGION_SIZE_8KB)); */
HALT_IF_DEBUGGING();
ARM_MPU_Enable(0);
return SYSLOG_OK;
}
Я использую только CMSIS API, поэтому проверяю сборку и woops:
>0x80003ec <setMPU_sysLog+36> bkpt 0x0001
0x80003ee <setMPU_sysLog+38> ldr r3, [pc, #28] ; (0x800040c <setMPU_sysLog+68>)
0x80003f0 <setMPU_sysLog+40> movs r2, #1
0x80003f2 <setMPU_sysLog+42> str.w r2, [r3, #148] ; 0x94
0x80003f6 <setMPU_sysLog+46> ldr r2, [r3, #36] ; 0x24
0x80003f8 <setMPU_sysLog+48> orr.w r2, r2, #65536 ; 0x10000
0x80003fc <setMPU_sysLog+52> str r2, [r3, #36] ; 0x24
0x80003fe <setMPU_sysLog+54> dsb sy
0x8000402 <setMPU_sysLog+58> isb sy
0x8000406 <setMPU_sysLog+62> movs r0, #0
0x8000408 <setMPU_sysLog+64> bx lr
0x800040a <setMPU_sysLog+66> nop
0x800040c <setMPU_sysLog+68> ; <UNDEFINED> instruction: 0xed00e000
0x8000410 <initSysLog> push {r3, lr}
Загрузить НЕОПРЕДЕЛЕННУЮ инструкцию на ПК в 0x80003ee? Что могло вызвать эту ошибку компилятора (?)? Кто-нибудь сталкивался с такой проблемой? Как начать его отладку? Дополнительная информация об отладке ниже:
0x08000398 in my_fault_handler_c (frame=0x2001ffb0) at CM7/exceptionHandlers.c:29
29 HALT_IF_DEBUGGING();
(gdb) p/a *frame
$1 = {r0 = 0xde684c0e, r1 = 0x6cefc92c, r2 = 0xed5b5cfb, r3 = 0xa3feeed1, r12 = 0xef082047, lr = 0xd7121a9e, return_address = 0xf16a13cf, xpsr = 0xf60e2caf}
Fields in SCB > HFSR:
VECTTBL: 0 Vector table hard fault
FORCED: 1 Forced hard fault
DEBUG_VT: 0 Reserved for Debug use
Fields in SCB > CFSR_UFSR_BFSR_MMFSR:
IACCVIOL: 1
DACCVIOL: 0
MUNSTKERR: 0
MSTKERR: 1
MLSPERR: 0
MMARVALID: 0
IBUSERR: 0 Instruction bus error
PRECISERR: 0 Precise data bus error
IMPRECISERR: 0 Imprecise data bus error
UNSTKERR: 0 Bus fault on unstacking for a return from exception
STKERR: 0 Bus fault on stacking for exception entry
LSPERR: 0 Bus fault on floating-point lazy state preservation
BFARVALID: 0 Bus Fault Address Register (BFAR) valid flag
UNDEFINSTR: 0 Undefined instruction usage fault
INVSTATE: 0 Invalid state usage fault
INVPC: 0 Invalid PC load usage fault
NOCP: 0 No coprocessor usage fault.
UNALIGNED: 0 Unaligned access usage fault
DIVBYZERO: 0 Divide by zero usage fault
arm-none-eabi-gcc -v
cc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major)
2 ответа
Проблема заключалась в том, чтобы не установить бит PRIVDEFENA. Итак, включение MPU помогло:
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
Это не неопределенная инструкция. Это значение (в данном случае адрес блока аппаратного регистра), используемое вашей функцией. Инструкции ARM Thumb не могут установить регистр с 32-битным значением, поэтому он должен быть сохранен в памяти и загружен оттуда.
Это не ошибка - это что-то очень стандартное.
Пример:
typedef struct
{
volatile uint32_t reg1;
volatile uint32_t reg2;
}MYREG_t;
#define MYREG ((MYREG_t *)0xed00e000)
void foo(uint32_t val)
{
MYREG -> reg2 = val;
}
void bar(uint32_t val)
{
MYREG -> reg1 = val;
}
и сгенерированный код:
foo:
ldr r3, .L3
str r0, [r3, #4]
bx lr
.L3:
.word -318709760
bar:
ldr r3, .L6
str r0, [r3]
bx lr
.L6:
.word -318709760
Места, где эти данные хранятся и никогда не доступны для кода. То же самое и в вашем коде. Он возвращается из функции до получения tere (
bc lr
)
Если вы воспользуетесь инструментом разборки (как и вы), он его не поймет и покажет неопределенные инструкции.
Кстати, вы используете arm-none-eabi-gdb? поскольку он показывает бессмысленные значения регистров,