2021-01-05 02:59 PM
Hello everybody! I need to store dataset into the RAM of my MCU. I use STM32H755ZIT6, Dual Core M7+M4. The problem is that when I define buffer for my data the ram will overflow. The Ram size is 1MB but the whole data set's size is around 250KB. it seems that the RAM is not contiguous and based on my search on the internet the clue I have is to use Core Coupled Memory RAM. Around 2/3 of my data fits into the RAM and I want to store the rest of it into the CCRAM area. Sofar I unly could understood that using this statement I can store variable in CCRAM:
__attribute__((section(".ccmram-strings"))) float Data_Set_Z[15000];
When I want to assign a value into this variable, the compiler shows the RAM overflow error. I read some application notes of ST and some block of memories have different address but I don't know how to use the in linker script.
Here is the Linker script file:
here is also the RAM.ld file
/*
******************************************************************************
**
** File : LinkerScript.ld
**
**
** Abstract : Linker script for STM32H7 series
** 256Kbytes RAM_EXEC and 256Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2019 STMicroelectronics.
** All rights reserved.
**
** 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 = 0x24080000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM_EXEC (rx) : ORIGIN = 0x24000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x24040000, LENGTH = 256K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into RAM_EXEC */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >RAM_EXEC
/* The program code and other data goes into RAM_EXEC */
.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 */
} >RAM_EXEC
/* Constant data goes into RAM_EXEC */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >RAM_EXEC
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM_EXEC
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >RAM_EXEC
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >RAM_EXEC
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >RAM_EXEC
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >RAM_EXEC
/* 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 */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> RAM_EXEC
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_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 left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
another thing I am considering is that the RAM blocks are as follows:
based on Linker script file I mentioned before, a 256KB block is only used . that is the reason of RAM overflow ,I think... .
2) How Can I use a bigger block? for example the block the name of which is SRAM mapped onto AXI bus 512 in the table below?
Despite the searches I did I could not understand how to change the linker-script files. Is there anybody who has time to help me regarding the mentioned two questions??
I think the more logical choice is to just select the bigger RAM In D1 domain which is also provided to M7 Core I am using ....
I tried changing the address space of the ram in the .ld file . at first, it was from /* : ORIGIN = 0x24000000, LENGTH = 256K */ to /* : ORIGIN = 0x24040000, LENGTH = 256K */.
then I changed it from 0x24000000, LENGTH = 512K to : ORIGIN = 0x2407FFFF, LENGTH = 512K according to memory-map file in the user manuals but after biulding the project I still get the ram overflow messege...... Please Help :)))
here are the error messeges.
Looking forward to your replies.
Best Regards
2021-01-05 04:03 PM
This explains it well. You need to add a definition for the CCMRAM section.
https://www.openstm32.org/Using+CCM+Memory?structure=Documentation
2021-01-05 04:19 PM
Thanks, before posting here I red this page but since I am a beginner I confused and could not exactly understand what I am supposed to do ... .
2021-01-05 05:21 PM
If you want to initialize the data you'll have to work harder, and fix startup.s too.
Anyway, the following should direct data into a separate section
__attribute__((section(".dtcmram"))) float Data_Set_Z[15000];
/*
******************************************************************************
**
** File : LinkerScript.ld
**
**
** Abstract : Linker script for STM32H7 series
** 256Kbytes RAM_EXEC and 256Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2019 STMicroelectronics.
** All rights reserved.
**
** 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 = 0x24080000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM_DTCM (rw) : ORIGIN = 0x00000000, LENGTH = 128K
RAM_EXEC (rx) : ORIGIN = 0x24000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x24040000, LENGTH = 256K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into RAM_EXEC */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >RAM_EXEC
.dtcm (NOLOAD) :
{
*(.dtcmram)
*(.dtcmram*)
} >RAM_DTCM
/* The program code and other data goes into RAM_EXEC */
.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 */
} >RAM_EXEC
/* Constant data goes into RAM_EXEC */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >RAM_EXEC
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM_EXEC
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >RAM_EXEC
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >RAM_EXEC
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >RAM_EXEC
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >RAM_EXEC
/* 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 */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> RAM_EXEC
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_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 left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
2021-01-06 08:56 AM
Thanks Tesla DeLorean, I still get the same RAM overflow errors. If you have time can you please explain what changes did you do in the linker script?
I red it but it was vague for me ....
2021-01-06 09:38 AM
The data still has to fit.
Not clear why the entire code/data needs to be in RAM. You might want to look at alternate ways of loading the RAM, ones where it doesn't need to copy initialized statics from one section to another, basically halving the available resources.
Perhaps you can look at the .MAP file as see where all the resources are being sucked up? You can make the MEMORYs unduly large so the linker can get closure, and then walk the file.
>>.. but since I am a beginner I confused and could not exactly understand what I am supposed to do ... .
In support cases it important impart the skills you do have, not the ones you don't.
Any MCU related stuff? Any linker/loader fundamentals? High School / College level?
>>If you have time can you please explain what changes did you do in the linker script? I read it but it was vague for me ....
The MEMORY portion tells the linker about the memory spaces available to it within the device. This can be a constrained subset of all resources.
The SECTION portion tells the linker about how to allocate sub-portions of the memory for different things, code/text, data, bss/uninitialized statics, ie stuff you assume starts with zeros in it. It controls the ordering of things, it can put things in the first bucket that meet the criterion expressed in the script.
2021-01-06 09:51 AM
Thanks you.
I need to collect a dataset and the time interval between the samples is short so that I can not store it on SD card and it's size is also a little bit large so that I can not store it on external SPI flash memories. After gathering a complete data set I can send it through a WIFI module and then clear Ram... that is why I am insisting on store only a data set the size of which is around 250K Byte.... I think the best way is to store data in RAM of the MCU and that is why I chose an MCU with 1MB RAM.
2021-01-06 10:00 AM
Ok, but why is the code there?
The AXI RAM is 512KB, the SRAM1,2,3 are contiguous with another 512KB, and there's 128KB in the DTCM
2021-01-06 04:02 PM
I want to put the variables near 45000 samples in RAM each hour, I collect 45000 sample, then I send them to a WIFI module then I clear the RAM and the next hour I will do the same iteratively.
I did step by step as it was mentioned in this page:
https://www.openstm32.org/Using+CCM+Memory?structure=Documentation
I aslo copied the linker script file you sent in my project and define my variable as you told kile this: __attribute__((section(".ccmram-strings"))) float Data_Set_Z[15000]; but I got the ram overflow messages like before.
moreover than Data_Set_Z[15000], I also defined :
float Data_Set_X[15000];
float Data_Set_Y[15000];
but these two array occupy more than 90 percent of my RAM so I can not add the third array which is Data_Set_Z[15000] to store my whole dataset.....
As my last hope :))) I was wondering whether it would be possible to change the dedicated memory area. Based on linker script file, memory is divided into two parts:
/* Specify the memory areas */
MEMORY
{
RAM_EXEC (rx) : ORIGIN = 0x24000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x24040000, LENGTH = 256K
}
1- would it be possible to dedicate more area to the part my arrays are inside ?? and make the rest smaller?
another thing I am thinking about is in linker script file it is written that " /* Initialized data sections goes into RAM" and there is another section of RAM for Uninitialized data. So, I defined my arrays like this :
float Data_Set_X[15000];
float Data_Set_Y[15000];
float Data_Set_Z[15000]={0}; and the RAM Overflow Error disappeared....
previously Idefined my arrays like this that led to ram overflow...
float Data_Set_X[15000];
float Data_Set_Y[15000];
float Data_Set_Z[15000];
Does it make sense? if I define like this, would my third array be put in another section of my ram so that the overflow does not happen ?
2021-01-07 10:42 AM
>>I want to put the variables near 45000 samples in RAM each hour, I collect 45000 sample, then I send them to a WIFI module then I clear the RAM and the next hour I will do the same iteratively.
You keep restating this like it answers the question, but WHY does the CODE need to be in the RAM too? I understand you want to store the DATA in RAM.
>> would it be possible to dedicate more area to the part my arrays are inside ?? and make the rest smaller?
You're picking these memory areas and sizes, there's other memory you can use, and you can pick how this is balanced/distributed.
You tell the linker what your desired floor plan is. It can only use memory you tell it about.
If you make it more complicated in the GNU/GCC implementation you're going to have to add code to startup.s to copy/initialize different areas.
To see what the linker has done you'd review the .MAP file