This document describes a way how to execute a selected function(s) out of RAM memory for a project running out of Flash memory.
- Create a custom linker section in the linker file (.ld) where a routine(s) should be placed into. This step is optional if you don't care where exactly in RAM the function should be placed. In such case default sections could be used instead.
MEMORY
{
flash_rchw : org = 0x00FA0000, len = 0x4
cpu0_reset_vec : org = 0x00FA0000+0x10, len = 0x4
cpu1_reset_vec : org = 0x00FA0000+0x14, len = 0x4
cpu2_reset_vec : org = 0x00FA0000+0x04, len = 0x4
m_my_flash : org = 0x01000000, len = 4K // optional - this is dedicated section for the RAM function rom image
m_text : org = 0x01001000, len = 5628K // default section for code
m_my_ram : org = 0x40000000, len = 4K // optional - specific section where a RAM routine(s) should be copied into
m_data : org = 0x40001000, len = 764K // default section for data/stack/heap
}
- If it's intended to keep routine(s) that should be executed from RAM within a specific custom section:
SECTIONS
{
...
.MyRamCode :
{
MY_RAM_START = .; // this symbol is optional
KEEP (*(.MyRamCode)) // KEEP - avoid dead stripping if an object is not referenced
MY_RAM_END = .; // this symbol is optional
} > m_my_ram AT>m_my_flash // the section above is linked into m_my_ram and Rom image is stored into m_my_flash
- Otherwise you can use the default memory areas for code/data if you don't care about the location of the routine(s):
SECTIONS
{
...
.MyRamCode :
{
MY_RAM_START = .; // this symbol are optional
KEEP (*(.MyRamCode)) // KEEP - avoid dead stripping if an object is not referenced
MY_RAM_END = .; // this symbol are optional
} > m_data AT>m_text // the section is linked into default data memory area and its rom image is placed into the default code memory
- add the __attribute__ statements to the RAM function prototypes. The function attribute "longcall" is required to be able to call this RAM function from flash.
__attribute__ ((section(".MyRamCode"))) // place the function below into .MyRamCode section
int test_RAM(int arg1) __attribute__ ((longcall)); // declare the function as "far"
- Default S32DS project startup initializes just the default data sections. Therefore it's necessary to perform section copy-down manually if the functions are placed into a custom section. This must be done before a RAM routine gets called e.g. at the beginning of main() or in the startup routine.
You can create some linker symbols (.MyRamCode RAM and ROM addresses and size) and import them to the module where copy-down is implemented.
__MY_RAM_ADR = ADDR (.MyRamCode);
__MY_RAM_SIZE = SIZEOF (.MyRamCode);
__MY_RAM_ROM_ADR = LOADADDR (.MyRamCode);
The final source file may look like this:
#include <string.h>
extern unsigned long __MY_RAM_ADR;
extern unsigned long __MY_RAM_ROM_ADR;
extern unsigned long __MY_RAM_SIZE;
__attribute__ ((section(".MyRamCode"))) // place the function below into .MyRamCode section
int test_RAM(int arg1) __attribute__ ((longcall)); // declare the function as "far"
...
void main(void)
{
int counter = 0;
memcpy(&__MY_RAM_ADR , &__MY_RAM_ROM_ADR, &__MY_RAM_SIZE); // copy the function from flash to RAM
counter = test_RAM(counter); // call the function
...
}
Hope it helps!
Stan