Skip to main content
robertroy9
Associate
August 23, 2012
Question

Hard Fault on first SRAM access

  • August 23, 2012
  • 13 replies
  • 2786 views
Posted on August 23, 2012 at 04:51

Hello,

STM32L152, Rowley CrossStudio 2.3, STM32L152DEMO pcb, Using CrossConnect debugger within CrossStudio.

I have seen this problem before, did not record/understand last time fixed.

What will cause a hard fault on first SRAM access in program (after startup_.s). I have a bunch of static structure global declarations before main, once in main execution hard faults at first SRAM access (usually is a push (R7, lr) ) and those values look reasonable.

Getting VCATCH, IMPRECISERR set, and drops to HardFault (CMSIS version). If I manually set CSB_SHCRS->BUSFAULTENA and rerun it will drop into bus fault handler.

The modified handler returns this:

[Hard fault handler - all numbers in hex]

R0 = 20001940

R1 = 0

R2 = 0

R3 = 0

R12 = 1fffe944

LR [R14] = 20001950  subroutine call return address

PC [R15] = 8000379  program counter

PSR = 80006a0

BFAR = e000ed38

CFSR = 400

HFSR = 40000000

DFSR = 8

AFSR = 0

SCB_SHCSR = 0

Tried making this the first thing in

uint32t *ACTLR = (uint32_t *)0xE000E008;

// *ACTLR |= 2; never executed this 

[Hard fault handler - all numbers in hex]

R0 = 20001940

R1 = 0

R2 = 0

R3 = 0

R12 = e008

LR [R14] = 20001950  subroutine call return address

PC [R15] = 8000177  program counter

PSR = 8000378

BFAR = e000ed38

CFSR = 400

HFSR = 40000000

DFSR = 8

AFSR = 0

SCB_SHCSR = 0

help or thoughtful guidance appreciated.

#stm32-hardfault-impreciserr
    This topic has been closed for replies.

    13 replies

    Tesla DeLorean
    Guru
    August 23, 2012
    Posted on August 23, 2012 at 14:01

    Presumably there is code in startup.s prior to main(), which gets executed and copys/clears out the statics?

    Check the value of SP

    The value for LR seems invalid, coming from RAM and EVEN.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    robertroy9
    Associate
    August 23, 2012
    Posted on August 23, 2012 at 19:00

    Hi Clive,

    Checked that static variablesa are intialized at debug entry to main. (what code initializes them is a mystery)

    Code in debugger looks like this:

    --- main.c -- 95 -------------------------------------------

    static uint8_t bc5RxByte = (uint8_t) 0x5A;

    static uint8_t lbtRxByte = (uint8_t) 0x5B;

    int main(void)

    {

        B580        push {r7, lr}

        B082        sub sp, sp, #8

        AF00        add r7, sp, #0

    --- main.c -- 100 ------------------------------------------

    {

        F5AD533E    sub.w r3, sp, #0x2F80

        F1A3037C    sub.w r3, r3, #0x7C

        F04F0200    mov.w r2, #0

        601A        str r2, [r3]

    --- main.c -- 100 ------------------------------------------

    bc5RxByte = 0x01;

        F240030C    movw r3, #12

        F2C20300    movt r3, #0x2000

        F04F0201    mov.w r2, #1

        701A        strb r2, [r3]

    --- main.c -- 101 ------------------------------------------

    lbtRxByte = 0x01;

        F240030D    movw r3, #13

        F2C20300    movt r3, #0x2000

        F04F0201    mov.w r2, #1

        701A        strb r2, [r3]

    --

    values of trace are as follows.

    static uint8_t bc5RxByte = 0; //memloc = 0x20000149

    static uint8_t lbtRxByte = 0;   //memloc = 0x2000014A

    int main(void) 

    {

    push {r7, lr}, push {0x00000000, 0x08000177}      ... r7=0x00000000, lr=0x08000177

    sub sp, sp, #8, sub 0x20001368, 0x20001950, #8    ... sp=0x20001360

    add r7, sp, #0, 0x00000000, 0x20001360, #0        ... r7=0x20001360, sp=0x20001360

    {

    sub.w r3, sp, #0x2F80, 0x00000009, 0x20001360, #0x2F80      ... r3=0x1fffe3e0

    sub.w r3, r3, #0x7C, 0x1fffe3e0, 0x1fffe3e0, #0x7C          ... r3=0x1fffe364

    mov.w r2, #0, 0x08000361, #0                                ... r2=0x00000000

    str r2, [r3], 0x00000000, 0x1fffe364                        ... r2=0x00000000 r3=0x1fffe364

    ** at this point the SCB_HFSR->FORCED, SCB_BFSR->IMPRECISERR, SCB_ICSR->ISPREEMPT, VECTPENDING=0x003 are set and of course I am then in the hard fault loop.

    Looking in the project settings for preprocessor options of STM32_startup.s , I find

    STM32L15x_HD

    STARTUP_FROM_RESET

    __NO_SYSTEM_INIT

    INITIALIZE_STACK

    I removed STARTUP_FROM_RESET & __NO_SYSTEM_INIT; but see not change in the behavior.

    What is generating the code (before the bc5RxByte = 0x01;) that tries to write to memory is a mystery to me.

    Enlightenment requested!

    Tesla DeLorean
    Guru
    August 23, 2012
    Posted on August 23, 2012 at 19:07

    Guess you need to figure out why it's allocation 12 KB of auto/local variables.

    R3 points into ROM, below RAM, need to make the stack bigger.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    robertroy9
    Associate
    August 23, 2012
    Posted on August 23, 2012 at 19:48

    Changing the stack from 4k to 8k no change.

    Memory Usage shows 6.6K free of 16K in idiot window.

    So you are saying that R3 is determined somewhere in the compiler as a result of the auto/allocation of static variables?

    I thought I could escape learning the startup.s and other particulars but it looks like I was wrong to think one could simply have the Crossworks figure out the bottom end stuff. Suggestions where to read? This is not covered that I see in Yiu's Definitive Guide to the M3 2nd edition.

    Tesla DeLorean
    Guru
    August 23, 2012
    Posted on August 23, 2012 at 20:37

    I don't know what your source looks like, the compiler is generating epilogue code in anticipation of using data/pointers which are 12K below the current stack pointer. From the code presented so far I don't know why.

    Does this work?

    static uint8_t bc5RxByte = (uint8_t) 0x5A;
    static uint8_t lbtRxByte = (uint8_t) 0x5B;
    int main(void)
    {
    bc5RxByte = 0x01;
    lbtRxByte = 0x01;
    while(1);
    }

    You probably need to look at a microprocessor book that describes the concepts of stack frames, local variables and parameter passing. The concepts are the similar across x86, MIPS and ARM, with the RISC parts using registers to pass the first few parameters. I could probably cite a MIPS text that I though covered this well. Other than that, perhaps search on ABI (Application Binary Interface) methods. And compiler's use of epilogue/prologue code, interfacing between assembler and higher level languages.
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    August 23, 2012
    Posted on August 23, 2012 at 20:43

    Introduction to RISC Assembly Language Programming, John Waldron

    http://www.amazon.com/Introduction-RISC-Assembly-Language-Programming/dp/0201398281/

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    August 23, 2012
    Posted on August 23, 2012 at 20:49

    Changing the stack from 4k to 8k no change.

    No doubt, it needs to be at least 12KB to make any difference.

    F5AD533E    sub.w r3, sp, #0x2F80

        F1A3037C    sub.w r3, r3, #0x7C

    0x2F80 + 0x7C = 0x2FFC = 12284 = 11.996 KB

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    robertroy9
    Associate
    August 23, 2012
    Posted on August 23, 2012 at 21:02

    If I comment out the remainder of the program, the offending code is not there. So then there is no hardfault.

    ''generating epilogue'' , so I suppose that I should see a pointer or address in the memory map file that is in code space then? Or is there some other method of tracking this anticipatory action of the compiler...or is it the linker?

    As to the book, I will likely get it <thank you for the pointer> but by God do I really need to understand that domain?

    From: clive1

    Posted: Thursday, August 23, 2012 8:44 PM

    Subject: Hard Fault on first SRAM access

    Introduction to RISC Assembly Language Programming, John Waldron

    http://www.amazon.com/Introduction-RISC-Assembly-Language-Programming/dp/0201398281/

    robertroy9
    Associate
    August 23, 2012
    Posted on August 23, 2012 at 21:08

    Ok, stack to 12384 <I would have never thought of going so large> and no hard fault. Now to figure where this enormous allocation is taking place.

     But back to that little bit of code, where does it hark from?

    int main(void)

    {

        B580        push {r7, lr}

        B082        sub sp, sp, #8

        AF00        add r7, sp, #0

    --- main.c -- 100 ------------------------------------------

    {

        F5AD533E    sub.w r3, sp, #0x2F80

        F1A3037C    sub.w r3, r3, #0x7C

        F04F0200    mov.w r2, #0

        601A        str r2, [r3]

    robertroy9
    Associate
    August 23, 2012
    Posted on August 23, 2012 at 21:22

    Clive,

     If I look at GNU I see something I never wanted to know about but under the circumstances...

    http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gccint/Function-Entry.html

    So you meant the generating prologue code to save <stuff> used by the epilogue code on exit of main? Since this is an embedded app, and exit means reset there is nothing to save. I wonder how I could be mucking that up?

    And many thanks for your insight and help.

    Rob