0

I have a problem enabling the MPU on the STM32H745 MCU. I wanted to just disable MPU, set region and then enable it. However, HardFault showed up. I thought it was a matter of wrong region settings. But after commenting, I noticed the problem occurs just by turning on the MPU.

Code:

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;
}

I use just CMSIS API, so I check assembly and 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}

Load UNDEFINED instruction to PC in 0x80003ee? What could cause this compilator(?) error? Has anyone encountered such a problem? How to start of debugging it? Additional debug information below:

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)
  • `so I check assembly` How do you check assembly? What command, and options, did you use? – KamilCuk Jul 17 '21 at 23:11
  • I checked it just via "layout asm" in gdb-multiarch with loaded m7 core .elf file – Wojciech Krupski Jul 17 '21 at 23:46
  • I don't see what you're looking at. The instruction at 0x80003ee is `ldr`, it's not undefined at all and I don't see why you would think it is. There is an undefined instruction at 0x800040c but it's just part of alignment padding. It's not meant to ever be executed (it's after `bx lr`) and I don't see any evidence that it has been. – Nate Eldredge Jul 18 '21 at 15:08
  • ldr r3, [pc, #28] ; (0x800040c ) Is not that mean that addres 0x800040c containing undefined instruction is loaded into PC? – Wojciech Krupski Jul 18 '21 at 15:13
  • @NateEldredge it is not padding it is simple address of the register as Thumb instructiuions do have 32 immediate load – 0___________ Jul 25 '21 at 16:42

2 Answers2

0

The problem was to not set PRIVDEFENA bit. So turning on the MPU as follows helped:

ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
0

It is not the undefined instruction. It is the value (in this case the address of the hardware register block) used by your function. ARM Thumb instructions cannot set the register with 32 bits value, so it has to be stored in the memory and loaded from there.

It is not a bug - it is something very standard.

Example:

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;
}

and generated code:

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

The places where this data is stored and never reached by the code. The same is in your code. It returns from the function before getting tere (bc lr)

If you use the disassembly tool (as you did), it will not understand it and show undefined instructions.

BTW are you using arm-none-eabi-gdb? as it shows nonsense values of the registers,

0___________
  • 60,014
  • 4
  • 34
  • 74