cancel
Showing results for 
Search instead for 
Did you mean: 

The Build Analyzer says my processor STM32L443CC has 64K RAM and 16K RAM2. And I am not using any RAM2. What is RAM2 and how do I use it?

KiptonM
Lead

On other processors sometimes there are keywords when defining variables to specify which memory area the variable should be stored in. Or there is a #pragma statement.

I have not seen either in the STM32 or the IDE.

I am guessing RAM2 might be a good place to put DMA transfers so the processor working in RAM does not interfere as much with the transfer. But I do not know how to access it in any case.

According to the memory map SRAM1 starts at address 0x2000 0000 and SRAM2 starts at 0x2000 C000, (it drives me crazy when different documents use different names for the same thing) which makes me think they overlap? Unless the memory map is dealing in 32-bit dwords rather than 8-bit bytes. But then I would expect to see a gap between SRAM1 and SRAM2.

I see SRAM2 can be write protected. But still nothing about how to access it.

And SRAM2 can be retained in standby mode.

In the STM32L443CC STM32L443RC and STM32443VC datasheet (DS11421 Rev 5

On page 83/220 it says CODE memory goes from 0x0000 0000 to 0x1FFF FFFF.

SRAM1 goes from 0x2000 0000 to 0x2BFF FFFF and SRAM2 is from 0x2C00 0000 to undefined from the picture but less than 0x4000 0000 where the peripherals start.

But then it shows SRAM2 also from 0x1000 0000 to 0x1000 4000. So it has two mappings? How do you know which one to use?

Still I have not seen how to access it using the IDE.

1 ACCEPTED SOLUTION

Accepted Solutions
KiptonM
Lead

Looking more closely at the linker script, there are no sections associated with RAM2.

So I added

.sram2 :
  {
    . = ALIGN(4);
    *(.sram2)           /* .sram2 sections (variables) */
  } >RAM2

to STM32L443CCTX_FLASH.ld

That worked!!!

Using ".sram2" RAM was smaller and the address of buffer was 0x100000000 in the RAM2 area.

View solution in original post

16 REPLIES 16
KnarfB
Principal III

SRAM2 does have two mappings. Details are in the reference manual, especially around "Figure 1. System architecture" which explains the AHB bus-matrix in greater detail.

0x2000 0000 + 48*1024 = 0x2000 C000, so both SRAMs are continous in that mapping. The other mapping 0x1000 0000 results in using different busses which may result in a performance boost, see https://developer.arm.com/documentation/ddi0439/b/Functional-Description/Interfaces/Bus-interfaces.

In the source code, gcc uses attributes to specify a section, like

uint8_t buffer[1024] __attribute__((section(".sram2")));

where the attribute name must match a linker script entry. An sample linker script is ./NUCLEO-L432KC/Templates/SW4STM32/STM32L432KC_NUCLEO/STM32L432KCUx_FLASH.ld or similar projects from the STM32L4 firmware package.

hth

KnarfB

KiptonM
Lead

Great that is exactly what I was looking for.

Just before I came to check on this, I was looking at the linker script STM32L443CCTX_FLASH.ld and saw:

/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 64K
  RAM2    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 16K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 256K
}

so naturally I guessed it would have been called "RAM2" not ".sram2". did not find sram2 in the linker script. I was wondering how it worked.

KiptonM
Lead

O.K. so it tried it for the heck of it.

uint8_t buffer[1024] __attribute__((section(".sram2")));
 
void write_buffer(void)
{
	uint16_t i;
	for (i=0;i<1024;i++)
	{
		buffer[i] = i & 0xFF;
	}
 
}

and the build analyzer still said 0 B used in RAM2

I tried RAM2 and .RAM2 in place of .sram2 and all cases gave 0 B of RAM2 used. and no compiler or linker errors or warnings in all cases.

Found the problem, the compiler does not add it if it is not used. So I had to call write_buffer() from some code that I knew was executed and RAM changed.

 I just commented it out, and the RAM number did not change either.

Try again,

Using ".RAM2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

Using "RAM2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

Using ".sram2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

Using "_RAM2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

Using "__RAM2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

Using "_sram2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

Using "__sram2" RAM was bigger and the address of buffer was 0x200000220 in the RAM area.

It puts it in RAM every time with no errors or warnings.

gbm
Lead III

What's your reason for using RAM2 explicitly? For simple usage cases, it's just the last 16 KiB block of RAM area.

If you really need to use RAM2, you should edit the link script and reduce the size of RAM by 16 KiB, then define a new section under SECTION which should be placed in RAM2, similarly to .data section which goes to RAM. This, unfortunately, isn't the end of story - you may need to init this section or maybe not (better not, then skip AT> FLASH), but it will still behave like initialized .data section even if effectively it will be .bss.

Generally, it's not worth the effort unless you have a real need for it (a rare, but existing case).

.LD along the lines of..

...
 
/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 64K
  RAM2    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 16K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 256K
}
 
...
 
/* Sections Definitions */
 
SECTIONS
{
 
...
 
/* toward end, after BSS, etc and before DISCARD */
 
    .sram2 (NOLOAD) : /* name in .MAP/ELF file, no backing content in .ELF */
    {
      . = ALIGN(4);
 
        *(.sram2) /* sections from object / attributes, compiler side */
        *(.sram2.*)
 
     . = ALIGN(4);
    } >RAM2 /* MEMORY it lives in */
 
...
 
}

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

Looking more closely at the linker script, there are no sections associated with RAM2.

So I added

.sram2 :
  {
    . = ALIGN(4);
    *(.sram2)           /* .sram2 sections (variables) */
  } >RAM2

to STM32L443CCTX_FLASH.ld

That worked!!!

Using ".sram2" RAM was smaller and the address of buffer was 0x100000000 in the RAM2 area.

If it has content you need to initialize you'd need to manage that in startup.s, and you'd need to have symbols about where it is parked in FLASH before it's copied.

Like this it will create a section in the .ELF at 0x10000000 with content described in the object file, and the debugger likely would download it for you.

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

It would not let me attach the STM32L443CCTX_FLASH.ld because the type was not in the list of files.

/*
******************************************************************************
**
** @file        : LinkerScript.ld
**
** @author      : Auto-generated by STM32CubeIDE
**
** @brief       : Linker script for STM32L443CCTx Device from STM32L4 series
**                      256Kbytes FLASH
**                      64Kbytes RAM
**                      16Kbytes RAM2
**
**                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) 2022 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/
 
/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
 
/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 64K
  RAM2    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 16K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 256K
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
 
  /* The program code and other data into "FLASH" Rom type memory */
  .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 into "FLASH" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
 
  .ARM.extab   : {
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH
 
  .ARM : {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH
 
  .preinit_array     :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH
 
  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(4);
  } >FLASH
 
  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
 
  /* Used by the startup to initialize data */
  _sidata = LOADADDR(.data);
 
  /* Initialized data sections into "RAM" Ram type memory */
  .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 */
 
  } >RAM AT> FLASH
 
  /* Uninitialized data section into "RAM" Ram type memory */
  . = 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;
  } >RAM
 
  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM
 
.sram2 :
  {
    . = ALIGN(4);
    *(.sram2)           /* .text sections (code) */
  } >RAM2
  
  /* Remove information from the compiler libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
 
  .ARM.attributes 0 : { *(.ARM.attributes) }
}

This is the modified file. FYI

You are probably right, but I wanted to know how to do it.

It is in another physical location with busses so If I ever needed more speed I could use it like a Harvard architecture.

Thanks for the response.