cancel
Showing results for 
Search instead for 
Did you mean: 

Strange STM32L152CBT6 Hard Fault issues

dadman
Associate II
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
31 REPLIES 31
dadman
Associate II
Posted on January 22, 2014 at 17:39

There is no Interrupt vector entry pointing to address 

0x20000

0690X000006052lQAA.png

John F.
Senior
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).

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
Up vote any posts that you find helpful, it shows what's working..
dadman
Associate II
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
Associate II
Posted on January 22, 2014 at 19:38

dadman
Associate II
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.
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
Up vote any posts that you find helpful, it shows what's working..
dadman
Associate II
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

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
Up vote any posts that you find helpful, it shows what's working..
dadman
Associate II
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.