cancel
Showing results for 
Search instead for 
Did you mean: 

Does Memory Sections in Flash.ld file require a particular sequence? And other Linker stuff

pranjalk197
Associate II

1. I have modified the STMxxx_Flash.ld  linker file by adding some memory sections. Does the sequence of SECTIONS definition matters? LinkerScript.ld and MPU Config Added.
Layout:
ITCM -> Has some functions
DTCM-> non DMA Global Variables
D1 RAM (First 256KB)-> DMA Buffers with Cacheable and Bufferable Disabled in MPU Region
D1 RAM(Last 64KB)-> Data benefitted from caching with Cacheable and Bufferable Enabled in MPU Region

 

image.png



2. Vector Table and ITCM have the same start address (0x0000 0000). I have to do anything or its handled already?

3. Did i modified the heap-stack section correctly for it to work from DTCM.

LinkerScript.ld

 

 

 

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(DTCMRAM) + LENGTH(DTCMRAM);    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x4000;      /* required amount of heap  */
_Min_Stack_Size = 0x8000; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
  ITCMRAM        (xrw)  : ORIGIN = 0x00000000,   LENGTH = 64K
  DTCMRAM        (xrw)  : ORIGIN = 0x20000000,   LENGTH = 128K
  FLASH          (rx)   : ORIGIN = 0x08000000,   LENGTH = 1024K
  RAM_D1         (xrw)  : ORIGIN = 0x24000000,   LENGTH = 256K    /* First 128KB of D1, uncached */
  RAM_D1_CACHED  (xrw)  : ORIGIN = 0x24040000,   LENGTH = 64K     /* Remaining D1 RAM, cached */
  RAM_D2         (xrw)  : ORIGIN = 0x30000000,   LENGTH = 32K
  RAM_D3         (xrw)  : ORIGIN = 0x38000000,   LENGTH = 16K
  BKPSRAM        (xrw)  : ORIGIN = 0x38800000,   LENGTH = 4K   /* Backup SRAM */
}

/* Define output sections */
SECTIONS
{

  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

/* itcm section start--------------------------------------------------------------------------*/
  .itcmram :
  {
    . = ALIGN(4);
    _sitcmram = .;
    KEEP(*(.itcmram))
    _eitcmram = .;
  } >ITCMRAM AT> FLASH
  _sitcmram_init = LOADADDR(.itcmram);
/* itcm section end--------------------------------------------------------------------------*/

/* DTCM RAM section start--------------------------------------------------------------------------*/
  .dtcmram :
  {
    . = ALIGN(4);
    _sdtcmram = .;
    KEEP(*(.dtcmram))
    _edtcmram = .;
  } >DTCMRAM AT> FLASH
  _sdtcmram_init = LOADADDR(.dtcmram);
/* DTCM RAM section end--------------------------------------------------------------------------*/

/* User_heap_stack section, used to check that there is enough RAM left------------------------- */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >DTCMRAM

/* RAM_D1_CACHED RAM section start--------------------------------------------------------------------------*/
/* Cached data section in D1 RAM (last 64KB) */
  .ram_d1_cached :
  {
    . = ALIGN(8);
    _sram_d1_cached_start = .;
    *(.ram_d1_cached)   /* Place your cached data here */
    . = ALIGN(8);
    _sram_d1_cached_end = .;
  } >RAM_D1_CACHED AT> FLASH

  _sram_d1_cached_init = LOADADDR(.ram_d1_cached);
/* RAM_D1_CACHED RAM section end--------------------------------------------------------------------------*/

/* BKPSRAM RAM section start--------------------------------------------------------------------------*/
 .bkp_data (NOLOAD) :
 {
   . = ALIGN(4);
   *(.bkp_data)
   . = ALIGN(4);
 } >BKPSRAM
/* BKPSRAM RAM section end--------------------------------------------------------------------------*/

  /* The program code and other data goes into FLASH */
  .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 goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } >FLASH
  .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH

  .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH

  .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
    *(.RamFunc)        /* .RamFunc sections */
    *(.RamFunc*)       /* .RamFunc* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >DTCMRAM AT> FLASH

  /* Uninitialized data section */
  . = 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;
  } >DTCMRAM

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

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

 

 

Edit: Added startup file

.syntax unified
.cpu cortex-m7
.fpu fpv5-d16                    // Enable hardware FPU
.thumb

.global  g_pfnVectors
.global  Default_Handler

/* Start address for the initialization values of the .data section. Defined in the linker script */
.word  _sidata
/* Start address for the .data section. Defined in the linker script */
.word  _sdata
/* End address for the .data section. Defined in the linker script */
.word  _edata
/* Start address for the .bss section. Defined in the linker script */
.word  _sbss
/* End address for the .bss section. Defined in the linker script */
.word  _ebss
/* Start address for the .itcmram section. Defined in the linker script */
.word  _sitcmram
/* End address for the .itcmram section. Defined in the linker script */
.word  _eitcmram
/* Start address for the initialization values of the .itcmram section. Defined in the linker script */
.word  _sitcmram_init
/* Start address for the .dtcmram section. Defined in the linker script */
.word  _sdtcmram
/* End address for the .dtcmram section. Defined in the linker script */
.word  _edtcmram
/* Start address for the initialization values of the .dtcmram section. Defined in the linker script */
.word  _sdtcmram_init
/* Start address for the initialization values of the .ram_d1_cached section. Defined in the linker script */
.word  _sram_d1_cached_init
/* Start address for the .ram_d1_cached section. Defined in the linker script */
.word  _sram_d1_cached_start
/* End address for the .ram_d1_cached section. Defined in the linker script */
.word  _sram_d1_cached_end
/* Stack used for SystemInit_ExtMemCtl; always internal RAM used */

/**
 * @brief  This is the code that gets called when the processor first
 *         starts execution following a reset event. Only the absolutely
 *         necessary setup is performed, after which the application
 *         supplied main() routine is called.
 * @PAram  None
 * @retval None
 */
.section  .text.Reset_Handler
.weak  Reset_Handler
.type  Reset_Handler, %function
Reset_Handler:
  ldr   sp, =_estack      /* Set stack pointer */

/* Call the clock system initialization function. */
  bl  SystemInit

/* Copy the data segment initializers from flash to SRAM */
  ldr r0, =_sdata
  ldr r1, =_edata
  ldr r2, =_sidata
  movs r3, #0
  b LoopCopyDataInit

CopyDataInit:
  ldr r4, [r2, r3]
  str r4, [r0, r3]
  adds r3, r3, #4

LoopCopyDataInit:
  adds r4, r0, r3
  cmp r4, r1
  bcc CopyDataInit

/* Copy the itcmram segment initializers from flash to ITCMRAM */
  ldr r0, =_sitcmram     /* Start address in ITCMRAM */
  ldr r1, =_eitcmram     /* End address in ITCMRAM */
  ldr r2, =_sitcmram_init/* Start address of initialization values in Flash */
  movs r3, #0
  b LoopCopyItcmramInit

CopyItcmramInit:
  ldr r4, [r2, r3]       /* Load word from Flash (_sitcmram_init) */
  str r4, [r0, r3]       /* Store word to ITCMRAM (_sitcmram) */
  adds r3, r3, #4        /* Increment offset */

LoopCopyItcmramInit:
  adds r4, r0, r3        /* Check if all data is copied */
  cmp r4, r1             /* Compare with end of ITCMRAM (_eitcmram) */
  bcc CopyItcmramInit    /* If not finished, continue copying */

/* Copy the dtcmram segment initializers from flash to DTCMRAM */
  ldr r0, =_sdtcmram     /* Start address in DTCMRAM */
  ldr r1, =_edtcmram     /* End address in DTCMRAM */
  ldr r2, =_sdtcmram_init/* Start address of initialization values in Flash */
  movs r3, #0
  b LoopCopyDtcmramInit

CopyDtcmramInit:
  ldr r4, [r2, r3]       /* Load word from Flash (_sdtcmram_init) */
  str r4, [r0, r3]       /* Store word to DTCMRAM (_sdtcmram) */
  adds r3, r3, #4        /* Increment offset */

LoopCopyDtcmramInit:
  adds r4, r0, r3        /* Check if all data is copied */
  cmp r4, r1             /* Compare with end of DTCMRAM (_edtcmram) */
  bcc CopyDtcmramInit    /* If not finished, continue copying */

/* Copy the ram_d1_cached segment initializers from flash to RAM_D1_CACHED */
  ldr r0, =_sram_d1_cached_start /* Start address in RAM_D1_CACHED */
  ldr r1, =_sram_d1_cached_end   /* End address in RAM_D1_CACHED */
  ldr r2, =_sram_d1_cached_init  /* Start address of initialization values in Flash */
  movs r3, #0
  b LoopCopyRamD1CachedInit

CopyRamD1CachedInit:
  ldr r4, [r2, r3]       /* Load word from Flash (_sram_d1_cached_init) */
  str r4, [r0, r3]       /* Store word to RAM_D1_CACHED (_sram_d1_cached_start) */
  adds r3, r3, #4        /* Increment offset */

LoopCopyRamD1CachedInit:
  adds r4, r0, r3        /* Check if all data is copied */
  cmp r4, r1             /* Compare with end of RAM_D1_CACHED (_sram_d1_cached_end) */
  bcc CopyRamD1CachedInit /* If not finished, continue copying */

/* Zero fill the bss segment */
  ldr r2, =_sbss
  ldr r4, =_ebss
  movs r3, #0
  b LoopFillZerobss

FillZerobss:
  str  r3, [r2]
  adds r2, r2, #4

LoopFillZerobss:
  cmp r2, r4
  bcc FillZerobss

/* Call static constructors */
  bl __libc_init_array
/* Call the application's entry point */
  bl  main
  bx  lr
.size  Reset_Handler, .-Reset_Handler

 

 

 

 

3 REPLIES 3

Order matters in processing the linker script as it is processed in a linear fashion.

It's also necessary to add code in startup.s to initialize things properly, move data around and clear things.

Better implementations create tables the startup code can process/unpack more automatically. Look at how Arduino manages this with the GNU tools.

You'd want to a) review the .MAP to see what the linker is up to and b) review the .ELF to understand what the linker built. Check tools like OBJCOPY and OBJDUMP to confirm/validate what's going on.

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

I modified the startup file. I will check Arduino implementation. But, what I have no starting point how the sequencing of SECTIONS should be.

how the sequencing of SECTIONS should be.

Linker scatters each input object file (for example main.o) to sections (text, data etc.) then scans the link script to find the target section of each source section. The first match wins. This is why the order of sections and filters in the link script is important. Most specific filters (that contain exact section name) should go first.