Initialized data in both internal and external RAM

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Initialized data in both internal and external RAM

1,556 Views
carlobramini
Contributor II

Hello,

I'm using an LPC1788 with an SDRAM connected to the external bus and it works fine.

However, I'm facing a problem with initialized data at compile time.

Let's think on a piece of code like this one:

int a = 1; /* This will be allocated into the internal RAM */
int b = 2 __attribute__((section(".ext_ram"))); /* This will be allocated into the external RAM */

The two variables 'a' and 'b' are allocated properly, but I have some troubles to find the right way for initializing their values when the firmware starts. Usually, initialized data is set when the entry point is executed, by using a for() cycle, like this piece of code from lpcopen:

    /*
     * Copy the initialized data of the ".data" segment
     * from the flash to the are in the ram.
     */
    pSrc  = &_etext;
    pDest = &_data;
    while(pDest < &_edata)
    {
        *pDest++ = *pSrc++;
    }

I think that I should duplicate this code also for external memory, but until now I did not get success.

This is my linker script:

/*-----  Stack(s) size / heap size are defined here  ---------*/

   stack_size = 2048;

/*------------------------------------------------------------------------*/
             /* LPC1788 */
MEMORY
{
   FLASH (rx)   : ORIGIN = 0x00000000, LENGTH = 0x00080000
   RAM (rw)     : ORIGIN = 0x10000100, LENGTH = 0x00010000 - 0x100 - 32
   USB_RAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00004000
   ETH_RAM (rw) : ORIGIN = 0x20004000, LENGTH = 0x00004000
   EXT_RAM (rw) : ORIGIN = 0x80000000, LENGTH = 0x00800000
}

ENTRY(ResetHandler)

SECTIONS
{
   .usb_ram (NOLOAD):
   {
     *(.usb_ram)
   } > USB_RAM

   .eth_ram (NOLOAD):
   {
     *(.eth_ram)
   } > ETH_RAM

   .ext_ram :
   {
     *(.ext_ram)
   } > EXT_RAM

   .text :
   {
     _stext = . ;
     *(.reset)                  /* Startup code */
     *(.text)                  /* remaining code */
     *(.rodata)                 /* read-only data (constants) */
     *(.rodata*)
     *(.glue_7)
     *(.glue_7t)
   } > FLASH

   .ARM.exidx : {
     __exidx_start = .;
      *(.ARM.exidx* .gnu.linkonce.armexidx.*)
     __exidx_end = .;
   } > FLASH

   . = ALIGN(4);
   _etext = . ;
   PROVIDE (etext = .);

   /* .data section which is used for initialized data */
   .data : AT (_etext)
   {
     _data = .;
     *(.data)
   } > RAM

   . = ALIGN(4);
   _edata = . ;
   PROVIDE (edata = .);

   /* .bss section which is used for uninitialized data */
   .bss (NOLOAD) :
   {
     __bss_start = . ;
     __bss_start__ = . ;
     *(.bss)
     *(COMMON)
     . = ALIGN(4);
   } > RAM

   . = ALIGN(4);
   __bss_end__ = . ;
   PROVIDE (__bss_end = .);

   .stack_bottom  ALIGN(__bss_end__ , 4) (NOLOAD) :
   {
      __stack__bottom__ = .;
      *(.stack)
   }
   __stack_bottom_end__ = __stack__bottom__  + stack_size ;
   ._estack  ALIGN(__stack_bottom_end__ , 4) (NOLOAD) :
   {
      _estack = .;
      *(.stack)
   }

  _end = . ;
  PROVIDE (end = .);

  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
}

I added an .ext_ram section but this surely needs more information added.

Thank you very much for your time.

Sincerely.

Labels (3)
0 Kudos
5 Replies

1,412 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Carlo Bramini,

Thank you for your interest in NXP Semiconductor products and
the opportunity to serve you.
To provide the fastest possible support, I'd like to suggest you refer to periph_memtest demo in the LPC1788's demo project, the periph_memtest demo shows how to do a memory test for verifying SDRAM operation.

Have a great day,
TIC

 

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,412 Views
carlobramini
Contributor II

Hello,

as I had written in my initial message, the SDRAM is already working fine.

Thank you very much for your replies.

Sincerely.

0 Kudos

1,412 Views
converse
Senior Contributor V

You will need to add a couple of symbols to your linker script so that that you initialisation code can copy the data.

So define your section like this

   .ext_ram :
   {
     _ext_ram_start = . ;
     *(.ext_ram)
   } > EXT_RAM

   . = ALIGN(4) ;
   _ext_ram_end = . ;

and then add your initialisation loop, using _ext_ram_start and _ext_ram_end

0 Kudos

1,412 Views
carlobramini
Contributor II

Hello,

actually, I did that already, but unfortunately it does not work because the constant data is not placed into the .rodata section, so the value to be assigned seems to be lost.

Then, it may happen that some data are initialized, but some data are not.

So, I had also modified the linker script in this way:

   .ext_ram :
   {
     _ext_ram_start = . ;
     *(.ext_ram)
     . = ALIGN(4) ;
     _ext_ram_end = . ;
     _ext_bss_start = . ;
     *(.ext_bss)
     . = ALIGN(4) ;
     _ext_bss_end = . ;

   } > EXT_RAM

and I declared the example variables as:

int b __attribute__((section(".ext_ram"))) = 2; /* This will be allocated into the external RAM (RO)*/
int c __attribute__((section(".ext_bss"))); /* This will be allocated into the external RAM (BSS)*/

But the problem still remains the assignment.

Thank you very much for your support.

Sincerely.

0 Kudos

1,412 Views
converse
Senior Contributor V

I suggest that you take a look at the way that MCUXpresso does this.

The linker, is used to create a table that is then read by the startup code to initialise the data in the various RAM blocks. They key is that data has a load-address (effectively, where it is stored in the flash) and an executable address (where the data needs to be a runtime). It looks like this:

        __data_section_table = .;

        LONG(LOADADDR(.data));

        LONG(    ADDR(.data));

        LONG(  SIZEOF(.data));

        LONG(LOADADDR(.data_RAM2));

        LONG(    ADDR(.data_RAM2));

        LONG(  SIZEOF(.data_RAM2));

        __data_section_table_end = .;

The startup code loops through the table, initialising the data

    unsigned int *SectionTableAddr;

    // Load base address of Global Section Table

    SectionTableAddr = &__data_section_table;

    // Copy the data sections from flash to SRAM.

    while (SectionTableAddr < &__data_section_table_end) {

        LoadAddr = *SectionTableAddr++;

        ExeAddr = *SectionTableAddr++;

        SectionLen = *SectionTableAddr++;

        data_init(LoadAddr, ExeAddr, SectionLen);

    }

(where data_init, is effectively just a memcpy).

0 Kudos