AnsweredAssumed Answered

Placing specific functions into RAM blocks

Question asked by LPCware Support on Mar 31, 2016

In most modern MCUs with built-in flash memory, code is normally executed directly from flash memory.  Various techniques, such as prefetch buffering are used to ensure that code will execute with minimal or zero wait states, even a higher clock frequencies. Please see the documentation for the MCU that you are using for more details.

 

However it is also possible to place specific functions into any of the defined banks of RAM for the target MCU, as displayed in:

 

Project -> Properties ->  C/C++ Build -> MCU settings

 

and sometimes there can be advantages in relocating small, time critical functions so that they run out of RAM instead of flash.

 

For simplicity, the *additional* memory regions are named sequentially, starting from 2, (as well as using their "formal" region name - for example RamAHB32). So for a device with 3 RAM regions, alias names RAM, RAM2 and RAM3 will be available.

 

This placement is controlled via macros provided in an LPCXpresso header file which can be pulled into you project using:

 

#include <cr_section_macros.h>

 

The macro __RAMFUNC has been added from LPCXpresso IDE v 7.1.0 and can be used to locate a function into a specific RAM region.

 

For example, to place a function into the main RAM region, use:

 

__RAMFUNC(RAM) void fooRAM(void) {...

 

To place a function into the RAM2 region, use:

 

__RAMFUNC(RAM2) void fooRAM2(void) {...

 

Alternatively, RAM can be selected by formal name (as listed in the memory configuration editor), for example:

 

__RAMFUNC(RamAHB32) void HandlerRAM(void) {...

 

In order to initialize RAM based code (and data) into specified RAM banks, the managed linker script mechanism will create a "Global Section Table" in your image, directly after the vector table. This contains the addresses and lengths of each of the data (and bss) sections, so that the startup code can then perform the necessary initialization (copy code/data from Flash to RAM) .

 

Long branch veneers and debugging

 

Due to the distance in the memory map between flash memory and RAM, you will typically require a "long branch veneer" between the function in RAM and the calling function in flash. The linker can automatically generate such a veneer for direct function calls, or you can effectively generate your own by using a call via a function pointer.

 

One point to note is that debugging code with a linker generated veneer can sometimes cause problems. This veneer will not have any source level debug information associated with it, so that if you try to step in to a call to your ram code, typically the debugger will step over it instead.

 

You can work around this by single stepping at the instruction level, setting a breakpoint in your RAM code, or by changing the function call from a direct one to a call via a function pointer.

 

Other related FAQs:

 

Outcomes