It is so easy to place a function in RAM when you use IAR EWARM, all you have to do is put one magical word. Then, EWARM do automatically handle the function and place it in RAM.
Now, how about MCUXpresso IDE? that is a GCC environment, how can you do that?
This time, I will give you a hint how you can place a function in RAM in case of GCC environment.
As a matter of fact, it is also so easy to do it even in GCC environment like it is in IAR EWARM environment.
Basically, all you need is just one key word to be placed before the function or variable you want. The function or variable with the keyword will be placed in RAM.
Just as your reference, here is the previous post about IAR EWARM case.
Ref. Sooo easy! Just 1 magical word ! To execute a function from RAM using IAR EWARM.
Here we go!
Contents
Points
- Required “__attribute__” keyword
- Need to place it in .data section
- It is automatically copied from FlashROM to RAM in order to place it in RAM.
__attribute__ key word
__attribute__ keyword is described as below in the GCC online documentation.
Particularly, it is said that it is used to declare the attribute of the function or variable, then it helps the compiler to optimize calls and check the code.
For example, if you use the keyword for an interrupt handler function, then the entry/exit of the function optimized for an interrupt handler is generated.
And, you can control the code placement. Yes, this is what we need it.
Attributes
longcall:This is an attribute for function. It declares that the function with this attribute is to be called from different place. The compiler always uses a pointer to call the function.
section :This attribute places variables and/or functions in section you specify.
With these attributes specified, you can place your functions or variables in RAM. If you want a variable to be placed in RAM, you may not use longcall attribute. That attribute requires for function, but not for variables.
Code example : __attribute__ ((longcall, section(“memory_section”)))
“memory_section” is the section in which you want your function to be placed.
Linker script
If you want to place a function in specific section, you might as well create section in liker script.
Then, let’s see the inside.
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
PROVIDE(__start_data_RAM2 = .) ;
*(.ramfunc.$RAM2)
*(.ramfunc.$SRAM_LOWER)
*(.data.$RAM2*)
*(.data.$SRAM_LOWER*)
. = ALIGN(4) ;
PROVIDE(__end_data_RAM2 = .) ;
} > SRAM_LOWER AT > PROGRAM_FLASH
/* DATA section for FLEX_RAM */
.data_RAM3 : ALIGN(4)
{
FILL(0xff)
PROVIDE(__start_data_RAM3 = .) ;
*(.ramfunc.$RAM3)
*(.ramfunc.$FLEX_RAM)
*(.data.$RAM3*)
*(.data.$FLEX_RAM*)
. = ALIGN(4) ;
PROVIDE(__end_data_RAM3 = .) ;
} > FLEX_RAM AT > PROGRAM_FLASH
.data : ALIGN(4)
{
FILL(0xff)
_data = . ;
*(vtable)
*(.ramfunc*)
*(.data*)
. = ALIGN(4) ;
_edata = . ;
} > SRAM_UPPER AT>PROGRAM_FLASH
MCUXpresso SDK gives you several RAM section in default where you can place your function, data, data_RAM2 and data_RAM3.
.data/.data_RAM2/.data_RAM3 is a section name. Besides these sections, there are a code section (.text) or readonly data section (.rodata) for instance.
The section name is followed by {} brackets.
In the .data section of bracket, there is *(.ramfunc*). [*] is is a wild card of object files.
‘.ramfunc*’ is a section name which is defined in a source code.
Placement in section
For .data section, the above linker script places all object file in .data section if the object files are with attribute of section .ramfunc*.
If it is matched with .ramfunc.$RAM2 or .ramfunc.$RAM3, then it will be placed in .data_RAM2 or RAM3 instead of .data section. If the later part of the section name like .$RAM2 doesn’t match, t is placed in .data section.
Actual place to have code stored, and a place to be executed
>RAM_Area AT>PROGRAM_FLASH
This line means that a code or variables and functions are actually stored in PROGRAM_FLASH. But, the code is executed from RAM.
MCUXpresso SDK defines several RAM areas. For example, Kinetis MCU supports three kinds of RAM, upper side of RAM (SRAM_UPPER), lower side of RAM (SRAM_LOWER) and FLEX_RAM if it supports Flex Memory feature.
If you want to place a function in the lower side of RAM, you need to define the attribute with .ramfunc.$SRAM_LOWER (.ramfunc.$RAM2 is also ok).
Then, you will see the function is now placed in SRAM_LOWER section.
If you just declare a function with attribute section .ramfunc, the function will be placed in SRAM_UPPER in default.
Automatically copy will be done from FlashROM to RAM
Even If you define your function in RAM, the function is actually still stored in FlashROM (PROGRAM_FLASH). The code is however executed from RAM you specified.
RAM is a volatile memory, meaning that data in RAM stays there while the device is powered but RAM loses its data when it is shutting down.
This means that Data needs to be copied from FlashROM to RAM whenever the device is powered and initialized.
if using MCUXpresso SDK, you don’t need to do it. It is automatically done that data or code are copied from FlashROM to the specified attribute section (.data, ,data_RAM2, .data_RAM3) if you define __attribute__ keyword. It is so easy.
So, all you have to do is to declare __attribute__ keyword with section you want like I already mentioned above.
Let’s see the actual code in below test code.
Experiment Test code
volatile uint32_t cnt;
/* I want to place below test() in RAM(SRAM_LOWER). */
__attribute__ ((longcall, section(".data.$SRAM_LOWER"))) void test(){
cnt++;
}
int main(void)
{
char ch;
/* Init board hardware. */
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("hello world.\r\n");
while (1)
{
test();
ch = GETCHAR();
PUTCHAR(ch);
}
}
Map file
.data_RAM2 0x000000001fff0000 0x1c load address 0x0000000000003600
FILL mask 0xff
[!provide] PROVIDE (__start_data_RAM2, .)
*(.ramfunc.$RAM2)
*(.ramfunc.$SRAM_LOWER)
*(.data.$RAM2*)
*(.data.$SRAM_LOWER*)
.data.$SRAM_LOWER
0x000000001fff0000 0x1c ./source/hello_world.o
0x000000001fff0000 test
0x000000001fff001c . = ALIGN (0x4)
[!provide] PROVIDE (__end_data_RAM2, .)
.rel.dyn 0x000000001fff001c 0x0 load address 0x000000000000361c
.rel.iplt 0x000000001fff001c 0x0 ./utilities/fsl_assert.o
You can see the test() in RAM, the address is 0x1FFF0000 (SRAM_LOWER).
Summary
For IAR EWARM, there is a magical keyword “__ramfunc” to place code in RAM and it is so easy, whereas in GCC environment there is a similar keyword of it, that is “__attribute__”.
In the attribute keyword, if you specified with RAM section where you want to place, the code with the attribute section is automatically copied from FlashROM to RAM, and it will be executed from RAM.
If you want to place your function in RAM, please try this article.