Search code examples
armembeddedbluetooth-lowenergymicrocontroller

ARM M4 branches to unreadable address immediately after reset


I'm working on a project on a Silicon Labs Thunderboard React (RD0057) which has a EFR32BG1xxxF256 processor on it (Cortex M4).

Recently when I went to program the board and debug, the code immediately goes to a hard fault before entering main. (IACCVIOL and STKERR both set).

I've:

  • Reverted the code to a previous version I know compiled and ran
  • Tried another board I have
  • Used the J-Link adapter to fully erase the flash and reprogram it
  • Tried an empty example project

All to the same result

I then stepped through the code and saw that just after reset the code:

  • starting at address 0xf210000
  • some random seemingly unrelated stuff (4 lines)
  • loads R3 with 0x4
  • loads R2 with R3 (after executing this R2 shows 0xFFFFF in debugger)
  • bx R2 (which branches to ffffffe0, which says "Fail to read memory" and triggers the hard fault)

Tools: - Thunderboard React RD0057 - WSTK 4001A Rev A01 (Functioning as J-Link adapter) - Simplicity Studio - Bluetooth SDK 2.10.1

I need to work out a way to post my code later tonight, but does this issue sound familiar to anyone? I'm thinking it might not be code related because it's happened in known good versions of the project and in empty example projects. Any help is appreciated.

Update 1:

Pastebin of Start of Binary, excerpt first three entries:

007c 0020 4da0 0000 49a0 0000 49a0 0000
49a0 0000 49a0 0000 49a0 0000 49a0 0000
49a0 0000 49a0 0000 49a0 0000 49a0 0000

I checked the binary as suggested, and the first few entries appear to be a vector table (bunch of 0x49A0 which I believe translates to loading addresses into registers).

Then I used the J-link "J-Mem" to read out the memory of the chip. This showed all 0xFFFF's after programming the chip with the IDE (blank chip). I then used the J-Link command line utility to flash the binary file with the start address set to 0x00. Then read back the memory again, and this appears to be successful, with the contents matching the bin file. Executing this shows me getting past that first load and branch that caused the hard fault before, but now hitting another hard fault elsewhere.

  • Need to determine why the IDE is unsuccessful at programming code. Assuming something is set wrong with an offset because it seems to be missing the flash address range altogether.
  • Need to determine where this new hard fault is occurring and if it's the fault of my code or another weird thing.

Solution

  • If you have the gnu binutils built for arm/thumb, take this:

    .thumb
    .thumb_func
    .global _start
    _start:
    .word 0x20001000
    .word reset
    .word hang
    .word hang
    .word hang
    .thumb_func
    reset:
        nop
        nop
        nop
        nop
        nop
        b reset
    .thumb_func
    hang:   b .
    

    build it:

    arm-none-eabi-as flash.s -o flash.o
    arm-none-eabi-ld -Ttext=0 flash.o -o flash.elf
    arm-none-eabi-objdump -D flash.elf > flash.list
    arm-none-eabi-objcopy flash.elf -O binary flash.bin
    

    It doesn't have to be arm-none-eabi; it can be arm-linux-gnueabi or whatever arm-something-something.

    Examine the list file; this is what you are looking for to boot a cortex-m.

    00000000 <_start>:
       0:   20001000    andcs   r1, r0, r0
       4:   00000015    andeq   r0, r0, r5, lsl r0
       8:   00000021    andeq   r0, r0, r1, lsr #32
       c:   00000021    andeq   r0, r0, r1, lsr #32
      10:   00000021    andeq   r0, r0, r1, lsr #32
    
    00000014 <reset>:
      14:   46c0        nop         ; (mov r8, r8)
      16:   46c0        nop         ; (mov r8, r8)
      18:   46c0        nop         ; (mov r8, r8)
      1a:   46c0        nop         ; (mov r8, r8)
      1c:   46c0        nop         ; (mov r8, r8)
      1e:   e7f9        b.n 14 <reset>
    
    00000020 <hang>:
      20:   e7fe        b.n 20 <hang>
    

    First word in flash gets loaded into the stack pointer for you, you can change the stack pointer in your bootstrap code if you want, this just saves a step. The address for reset orred with a 1 is next, has to have the lsbit set. Reset is at 0x0014 above so the reset vector needs to have 0x0014|1 = 0x0015.

    The rest of the vectors don't matter to get you booted. This one puts it in a simple infinite loop which you can halt and resume with your debugger and find it at different addresses hopefully as you repeat halt and resume.

    It is probably easier to load the elf file than the bin file with a debugger, but at the same time the tool might not be writing to flash correctly. Use the tool to dump a few words starting at 0x00000000.

    If your binary does not start with a vector table and/or if the vector table has even numbered addresses in it you will go off the rails immediately after reset. If it does, then you would need to dig further.