Loading...
 

SW4STM32 and SW4Linux fully supports the STM32MP1 asymmetric multicore Cortex/A7+M4 MPUs

   With System Workbench for Linux, Embedded Linux on the STM32MP1 family of MPUs from ST was never as simple to build and maintain, even for newcomers in the Linux world. And, if you install System Workbench for Linux in System Workbench for STM32 you can seamlessly develop and debug asymmetric applications running partly on Linux, partly on the Cortex-M4.
You can get more information from the ac6-tools website and download (registration required) various documents highlighting:

System Workbench for STM32


use STM32F4 CCM memory for the stack and the heap

The microprocessor on my STM32F4Discovery has 128KB of normal RAM and 64KB of CCM (core-coupled) RAM.

I have big arrays of memory (more than 100KB) used for DMA transfers so it would be nice if I could move my stack and heap memory into the CCM area to not run out of RAM. How can I achieve this with OpenSTM32?

Thanks.

France

For this there is several possibilities, depending on the amount of memory needed by your program.In all cases that may need to manually edit the linker script file (LinkerScript.ld, except if generated by CubeMX where the name depend on the chip reference).

You must first look for the MEMORY section and, if it is not present, add a line looking like
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
(of course you must check the address of the CCM block; this comes from a STM32F429i chip).


Then you must decide which sections must be placed in CCM.

You may for example place all initialized data in CCRAM by changing the line that reads
} >RAM AT> FLASH
at the end of the .data section by
} >CCMRAM AT> FLASH

You may also place all BSS (zero initialized) data in CCRAM by changing the line that reads
} >RAM
at the end of the .bss section by
} >RAM

You may also place individual variables in the CCRAM area by adding to their definition a section attribute, like, for variable in_ccmram_buffer declaring it by:
char in_ccram_buffer[1024] __attribute__((section("ccmram")));
(Yes, there is double underscores and double parentheses in this ugly syntax, mainly to be sure you do not use it by mistake...) If it does not exist, you must create the .ccmram section by:
/* CCM-RAM section 
  * 
  * IMPORTANT NOTE! 
  * If variables placed in this section must be zero initialized,
  * the startup code needs to be modified to initialize this section.  
  */
  .ccmram :
  {
    . = ALIGN(4);
    _sccmram = .;       /* create a global symbol at ccmram start */
    *(.ccmram)
    *(.ccmram*)
    
    . = ALIGN(4);
    _eccmram = .;       /* create a global symbol at ccmram end */
  } >CCMRAM
Note that, by default, variables placed in CCMRAM by such an attribute can’t be initialized, even to zero. If you needed to initilalize them to zero, you must slightly enhance the startup_stm32xxxxx.S file to add a second zero-initialization loop (using symbols _sccmram and _eccmram); conversely you can create initialized ccmram data sections by duplicating the data section copying code (using symbols _siccmram, _sccmidata and _eccmidata) and creating a .ccmidata section similarly to the way the .data section was defined:
_siccmram = LOADADDR(.ccmram); /* May be already present */

  /* Initialized CCM-RAM section 
  * 
  * IMPORTANT NOTE! 
  * If initialized variables will be placed in this section, 
  * the startup code needs to be modified to copy the init-values.  
  */
  .ccmidata : 
  {
    . = ALIGN(4);
    _sccmidata = .;        /* create a global symbol at data start */
    *(.ccmidata)           /* .data sections */
    *(.ccmidata*)          /* .data* sections */

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


Finally to place the heap and stack in CCMRAM (possibly after other data) you just have to do two small modifications in the linker script:

  1. Redirect the output of the ._user_heap_stack to the CCMRAM memory area instead of RAM.
  2. Redefine the _estack symbol to the end of the CCMRAM by replacing
    _estack = 0x2002FFFF;    /* end of RAM */
    by (for example, again specific addresses may change)
    _estack = 0x1000FFFF;    /* end of CCMRAM */



This may seem a bit complex but, for simple operations like this, it should work without too much difficulties.

I hope this will help you,

Nevertheless, be careful: all this should work but was not tested directly and there may be some typos here and there...

Bernard

Thank You very much!

But is some additive issues for this.

If We use memalloc, getmem and etc... we will have problems after change stack to CCM, because function _sbr from syscalls.c is not correct developed. OMG!

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

caddr_t _sbrk(int incr)
{
extern char end asm(“end”);
static char *heap_end;
char *prev_heap_end;

if (heap_end == 0)
heap_end = &end;

prev_heap_end = heap_end;
if (heap_end + incr > stack_ptr)
{
// write(1, “Heap and stack collision\n”, 25);
// abort();
errno = ENOMEM;
return (caddr_t) -1;
}

heap_end += incr;

return (caddr_t) prev_heap_end;
}
// where stack_ptr is alias for SP register

+++++++++++++++++++++++++++++++++++++++++++++++++

Heap end compared with current SP!!! OMG!!! program with this _sbr() can work only if you have exceed memory...

ST developers! please do someting ;)

My changes in linker script and syscalls.c to solve this problem:
xxx.ld

++++++++++++++++++++++++++++++++++++++++++++++

/* Highest address of the user mode stack */
_estack = 0x10004000; /* pointer to stack, stack grows down and at address 0x10000000 we have hard fault exception*/
_Min_Stack_Size = 0x3F80; /* required amount of stack */
_Min_Stack_Ptr = _estack - _Min_Stack_Size; /* used to control out of bounds*/

_Max_Heap_Ptr = 0x20020000;
_Min_Heap_Size = 0; /* required amount of heap used only for error cheking*/

/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
ROM (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}

++++++++++++++++++++++++++++++++++++++++++++++

bottom of xxxx.ld:
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = ALIGN(8);
} >RAM
._user_heap_stack_ccm :
{
. = ALIGN(8);
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >CCRAM

++++++++++++++++++++++++++++++++++++++++++++++

and syscalls.c:
caddr_t _sbrk(int incr)
{
extern char end asm(“end”);
extern char _Max_Heap_Ptr asm(“_Max_Heap_Ptr”);
static char *heap_end;
char *prev_heap_end;

if (heap_end == 0)
heap_end = &end;
prev_heap_end = heap_end;
// please check
char * addresToCheck =0;
if (heap_end + incr > &_Max_Heap_Ptr)
{
//Heap collision
while(1) {};
// comment one of this (up or two down lines)
//errno = ENOMEM;
//return (caddr_t) -1;
}

heap_end += incr;

return (caddr_t) prev_heap_end;
}


@dautrevaux

THANK you, Bernard!


Hi,

What will be the procedure to run function from CCM RAM ?

Thank you