RTOS, Extended memory, C++ and Static initializers

cancel
Showing results for 
Search instead for 
Did you mean: 

RTOS, Extended memory, C++ and Static initializers

829 Views
ocmonte
Contributor III

Hello Group,

The subject line is a mouthful, but we have an interesting problem and I need to understand what is happening.

We are using a K60 line CPU with extended memory with FreeRTOS.

The System:

  • Using Processor Expert
  • Have 512K of external memory
  • FreeRTOS heap is pointing to the extended memory using PE at 0x60000000 using scheme 4
  • We are using C/C++ (porting code from another project and it's very C++ish)

The problem is we suddenly cannot use certain classes in initializers (constructor or module) specifically std::string.

Ex (module initializer):

    #include "string"

    std::string myString = "Hello World";

    void SomeFunctions(){  }

Looking at the assembly where the fault is caused by add.w r3, r7, #12 where r3 = 0xffff and r7 - 0x1fffffd0

The initialization string myString causes a system fault. Now for the questions:

  • This is using std::string - is it possible something in the class has not been initialized yet?
  • What would cause such a fault and what is the best way to figure out what is causing it?
  • Since we are using FreeRTOS, what happends to the default heap defined in the CPU section of PE?

Hints would be greatly appreciated.

Cheers,

Monte---

0 Kudos
7 Replies

336 Views
ocmonte
Contributor III

It looks like the I cannot call the pvPortMalloc (heap_4.c) before the C/C++ initialization (__start()) is complete.  So I gather I need to somehow place the standard C heap in a specific location of memory (0x60000000 - not sure if that's possible).

* overloading of malloc/alloc have not done. Need to look into that.

Monte---

0 Kudos

336 Views
ocmonte
Contributor III

Hello Hao,

Currently we have external RAM at 0x60000000 and I have FreeRTOS heap manager  (Scheme 4) pointing to that segment. Again, I have **overloaded** new and delete to use FreeRTOS's memory management. When I don't have module initializers, the memory managemen works fine. When I do it does not.

Below is the printsize and linker file

TIA

Monte---

'Invoking: Cross ARM GNU Print Size'

arm-none-eabi-size --format=sysv --totals -x "CloverleafOG.elf"

CloverleafOG.elf  :

section                 size         addr

.interrupts            0x1e0          0x0

.cfmprotect             0x10        0x400

.text                0x3be84        0x410

.ARM.extab            0x2b60      0x3c294

.ARM                  0x2030      0x3edf4

.init_array             0x18      0x40e24

.fini_array              0x4      0x40e3c

.data                  0x1c0   0x1fff0000

.m_data_60000000     0x20000   0x60000000

.bss                  0x1604   0x1fff0200

.romp                   0x30   0x1fff1804

._user_heap_stack     0x4400   0x1fff1834

.ARM.attributes         0x2a          0x0

.debug_info         0x11f5fc          0x0

.debug_abbrev        0x1599f          0x0

.debug_aranges        0x6750          0x0

.debug_ranges         0x6268          0x0

.debug_macro         0x4325e          0x0

.debug_line          0x3b5e9          0x0

.debug_str          0x116e11          0x0

.comment                0x70          0x0

.debug_frame         0x1a960          0x0

.stab                   0xcc          0x0

.stabstr               0x1b9          0x0

Total               0x35843e

/* ################################################################### */

/*##

/*##     This component module is generated by Processor Expert. Do not modify it. */

/*##                                   */

/*##     Filename  : ProcessorExpert.ld */

/*##                                   */

/*##     Project   : CloverleafOG      */

/*##                                   */

/*##     Processor : MK60DN512VLL10    */

/*##                                   */

/*##     Compiler  : GNU C Compiler    */

/*##                                   */

/*##     Date/Time : 2015-08-18, 19:57, # CodeGen: 147 */

/*##                                   */

/*##     Abstract  :                   */

/*##                                   */

/*##     This file is used by the linker. It describes files to be linked, */

/*##     memory ranges, stack size, etc. For detailed description about linker */

/*##     command files see compiler documentation. This file is generated by default. */

/*##     You can switch off generation by setting the property "Generate linker file = no" */

/*##     in the "Build options" tab of the CPU component and then modify this file as needed. */

/*##

/*##                                   */

/*## ###################################################################*/

 

/* Entry Point */

ENTRY(__thumb_startup)

/* Highest address of the user mode stack */

_estack = 0x20000000;    /* end of m_data */

__SP_INIT = _estack;

__stack = _estack;

/* Generate a link error if heap and stack don't fit into RAM */

__heap_size = 0x0400;                  /* required amount of heap  */

__stack_size = 0x4000;                 /* required amount of stack */

MEMORY {

  m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x000001E0

  m_text      (RX) : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0

  m_data      (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000

  m_data_20000000 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000

  m_data_60000000 (RW) : ORIGIN = 0x60000000, LENGTH = 0x00080000

  m_cfmprotrom  (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010

}

/* Define output sections */

SECTIONS

{

  /* The startup code goes first into INTERNAL_FLASH */

  .interrupts :

  {

    __vector_table = .;

    . = ALIGN(4);

    KEEP(*(.vectortable)) /* Startup code */

    . = ALIGN(4);

  } > m_interrupts

  .cfmprotect :

  {

    . = ALIGN(4);

KEEP(*(.cfmconfig)) /* Flash Configuration Field (FCF) */

. = ALIGN(4);

  } > m_cfmprotrom

 

  /* The program code and other data goes into INTERNAL_FLASH */

  .text :

  {

    . = ALIGN(4);

    *(.text)           /* .text sections (code) */

    *(.text*)          /* .text* sections (code) */

    *(.rodata)         /* .rodata sections (constants, strings, etc.) */

    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */

    *(.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 */

  } > m_text

   .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > m_text

    .ARM : {

    __exidx_start = .;

      *(.ARM.exidx*)

      __exidx_end = .;

  } > m_text

.ctors :

  {

    __CTOR_LIST__ = .;

    /* gcc uses crtbegin.o to find the start of

       the constructors, so we make sure it is

       first.  Because this is a wildcard, it

       doesn't matter if the user does not

       actually link against crtbegin.o; the

       linker won't look for a file to match a

       wildcard.  The wildcard also means that it

       doesn't matter which directory crtbegin.o

       is in.  */

    KEEP (*crtbegin.o(.ctors))

    /* We don't want to include the .ctor section from

       from the crtend.o file until after the sorted ctors.

       The .ctor section from the crtend file contains the

       end of ctors marker and it must be last */

    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))

    KEEP (*(SORT(.ctors.*)))

    KEEP (*(.ctors))

    __CTOR_END__ = .;

  } > m_text

  .dtors :

  {

    __DTOR_LIST__ = .;

    KEEP (*crtbegin.o(.dtors))

    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))

    KEEP (*(SORT(.dtors.*)))

    KEEP (*(.dtors))

    __DTOR_END__ = .;

  } > m_text

  .preinit_array     :

  {

    PROVIDE_HIDDEN (__preinit_array_start = .);

    KEEP (*(.preinit_array*))

    PROVIDE_HIDDEN (__preinit_array_end = .);

  } > m_text

  .init_array :

  {

    PROVIDE_HIDDEN (__init_array_start = .);

    KEEP (*(SORT(.init_array.*)))

    KEEP (*(.init_array*))

    PROVIDE_HIDDEN (__init_array_end = .);

  } > m_text

  .fini_array :

  {

    PROVIDE_HIDDEN (__fini_array_start = .);

    KEEP (*(SORT(.fini_array.*)))

    KEEP (*(.fini_array*))

    PROVIDE_HIDDEN (__fini_array_end = .);

___ROM_AT = .;

  } > m_text

  /* Initialized data sections goes into RAM, load LMA copy after code */

  .data : AT(___ROM_AT)

  {

    . = ALIGN(4);

    _sdata = .;        /* create a global symbol at data start */

    *(.data)           /* .data sections */

    *(.data*)          /* .data* sections */

    . = ALIGN(4);

    _edata = .;        /* define a global symbol at data end */

  } > m_data

  ___data_size = _edata - _sdata;

  ___m_data_20000000_ROMStart = ___ROM_AT + SIZEOF(.data);

  .m_data_20000000 : AT(___m_data_20000000_ROMStart)

  {

     . = ALIGN(4);

     ___m_data_20000000_RAMStart = .;

     *(.m_data_20000000) /* This is an User defined section */

     ___m_data_20000000_RAMEnd = .;

     . = ALIGN(4);

  } > m_data_20000000

  ___m_data_20000000_ROMSize = ___m_data_20000000_RAMEnd - ___m_data_20000000_RAMStart;

 

  ___m_data_60000000_ROMStart = ___m_data_20000000_ROMStart + SIZEOF(.m_data_20000000);

  .m_data_60000000 : AT(___m_data_60000000_ROMStart)

  {

     . = ALIGN(4);

     ___m_data_60000000_RAMStart = .;

     *(.m_data_60000000) /* This is an User defined section */

     ___m_data_60000000_RAMEnd = .;

     . = ALIGN(4);

  } > m_data_60000000

  ___m_data_60000000_ROMSize = ___m_data_60000000_RAMEnd - ___m_data_60000000_RAMStart;

 

 

  /* Uninitialized data section */

  . = ALIGN(4);

  .bss :

  {

    /* This is used by the startup in order to initialize the .bss section */

    __START_BSS = .;

  PROVIDE ( __bss_start__ = __START_BSS );

    *(.bss)

    *(.bss*)

    *(COMMON)

    . = ALIGN(4);

    __END_BSS = .;

    PROVIDE ( __bss_end__ = __END_BSS );

  } > m_data

  _romp_at = ___ROM_AT + SIZEOF(.data) +SIZEOF(.m_data_20000000) +SIZEOF(.m_data_60000000);

  .romp : AT(_romp_at)

  {

    __S_romp = _romp_at;

    LONG(___ROM_AT);

    LONG(_sdata);

    LONG(___data_size);

    LONG(___m_data_20000000_ROMStart);

    LONG(___m_data_20000000_RAMStart);

    LONG(___m_data_20000000_ROMSize);

    LONG(___m_data_60000000_ROMStart);

    LONG(___m_data_60000000_RAMStart);

    LONG(___m_data_60000000_ROMSize);

    LONG(0);

    LONG(0);

    LONG(0);

  } > m_data

 

  /* User_heap_stack section, used to check that there is enough RAM left */

  ._user_heap_stack :

  {

    . = ALIGN(4);

    PROVIDE ( end = . );

    PROVIDE ( _end = . );

    __heap_addr = .;

    __HeapBase = .;

    . = . + __heap_size;

    __HeapLimit = .;

    . = . + __stack_size;

    . = ALIGN(4);

  } > m_data

  .ARM.attributes 0 : { *(.ARM.attributes) }

}

0 Kudos

336 Views
sergeisharonov
Contributor III

> ..Again, I have **overloaded** new and delete to use FreeRTOS's memory management...

Have you also **overloaded** malloc and free? Newlib calls these behind your back during startup before main(). Not sure how/if this interacts with your constructors but worth a try.

Sergei

0 Kudos

336 Views
cutworth
NXP Employee
NXP Employee

Hi Monte,

I am not sure if I am pointing to the right direction. But from the address 0x1fffffd0 where you see system fault, mystring allocates variable close to internal SRAM boundary and it could cross that boundary. K60's internal SRAM is divided as two half, with 0x2000_0000 in middle, so when you have 128KB SRAM, it's from 0x1ffff_0000 to 0x2000_ffff. Allocating variable cross the boundary and then later access it has problem. Please check if the system fault generated is hard fault or not.

Maybe you could shared the linker file,  is it the default one generated by PE? Find in memory map where mystring is really allocated in RAM.

Hao

0 Kudos

336 Views
ocmonte
Contributor III

Hi Sergei,

Thanks for your suggestion. heap_4.c does know and seems to create the buffer at the correct location. Since this initialization is performed during the C startup (FRTOS has not been initialized) and I've overridden the new and delete with FRTOS calls, I'm beginning to believe that there is an initialization problem (maybe). If I remove the module initialization and create dynamic memory at run time (opposed to C initialization time) all works well.

I'm still looking into the problem.

0 Kudos

336 Views
ocmonte
Contributor III

[update]

I've narrowed down to FreeRTOS. I've overloaded new and delete functions to call pvPortMalloc and vPortFree. It looks like the code makes an effort to initialize the heap when it's called for the first time. However I'm wondering if this is really true. I do get weirdness when stepping through the code.

I'll update when more is known.

0 Kudos

336 Views
sergeisharonov
Contributor III

Did you teach heap_4.c where your heap is located?

0 Kudos