Using CCM Memory

Some STM32 CPUs include two banks of memory: the standard SRAM and another bank of Core-Coupled-Memory (a.k.a. CCM) which may be faster than the standard SRAM and is usually smaller.

In some cases it may be interesting to place datain this area.

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

Checking if CCM was declared

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).

Placing full data sections in CCM

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

Placing all initialized data in CCM

This is quite simple; You may place all initialized data in CCRAM by changing the line that reads
at the end of the .data section by

Placing all zero-initialized data in CCM

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

Placing individual variables in CCM

You may place individual variables in the CCRAM area, although this may be a bit more complex.

Placing uninitialized variables in CCM

You can very simply place uninitialized variables in CCM 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 
  * 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 */
    . = ALIGN(4);
    _eccmram = .;       /* create a global symbol at ccmram end */

If it exist, in your linker script be careful not to initialize ythe variable, even to zero, as it will take space in flash; optionally you may suppress the AT> FLASH stance at the end of the default .ccmram section definition.

Placing zero-initialized variables in CCM

By default, variables placed in CCMRAM by attributes 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) by duplicating the code for the bss, just after its final bcc FillZerobss, modifying it to look like:
ldr	r2, =_sccmram
	b	 LoopFillZeroCcm
/* Zero fill the ccmram segment. */
	movs r3, #0
 	str  r3, [r2]
	adds r2, r2, #4

	ldr	r3, = _eccmram
	cmp	r2, r3
	bcc	FillZeroCcm

Placing initialized data in CCM

Conversely you can create initialized ccmram data sections by placing initailized variables in a .ccmidata section.

You must first define this section in the linker script by:
_siccmram = LOADADDR(.ccmram); /* May be already present */

  /* Initialized CCM-RAM section 
  * 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 */

The you must duplicate the data section copying code (using symbols _siccmram, _sccmidata and _eccmidata) just after its bcc CopyDataInit:
/* Copy the ccm segment initializers from flash to SRAM */
  movs	r1, #0
  b	LoopCopyCcmInit

	ldr	r3, =_siccmdata
	ldr	r3, [r3, r1]
	str	r3, [r0, r1]
	adds	r1, r1, #4

	ldr	r0, =_siccmdata
	ldr	r3, =_eiccmdata
	adds	r2, r0, r1
	cmp	r2, r3
	bcc	CopyCcmInit

Placing the heap and stack in CCM

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 = 0x20020000;    /* end of RAM */
    by (for example, if the CCM RAM goew from 0x10000000 to 0x1000FFFF, again specific addresses may change)
    _estack = 0x10010000;    /* end of CCMRAM */