2024-09-22 03:15 AM - edited 2024-09-22 07:15 AM
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
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
2024-09-22 06:10 AM
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.
2024-09-22 07:13 AM - edited 2024-09-22 07:16 AM
I modified the startup file. I will check Arduino implementation. But, what I have no starting point how the sequencing of SECTIONS should be.
2024-09-22 12:32 PM
> 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.