Referring to the MSP430 microcontroller device datasheet, the current consumption in active mode (CPU on) is usually specified around 10-40% lower if the code is executed from SRAM than from flash memory. For example:
- The MSP430F22x4 datasheet specifies the current consumption in active mode (CPU = 1MHz, Vcc = 3.3V) to be 340 uA when running code from SRAM and 390 uA when running from Flash.
- The MSP430F543xA datasheet specifies current consumption in active mode (CPU= 1MHz, PMMCOREVx=0, Vcc = 3.0V) to be 0.17 mA when running code from SRAM and 0.29 mA when running from flash.
Therefore in an application which has very limited power source and has small routines which are executed quite often, it is useful to execute the routine from SRAM instead of flash memory to reduce the current consumption. Onwards let’s call such function executed from RAM/SRAM during run-time as “RAM function”. The basic principle is quite simple: the code needs of course to be first stored in a non-volatile memory (e.g. flash memory), however these code will then be copied into RAM during initialization to enable executing it from RAM during run-time.
The following guide shows the implementation of code example for implementing RAM function in C programming language for MSP430 microcontroller device on the IAR Embedded Workbench (IAR EWB) compiler and Code Composer Studio (CCSTUDIO), inspired by the flash write code example of MSP430F543x. The example uses the MSP430G2553 on MSP-EXP430G2 Launchpad development board as target device. The MSP430G2553 microcontroller basically has 16 KB Flash (address range 0xC000 – 0xFFFF) and 512 bytes SRAM (address range 0x200 – 0x3FF) on-chip. Although practically it is not really suitable to use the MSP430G2553 for implementing RAM functions due the small SRAM memory size, the example codes basically tries to give a proof of concept on how RAM functions which can even implement ISR (In terrupt Service Routine).
The example code can be downloaded at this link.
IAR EWB Implementation
Implementing such a RAM function in with IAR EWB compiler is very easy. This can be done by simply adding the __ramfunc keyword in the function definition as shown in the example code. As can be found in the example code, there are basically four C functions which are defined with __ramfunc keyword: main_loop(), blink_led1(), blink_led2(), and TIMER_ISR(), with the latter is basically an ISR function. After successful compilation, the generated .map file of the example code shows the following output for the symbol-address assignments:
**************************************** * * * ENTRY LIST * * * **************************************** Module Entry Address ------ ----- ------- . . . . . . . . main C076 main_loop 0200 blink_led1 020A blink_led2 021E __low_level_init C0DC TIMER_ISR 0236 TIMER_ISR::??INTVEC 18 FFF2
As can be seen above, the four functions defined with __ramfunc keyword are assigned to the memory address of the on-chip SRAM (between 0x200 – 0x3FF).
In order to test this also “live” on the target device, compile and download the code into the MSP430G2553 on the MSP-EXP430G2 Launchpad board by starting the debug session in IAR IDE. Put a breakpoint at one of the RAM functions above then execute debug run. When the debugger hits the breakpoint, check the PC register content which shall point to the code residing in the SRAM area (between 0x200 – 0x3FF):
CCSTUDIO Implementation
Using Code Composer Studio (CCSTUDIO) to implement RAM functions is a little bit more complicated. It requires the user to first define the memory area where the code shall be stored in flash and also executed in SRAM during run-time.
In this example, the memory partition for imeplementing RAM functions is defined in the header file ram_func_ccs_mem.h as follows:
// RAM memory (0x0200 - 0x03FF) #define RAM_CODE_START_ADDR (0x0200) // 128 bytes for code #define RAM_CODE_END_ADDR (0x027F) #define RAM_CODE_LEN (RAM_CODE_END_ADDR - RAM_CODE_START_ADDR + 1) #define RAM_DATA_START_ADDR (RAM_CODE_END_ADDR + 1) #define RAM_DATA_END_ADDR (0x03FF) #define RAM_DATA_LEN (RAM_DATA_END_ADDR - RAM_DATA_START_ADDR + 1) // Flash memory (0xC000-0xFFBF), Interrupt Vector (0xFFC0-0xFFFF) #define FLASH_RAM_CODE_START_ADDR (0xC000) // shall match the length of RAM for code #define FLASH_RAM_CODE_END_ADDR (FLASH_RAM_CODE_START_ADDR + RAM_CODE_LEN - 1) #define FLASH_RAM_CODE_LEN (RAM_CODE_LEN) #define FLASH_START_ADDR (FLASH_RAM_CODE_END_ADDR + 1) #define FLASH_END_ADDR (0xFFBF) #define FLASH_LEN (FLASH_END_ADDR - FLASH_START_ADDR + 1)
As can be seen above, there are 128 bytes from each on-chip SRAM and FLASH memory which are allocated to store the RAM functions. The SRAM for storing the RAM function is defined at memory between 0x200 –0x27F (from RAM_CODE_START_ADDR to RAM_CODE_END_ADDR), while the flash used is between 0xC000 to 0xC07F (FLASH_RAM_CODE_START_ADDR to FLASH_RAM_CODE_END_ADDR).
The settings in the header file are used by the linker command file (lnk_msp430g2553.cmd) for defining new memory areas in the MEMORY directive as follows (RAM_CODE and FLASH_RAM_CODE):
MEMORY { . . . . . . . RAM_CODE : origin = RAM_CODE_START_ADDR, length = RAM_CODE_LEN RAM : origin = RAM_DATA_START_ADDR, length = RAM_DATA_LEN . . . . . . . FLASH_RAM_CODE : origin = FLASH_RAM_CODE_START_ADDR, length = FLASH_RAM_CODE_LEN FLASH : origin = FLASH_START_ADDR, length = FLASH_LEN . . . . . . . }
Then in the SECTION directive of the same linker command file, these new memory areas are used to define a new memory section on how it shall be stored/loaded and executed:
SECTIONS { . . . . . . . .ram_code : load = FLASH_RAM_CODE, run = RAM_CODE . . . . . . . }
The new “.ram_code” section can now then be used e.g. together with the CODE_SECTION pragma to define the RAM function within the code:
#pragma CODE_SECTION(main_loop, ".ram_code") void main_loop(void) { while(1) { // enable interrupt and sleep __bis_SR_register(LPM3_bits + GIE); // blink LED2 blink_led2(); } }
After compiling the source code, the generated .map file shows the following results: The RAM functions are first stored/loaded in the flash memory (between 0xC000 –0xFFFF):
SECTION ALLOCATION MAP output attributes/ section page origin length input sections -------- ---- ---------- ---------- ---------------- .ram_code * 0 0000c000 0000005e RUN ADDR = 00000200 0000c000 00000020 ram_func_ccs.obj (.ram_code:TIMER_ISR) 0000c020 0000001c ram_func_ccs.obj (.ram_code:blink_led2) 0000c03c 00000018 ram_func_ccs.obj (.ram_code:blink_led1) 0000c054 0000000a ram_func_ccs.obj (.ram_code:main_loop)
However the symbols of these RAM functions are located in SRAM memory (between 0x200 – 0x27F):
GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name address name -------- ---- . . . . . . 00000200 TIMER_ISR . . . . . . 0000023c blink_led1 00000220 blink_led2 . . . . . . 00000254 main_loop . . . . . .
Unlike the IAR compiler, using the CCSTUDIO compiler requires the user to manually copy the code binary content from FLASH memory to SRAM before being able to execute it on SRAM. In order to make it simpler, this is done in the custom C pre init function as can be shown follows:
int _system_pre_init(void) { // stop WDT WDTCTL = WDTPW + WDTHOLD; // copy ram code from flash to ram memcpy(((void*)RAM_CODE_START_ADDR), ((void*)FLASH_RAM_CODE_START_ADDR), RAM_CODE_LEN); // Perform C/C++ global data initialization return 1; }
As using the IAR compiler above, it is also possible to use CCSTUDIO to debug the RAM functions by putting a breakpoint in one of the RAM functions and examining the content of PC register which shall point to SRAM memory:
Awesome. Exactly what I’ve been trying to do to lower power in my system. Unfortunately I didn’t realize that my MSP430G2553 is rather limited in its memory, so I guess this won’t help. I’ve been following this MSP430 tutorial and didn’t realize until much later that to do this RAM capability I’d need a lot of RAM.
Jane, you are correct. Actually running code from SRAM would make more sense for devices which has much bigger SRAM size. Anyway I decided to write it for MSP430G2553 since the MSP-EXP430G2 Launchpad is the most popular kit for MSP430.
Great job! Thanks for posting this. It’s very helpful
I want to write function into flash only but at specific address but it won’t work using CODE_SECTION and i am using CCS.
can you help?
I want some detail info on memory and section in linker part
Thanks for posting this.
I had forgotten that the end application had to manually copy code from flash to sram with CCS.
Thank you!
Very useful info, I’ve used it to copy ISR code for my Application Image that resides in the >64K of FLASH into RAM