SystemWorkbench for STM32 CCM Settings |
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 data in this area.
For this there is several possibilities, depending on the amount of memory needed by the program. In all cases, the user may need to manually edit the linker script file (LinkerScript.ld, except if generated by CubeMX where the name depend on the chip reference).
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 the user must check the address of the CCM block; this comes from a STM32F429i chip).
Then the user has to select the sections to be placed in CCM.
This is quite simple; all initialized data can be placed in CCRAM by changing the line that reads
} >RAM AT> FLASH
at the end of the .data section by
} >CCMRAM AT> FLASH
All BSS (zero initialized) data can also be placed in CCRAM by changing the line that reads
} >RAM
at the end of the .bss section by
} >CCMRAM
The user can place individual variables in the CCRAM area, although this may be a bit more complex.
Uninitialized variables can be easily placed 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 are double underscores and double parentheses. This syntax is put in place to ensure it is not used by mistake...) If it does not exist, the user 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
If it exist, in the linker script be careful not to initialize the variable, even to zero, as it will take space in flash; optionally the user may suppress the AT> FLASH stance at the end of the default .ccmram section definition.
By default, variables placed in CCMRAM by attributes can't be initialized, even to zero.
If the user needs to initialize them to zero, he 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. */ FillZeroCcm: movs r3, #0 str r3, [r2] adds r2, r2, #4 LoopFillZeroCcm: ldr r3, = _eccmram cmp r2, r3 bcc FillZeroCcm
Conversely the user can create initialized ccmram data sections by placing initailized variables in a .ccmidata section.
First, define this section in the linker script by:
_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
Then the user 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 CopyCcmInit: ldr r3, =_siccmdata ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 LoopCopyCcmInit: ldr r0, =_siccmdata ldr r3, =_eiccmdata adds r2, r0, r1 cmp r2, r3 bcc CopyCcmInit
Finally to place the heap and stack in CCMRAM (possibly after other data), two small modifications are required in the linker script:
_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 */
For more information about C/C++ development tools in Eclipse, please see C/C++ Development User Guide.