cancel
Showing results for 
Search instead for 
Did you mean: 

Hardfault in __libc_init_array with STM32L072

OCout.1
Associate II

Hi,

I'm working on a STM32L072 project, with an environment composed of arm-none-eabi-gcc compiler version 10-2020-q4, make and Eclipse IDE.

I'm having trouble with a hardfault occuring in libc_init_array function call in startup file. Using disassembly in debug mode, I can see that the instruction that causes the issue is "blx r3" which jumps at address 0x0. At this point, the r3 register value is 0x0.

0693W000006Hx7xQAC.pngAccording to ARM documentation, the blx instruction exchange the instruction set. I've then tried to write the libc_init_array function in my project asI thought maybe the external libc_init_array function used was not compiled with the right instruction set.

Though this does not fix my problem, I am able to see that the jump at 0x0 address is due to callback call using an array of callback named "__init_array_start" that is initialized with 0x0, in the libc_init_array function.

0693W000006HxLGQA0.pngI'm now stuck at this point and don't really know where to look next.

I've looked into the linker file and the map file, I've tried to modify compiler and linker options but without success so far.

Also, the compiler optimization flag is set to -O1. Setting it to -Os prevents from entering the libc_init_array harfault at startup but brings up more issues later. Moreover, using optimization is only a short term solution.

Do you have any idea on what is causing this harfault ?

Below is compiler command line and the linker file of the project:

GCC arguments:

"C:\tools\tlc\tlc.git\0.0.30\..\..\\compilers\gcc.git\10-2020-q4-update/bin/arm-none-eabi-gcc" -mthumb -mcpu=cortex-m0plus -march=armv6-m -static -specs=nano.specs -specs=nosys.specs -specs=rdimon.specs -Wl,--gc-sections -mslow-flash-data -DDEBUG -g3 -gdwarf-2 -TC:/Projects/bsp/STM32/stm32L072.git/0.6.0/src/STM32L072CBTX_FLASH.ld -Wl,-Map,src/out/mapfile.map -o "src/out/application.elf" @./src/out/ObjectFiles.txt -lm

Linker file:

/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);	/* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x500;	/* required amount of heap  */
_Min_Stack_Size = 0x500;	/* required amount of stack */
 
/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 128K
  EEPROM   (rw)    : ORIGIN = 0x8080000,   LENGTH = 6K
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
 
  /* The program code and other data into "FLASH" Rom type memory */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)
 
    KEEP (*(.init))
    KEEP (*(.fini))
 
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH
 
  /* Constant data into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
 
  .ARM.extab   : { 
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH
  
  .ARM : {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH
 
  .preinit_array     :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
 
 
  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);
 
  /* Initialized data sections into "RAM" Ram type memory */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
    *(.RamFunc)
 
    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
    
  } >RAM AT> FLASH
 
  SVC_NV_RAM_NB_PAGE = (4);         /* set the number of page you want*/
  SVC_NV_RAM_PAGE_SIZE = (4096);    /* set size of a page, this info is located in the datasheet from the uC*/
  SVC_NV_RAM_SIZE = (SVC_NV_RAM_NB_PAGE * SVC_NV_RAM_PAGE_SIZE);
  .SVC_NV_RAM_SECTION (ORIGIN(FLASH) + LENGTH(FLASH) - (SVC_NV_RAM_SIZE)) (NOLOAD):
  {
      /* align data to a page */
      . = ALIGN(SVC_NV_RAM_PAGE_SIZE);
      *(.SVC_NV_RAM_SECTION)
  } >FLASH
 
  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 
  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
  .ARM.attributes 0 : { *(.ARM.attributes) }
}

You will also find attached the mapfile.

Thanks for your help.

1 ACCEPTED SOLUTION

Accepted Solutions
OCout.1
Associate II

-- Resolved --

Hi,

I've finally found the origin of my problem.

I've realized that my application doesn't crash if I flash it using STM32 ST-Link Utility instead of debugging via Eclipse and .elf file.

The problem was located in the debug configuration where I was using a script called stm32l0.cfg as a argument of openOCD whereas I should have used stm32l0_dual_bank.cfg instead. The latter does include the whole 128ko unlike the first one who is only configured for the first bank of 64ko.

If you don't pay attention to the existence of two configuration files for the stm32l0, it is not obvious to me that the file called "stm32l0.cfg" is only configured for half of the flash capacity of the MCU.

Hope it will help.

Olivier

View solution in original post

6 REPLIES 6
KnarfB
Principal III

__init_array_start marks the start of an array of function pointers. These are used for static constructors in C++ and maybe used for other purposes. There should be definitely no NULL pointer in that array. Thats what happening in your code.

It no so easy what causes this behaviour. You could try to start a new default project for your MCU and compare.

You could also halt the debugger of your project at the very beginning (Reset_Handler) and step through the init code.

AFAIK there is, by default, one function pointer in that init arry, a function named frame_dummy. This could be the one at line 14950 in your mapfile.

Coming from

c:/tools/tlc/compilers/gcc.git/10-2020-q4-update/bin/../lib/gcc/arm-none-eabi/10.2.1/thumb/v6-m/nofp/crtbegin.o

If this isn't a CPP/C++ app you can safely remove the call in startup.s

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

> Coming from ...

Yes, that's the address of frame_dummy.

> If this isn't a CPP/C++ app you can safely remove the call in startup.s

Yes, but this is a symptomatic treatment. The address should not be zero.

OCout.1
Associate II

Hi,

Thank you KnarfB and Tesla DeLorean for your help.

I've been investigated why the __init_array_start array in libc_init_array is 0x0 and it turns out that the complete second half of the flash memory is filled with 0x0. I can see in debug mode that from 0x08010000 to 0x08020000 the flash is empty.

The MCU has a 128ko flash but only 64ko is written although both the map file and the binary use addresses in the second half of the flash. Very confusing to me !

I figured it out by relocating the .preinit_array, .init_array and .fini_array sections in the linker file before the .rodata section. In this confiugration, the libc_init_array does not cause any trouble, given its corresponding flash sections are located in the first 64ko of the Flash. The application will however crash as soon as it uses data from the second half of the flash.

I feel I'm really close to solving my problem but I'm still stuck tyring to find out why the second 64Ko of the flash is not written.

I've found that the mcu has a dual bank feature and perhaps the second bank must be enabled or configured in the linker file or somewhere else.

I've tried to update the linker file by using two separate sections for the first 64ko of the flash (section FLASH) and the second 64ko (section FLASH2). I then assigned .rodata, .ARM.extab and .ARM sections to FLASH2. The result is the same : the second half of the flash is not written.

/**
 ******************************************************************************
 * @file      LinkerScript.ld
 * @author    Auto-generated by STM32CubeIDE
 * @brief     Linker script for STM32L072CBTx Device from STM32L0 series
 *                      128Kbytes FLASH
 *                      20Kbytes RAM
 *
 *            Set heap size, stack size and stack location according
 *            to application requirements.
 *
 *            Set memory bank area and size if external memory is used
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
 
/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);	/* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x500;	/* required amount of heap  */
_Min_Stack_Size = 0x500;	/* required amount of stack */
 
/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 64K
  FLASH2   (rx)    : ORIGIN = 0x8010000,   LENGTH = 64K
  EEPROM   (rw)    : ORIGIN = 0x8080000,   LENGTH = 6K
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
 
  /* The program code and other data into "FLASH" Rom type memory */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)
 
    KEEP (*(.init))
    KEEP (*(.fini))
 
    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH
  
    .preinit_array     :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
 
  /* Constant data into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH2
 
  .ARM.extab   : { 
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH2
  
  .ARM : {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH2
 
 
 
  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);
 
  /* Initialized data sections into "RAM" Ram type memory */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
    *(.RamFunc)
 
    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
    
  } >RAM AT> FLASH2
 
  SVC_NV_RAM_NB_PAGE = (4);         /* set the number of page you want*/
  SVC_NV_RAM_PAGE_SIZE = (4096);    /* set size of a page, this info is located in the datasheet from the uC*/
  SVC_NV_RAM_SIZE = (SVC_NV_RAM_NB_PAGE * SVC_NV_RAM_PAGE_SIZE);
  .SVC_NV_RAM_SECTION (0x08020000 - (SVC_NV_RAM_SIZE))(NOLOAD):
  {
      /* align data to a page */
      . = ALIGN(SVC_NV_RAM_PAGE_SIZE);
      *(.SVC_NV_RAM_SECTION)
  } >FLASH2
 
  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 
  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
  .ARM.attributes 0 : { *(.ARM.attributes) }
}

If you have any idea let me know !

Thanks again.

Olivier

OCout.1
Associate II

-- Resolved --

Hi,

I've finally found the origin of my problem.

I've realized that my application doesn't crash if I flash it using STM32 ST-Link Utility instead of debugging via Eclipse and .elf file.

The problem was located in the debug configuration where I was using a script called stm32l0.cfg as a argument of openOCD whereas I should have used stm32l0_dual_bank.cfg instead. The latter does include the whole 128ko unlike the first one who is only configured for the first bank of 64ko.

If you don't pay attention to the existence of two configuration files for the stm32l0, it is not obvious to me that the file called "stm32l0.cfg" is only configured for half of the flash capacity of the MCU.

Hope it will help.

Olivier

MNewm.1
Associate

Fixed my problem for me. Thanks.