2

For my application I need 305Kbytes of RAM for the variables.

According to Reference manual for the chip I am using - STM32L4R5ZI: "The STM32L4Rxxx and STM32L4Sxxx devices feature up to 640 Kbytes SRAM: • 192 Kbytes SRAM1 • 64 Kbytes SRAM2 • 384 Kbytes SRAM3"

In my Truestudio I do see these RAM1 to RAM3 partitions, but when I try to build with values overflowing the 192 Kbytes of SRAM1 I have error. Reading around showed me that most probable issue is the linker script and in it I found:


/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20030000;    /* end of 192K RAM */

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 2048K
  RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 192K
  RAM2 (rw)       : ORIGIN = 0x10000000, LENGTH = 64K
  RAM3 (rw)       : ORIGIN = 0x20040000, LENGTH = 384K
  MEMORY_B1 (rx)  : ORIGIN = 0x60000000, LENGTH = 0K
}

It is the first time I touch that, so I am curious how does it work. Do I just update the ld file? Also, considering the current code, how should I change it to be able to use all three partitions together, or just SRAM3 which would be enough for me? Is there another place I have to be careful about?

I see further in the script we have:

/* 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> FLASH
  
  _siram2 = LOADADDR(.ram2);

  /* RAM2 section 
  * 
  * IMPORTANT NOTE! 
  * If initialized variables will be placed in this section, 
  * the startup code needs to be modified to copy the init-values.  
  */
  .ram2 :
  {
    . = ALIGN(4);
    _sram2 = .;       /* create a global symbol at ram2 start */
    *(.ram2)
    *(.ram2*)
    
    . = ALIGN(4);
    _eram2 = .;       /* create a global symbol at ram2 end */
  } >RAM2 AT> FLASH

  /* 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(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM

Thank you!

EDIT: At the end, I used the proposed code to add RAM3 section, then allocated .bss in RAM3 and problem fixed.

D. K.
  • 111
  • 7

2 Answers2

3

Your C compiler 'organizes' your variables into a few standard memory 'sections'.
Global (or static local) variables which you initialize to zero when you declare them or global variables which you do not explicitly initialize are put in the .bss section.
Global (or static local) variables which you do initialize when you declare them are put into the .data section.
You will also have sections for the stack (or multiple stacks) and the heap (for malloc to use).
You can see that all these sections are defined in your linker script.
Your .bss. is in RAM.
.data is also in RAM, but since the linker also has to store all the values to use to initialize the variables there, .data also has a section in FLASH.
Your heap and stack area is combined into a section called .user_heap_stack (the compilers I work with typically put these into separate areas).

Now, your problem comes about when you create variables large enough that they don't fit into the memory segment they're allocated to. In your case we can see that all of the standard C memory sections are being put into the 192k RAM segment.

Unfortunately, you can't split a single C memory section across multiple memory segments, nor can you split a variable across multiple sections, so you're going to have to manually work out which of your variables you can move over into a different section to make everything fit.
Your linker script already has a section defined to allow you to use the 64k RAM2 memory segment, so to tell the compiler & linker to put a particular variable there you would do something like:
int variableName __attribute__((section(".ram2")));
to create an int called variableName and put it in the .ram2 section.

Although your linker script does define the RAM3 memory segment, it does not seem to have any sections put into it. So to be able to use the 384k RAM3 segement you'll have to add a few lines to your linker script. Something like:

  .ram3 :
  {
    . = ALIGN(4);
    _sram3 = .;       /* create a global symbol at ram3 start */
    *(.ram3)
    *(.ram3*)
    
    . = ALIGN(4);
    _eram3 = .;       /* create a global symbol at ram3 end */
  } >RAM3

This will give you a .ram3 memory section to use in the same way as the .ram2 example above.

Something you could also consider - since RAM3 is double the size of RAM - you might want to move the standard C sections like .bss, .data, etc into RAM3 and out of the RAM segment.
If you choose to move the location of the stack section to a different segment, remember to update the _estack definition at the top of your linker file.

brhans
  • 14,373
  • 3
  • 34
  • 49
  • Thank you for the explanation! In fact, I have two global 16bit arrays for image masking, each is about 150Kbytes. I currently run my software with one mask for debugging so ram1 is enough, but need to load the second mask for the final version. So my main goal should be to load these two arrays into SRAM3. Is there something I have to be careful about since we talk about arrays? I will include your example code to add the SRAM3 memory section. Then I have to use something like `int maskA __attribute__((section(".ram3")));` to load the specific array. How do we define an array not a variable? – D. K. Oct 09 '21 at 23:59
  • Define your array(s) just like you normally would, just append the section attibute at the end - so something like `int maskArray[10000] __attribute__((section(".ram3")));` – brhans Oct 10 '21 at 00:50
  • Thank you! I will start testing now. – D. K. Oct 10 '21 at 06:55
2

Binutils LD does not allow gaps in the memory space, thus you cannot combine RAM and RAM3.

You can try to use RAM3 instead of RAM as your data section.

Turbo J
  • 9,969
  • 1
  • 20
  • 28