Skip to main content
dadman
Associate II
January 21, 2014
Question

Strange STM32L152CBT6 Hard Fault issues

  • January 21, 2014
  • 31 replies
  • 5379 views
Posted on January 21, 2014 at 22:43

Hi all, 

I''ve spent three strange nights of trying to find solution for the following issue.

No success yet.

I'll be very glad for any advice how to solve it.

I've designed a board with STM32L152CBT6 (48pins)

Low power MCU 128kb Flash, 16kb RAM 

Running on 32Mhz HSI

gcc 4.7.2 CodeSourcery, C/C++ with stdlib.

Stack size 0x400

The board contains just the MCU, SWD pins for Segger JLink connection for debugging and CC11001 RF 868Mhz module from Alibaba attached via 2mm spacing header and LED.

The power source is 1A DCDC converter TracoPower 3,3V.

The MCU has proper blocking capacitors 100nf (+1uF for VDDA).

The MCU uses SPI2 (PB12 CS, PB13 CLK, PB14 MISO, PB15 MOSI) and PB5 for IRQ handler EXTI_Line5.

I'm running my RF packet library for the Radio as a test case.

At first I need to mention that the same library/test I'm running without any issue on STMF4 Discovery Kit, self-designed board with STM32F103VC and as well on STM32L152 Discovery board. 

The last STM32L152RBT6 MCU is almost the same MCU with the same memory configuration, just with 64 pins.

So what is the issue:

The issue is Hard Faults during execution. The Hard Fault occurrence is irregular but typically it happens when a packet is sent via RF. Sometimes this is the first packet sometimes it is running stable but when i touch a board the Hard fault occurres. The packet send consumes up to 30mA current.

After three days of testing I have found a workaround how deal with.

It is enough just to put this code during board initialization

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;

GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6;

GPIO_Init(GPIOB, &GPIO_InitStructure);

The code only initializes the pin PB6 as output on already running GPIOB clock.

That's enough. No setting on/off the pin is needed and the board immediately running perfectly stable like on other boards I've mentioned before.

The PB6 is connected via  SMD LED a resistor 750R to ground.

The voltage on the pin is at about 5mV.

When I've tried to remove the LED from board the Hard Fault returned back immediately.

I've tried to build another copy of the board to eliminate the MCU problem, the PCB problem, soldering problem etc.

And the result? The second board has the same strange problem.

Thank you very  much for your advice

Regards

Jakub

#stm-forum-software-pisses-me-off #stm32-hard-fault
    This topic has been closed for replies.

    31 replies

    John F.
    Associate III
    January 22, 2014
    Posted on January 22, 2014 at 17:46

    Is the RF field interfering with the hardware? Can you run a simple program on your second PCB while the first one runs the RF control software and see if it is also affected? Does your PCB and RF transmitter share the same power supply? ... the same ground?

    Does it still fault if you shield the PCB (with grounded aluminium foil for example).

    Tesla DeLorean
    Guru
    January 22, 2014
    Posted on January 22, 2014 at 17:53

    At least you have some consistency.

    You have the EXTI interrupt, might look at how that's configured, I'd move the clearing code to immediately after you've qualified it, otherwise it's likely to re-enter.

    I would focus on getting your Hard Fault handler (look's like Joseph Yiu's) working properly. Identify if ZERO is being passed in, and give a specific message in that case.

    I'd try the Hard Fault stuff off the debugger, let it run the handler, and be getting a very clear idea about what PC/LR come up in the faulting conditions, and then examine the assembler code around the faulting instruction. The C code is far less important.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    dadman
    dadmanAuthor
    Associate II
    January 22, 2014
    Posted on January 22, 2014 at 19:13

    >You have the EXTI interrupt, might look at how that's configured, I'd move the clearing code to immediately after you've qualified it, otherwise it's likely to re-enter.

    This is configuration of my EXTI handler:

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_GD0 ;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource5);

    /* Enable external interrupt */

    EXTI_InitStruct.EXTI_Line = EXTI_Line5;

    EXTI_InitStruct.EXTI_LineCmd = ENABLE;

    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;

    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;

    EXTI_Init(&EXTI_InitStruct);

    /* Enable EXTI interrupts */

    NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;

    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStruct);

    And this a code for EXTI IRQ handler

    void EXTI9_5_IRQHandler(void) {

    if(EXTI_GetITStatus(EXTI_Line5)) {

    if(!rf_transfer_started) {

    rf_transfer_started = 1;

    } else {

    rf_transfer_completed = 1;

    }

    EXTI_ClearITPendingBit(EXTI_Line5);

    }

    }

    >I would focus on getting your Hard Fault handler (look's like Joseph Yiu's) working properly.

    > Identify if ZERO is being passed in, and give a specific message in that case.

    I hope I have the right HardFault handler, I'm using this one https://github.com/feabhas/CM3_Fault_Handler

    The ASM code is that:

    HardFault_Handler:

    TST LR, #4

    ITE EQ

    MRSEQ R0, MSP

    MRSNE R0, PSP

    B Hard_Fault_Handler

    I hope it works well

    In Hard Fault Handler

    SCB->HFSR = 0x40000000

    Forced Hard Fault

    SCB->CFSR = 0x30000

    Usage fault: r0 = 0x20004000

    r1 = 0x800e771

    r2 = 0x800e7c5

    r3 = 0x80001d8

    r12 = 0x800e7d1

    lr = 0x800e7d9

    pc = 0x800e7e1

    psr = 0x0

    All the addresses in registers are the lowest interrupt handlers.

    >I'd try the Hard Fault stuff off the debugger, let it run the handler, and be getting a very clear idea about what PC/LR come up in the faulting conditions, and then examine the assembler code around the faulting instruction. The C code is far less important.

    What do you mean by run it off the debugger? How will I get the result without debugger?

    >You have the EXTI interrupt, might look at how that's configured, I'd move the clearing code to immediately after you've qualified it, otherwise it's likely to re-enter.

    This is configuration of my EXTI handler:

    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_GD0 ;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource5);

    /* Enable external interrupt */

    EXTI_InitStruct.EXTI_Line = EXTI_Line5;

    EXTI_InitStruct.EXTI_LineCmd = ENABLE;

    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;

    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;

    EXTI_Init(&EXTI_InitStruct);

    /* Enable EXTI interrupts */

    NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;

    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStruct);

    And this a code for EXTI IRQ handler

    void EXTI9_5_IRQHandler(void) {

    if(EXTI_GetITStatus(EXTI_Line5)) {

    if(!rf_transfer_started) {

    rf_transfer_started = 1;

    } else {

    rf_transfer_completed = 1;

    }

    EXTI_ClearITPendingBit(EXTI_Line5);

    }

    }

    >I would focus on getting your Hard Fault handler (look's like Joseph Yiu's) working properly.

    > Identify if ZERO is being passed in, and give a specific message in that case.

    I hope I have the right HardFault handler, I'm using this one https://github.com/feabhas/CM3_Fault_Handler

    The ASM code is that:

    HardFault_Handler:

      TST LR, #4

      ITE EQ

      MRSEQ R0, MSP

      MRSNE R0, PSP

      B Hard_Fault_Handler

    I hope it works well

    In Hard Fault Handler

    SCB->HFSR = 0x40000000

    Forced Hard Fault

    SCB->CFSR = 0x30000

    Usage fault: r0  = 0x20004000

    r1  = 0x800e771

    r2  = 0x800e7c5

    r3  = 0x80001d8

    r12 = 0x800e7d1

    lr  = 0x800e7d9

    pc  = 0x800e7e1

    psr = 0x0

    All the addresses in registers are the lowest interrupt handlers.

    >I'd try the Hard Fault stuff off the debugger, let it run the handler, and be getting a very clear idea about what PC/LR come up in the faulting conditions, and then examine the assembler code around the faulting instruction. The C code is far less important.

    What do you mean by run it off the debugger? How will I get the result without debugger?

    dadman
    dadmanAuthor
    Associate II
    January 22, 2014
    Posted on January 22, 2014 at 19:38

    dadman
    dadmanAuthor
    Associate II
    January 22, 2014
    Posted on January 22, 2014 at 19:39

    >Is the RF field interfering with the hardware? Can you run a simple program on your second PCB while the first one runs the RF control software and see if it is also affected?

    I put the RF module standalone and connected it with the main board via 10cm cables. The issue is still here. In the same HW configuration I'm running successfully the code and HW on other STM32 MCUs (F4, F1, STM32L152RBT6). 

    > Does your PCB and RF transmitter share the same power supply? ... the same ground?

    Yes, yes.

    >Does it still fault if you shield the PCB (with grounded aluminium foil for example).

    I'm not able to try it. I think the test with RF board standalone is sufficient.

    But still, If I have configured the PB6 pin the issue is gone.
    Tesla DeLorean
    Guru
    January 22, 2014
    Posted on January 22, 2014 at 19:56

    Off Debugger : Stand-alone with diagnostic information out a serial port

    It's calling your Hard Fault routine with a stack pointer of ZERO, this is not a valid address for it, and it is therefore dumping the content of the FLASH which is shadowed at ZERO.

    Thus

    void

    Hard_Fault_Handler

    (

    uint32_t

    stack

    [])

    Called as Hard_Fault_Handler(NULL);

    You should catch stack == NULL, because the results are useless. I'm not sure if your debugger is causing this, Keil does not.

    http://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/

    Niall Cooling

    cites Yiu

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    dadman
    dadmanAuthor
    Associate II
    January 22, 2014
    Posted on January 22, 2014 at 21:14

    I hope I have the right values:

    In Hard Fault Handler

    SCB->HFSR = 0x40000000

    Forced Hard Fault

    SCB->CFSR = 0x20400

    Usage fault: Bus fault: r0  = 0xf

    r1  = 0x20000fbc

    r2  = 0x20200006

    r3  = 0x200007ac

    r12 = 0x8

    lr  = 0x800a5af

    pc  = 0x800a794

    psr = 0x21000000

    0690X000006055ZQAQ.png

    0690X00000604ZQQAY.png

    Tesla DeLorean
    Guru
    January 23, 2014
    Posted on January 23, 2014 at 02:57

    Yes, that's a bit perplexing, looks to be signalling an INVSTATE

    The code also does not appear to be optimized, but does represent the C, although I can't see the literals it's loading.

    Observe that the address of you Hard Fault Handler in the vector table is EVEN (0x080001D8), this will cause a failure, the entries need to be ODD, indicating THUMB code.

    I2C1_ER_IRQHandler

    I2C2_ER_IRQHandler

    SPI2_IRQHandler
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    dadman
    dadmanAuthor
    Associate II
    January 23, 2014
    Posted on January 23, 2014 at 13:21

    >The code also does not appear to be optimized, but does represent the C, although I can't see the literals it's loading.

    The code is compiled by gcc 4.7.3 with no optimization -O0

    >Observe that the address of you Hard Fault Handler in the vector table is EVEN (0x080001D8), this will cause a failure, the entries need to be ODD, indicating THUMB code.

    Yes, the address was even, so I've wrapped the ASM code to C:

    extern void Hard_Fault_Handler(uint32_t stack[]);

    __attribute__ ((naked)) void HardFault_Handler(void)

    {

    __asm(''MRS r0, MSP'');

    __asm(''B Hard_Fault_Handler'');

    }

    Now the address of the Hard Fault handler is odd and all other handlers as well, see the next picture, the lowest part.

    0690X000006055jQAA.png

    But I'm not sure if it is OK that Eclipse debugger shows the Hardfault handler on the nearest lower even address. See the picture, red frames.

    After the change I had run the code again and GOT SPI2_IRQ. I was very happy but just for one minute. Because the SPI2_IRQ happened just twice from many tens of tests. :-(.

    For example I've got the following result:

    If I have breakpoint at start of the HardFault_handler, I'm able to step the handler and print the stack and so on.

    BUT if I remove the breakpoint the HardFault_handler crashes as shown (purple color).

    You can see that the function ftdi_println() at address 0x800dbcc is not called because the address is changed to 0x840dbcc. Just one bit is changed.

    My interpretations is that this is some memory bus problem because of hw problems.

    The Hard Fault is always caused by touching the PCB by my hand.

    Am I right?

    The faults in the Hard fault handler disallow me to use serial debugging without SWD :-(.

    But for example division by zero fault (manually added to code before the fault critical code)  works well, Hard Fault handler catches it a correctly print to serial port the stack.
    dadman
    dadmanAuthor
    Associate II
    January 24, 2014
    Posted on January 24, 2014 at 13:57

    Today I've tried to more stabilize the hardware used. 

    I have found a solution for stabilizing the MCU without need to initialize PB6.

    The solution is to put Ferrite Bead (Murata 

    BLM18BD152SN1D) on VDD route to the CC1101.

    Before that I have tried to measure some spikes on VDD, communication lines, IRQ lines but without any finding. All looked well. So I dont exactly know how really the bead helped :-(.