String format and printing functions such as (s)printf() are not natively supported on microcontroller architecture. Hence the use of these functions require the compiler to pull in additional libraries to generate a large amount of code. This additional code execution is directly translated into added time as well as energy required to perform the functions.
Depending on the support libraries and the compiler, (s)printf() functions usually require significant amount of code to be executed.
The code contains print() or sprintf() function call(s).
Avoid using (s)printf() functions in an MSP430 program. Try to print/send data in raw format if all possible. Alternatively, move the execution of the (s)printf() functions to RAM as code execution from RAM consumes much less power than Flash. If the MSP430 is part of a more complex system, try to offload the string printing/formatting to the host processor.
!Note that relocating the functions to RAM requires the use of a customized command linker file. This method is undetected by the ULP Advisor tool and the remark will still be issued. Once you can confirm the RAM execution in your code, you can suppress the remark by disabling the option for this rule in the Project's ULP Advisor setting.
Note that this instruction is specific for CCS.
The key idea behind RAM-executed functions is to link the functions to a memory section with the following attribute: "load = FLASH_AREA, run = RAM_AREA" defined in the linker command file. As the parameters suggest, the objects in the section will be allocated to FLASH, but at start up they will be copied over to RAM for execution. Note that the names FLASH_AREA or RAM_AREA can be the default names (FLASH, RAM) or preferrably user-defined to prevent confusion. For MSP430 devices with FRAM, FLASH regions can be substituted by FRAM regions.
The following steps describe necessary procedure to relocate functions to RAM for execution.
I. Create a load = FLASH, run = RAM memory section in the device linker command file.
Before:
RAM : origin = 0x2400, length = 0x2000 INFOA : origin = 0x1980, length = 0x0080 INFOB : origin = 0x1900, length = 0x0080 INFOC : origin = 0x1880, length = 0x0080 INFOD : origin = 0x1800, length = 0x0080 FLASH : origin = 0x4400, length = 0xBB80 FLASH2 : origin = 0x10000,length = 0x14400 ...
After reserving 0x200 bytes for RAM_EXECUTE and 0x200 bytes for FLASH_EXECUTE. Notice the new starting addresses (origins) & lengths:
RAM_EXECUTE : origin = 0x2400, length = 0x0200 RAM : origin = 0x2600, length = 0x1C00 INFOA : origin = 0x1980, length = 0x0080 INFOB : origin = 0x1900, length = 0x0080 INFOC : origin = 0x1880, length = 0x0080 INFOD : origin = 0x1800, length = 0x0080 FLASH_EXECUTE:origin = 0x4400, length = 0x0x200 FLASH : origin = 0x4600, length = 0xB980 FLASH2 : origin = 0x10000,length = 0x14400 ...
.bss : {} > RAM /* GLOBAL & STATIC VARS */
.sysmem : {} > RAM /* DYNAMIC MEMORY ALLOCATION AREA */
.stack : {} > RAM (HIGH) /* SOFTWARE SYSTEM STACK */
// add this line
.run_from_ram: load = FLASH_EXECUTE, run = RAM_EXECUTE
//
.text : {}>> FLASH | FLASH2 /* CODE */
.text:_isr : {} > FLASH /* ISR CODE SPACE */
....
We're done with the linker command file modification at this point.
II. Relocate user-generated functions:
1. Identify the functions to be relocated to RAM in your code.
2. Before the definition of each function, add the following line
#pragma CODE_SECTION(FunctionName,".run_from_ram")
void FunctionName(void)
{
III. Relocate built-in run-time library (rts430*) functions:
If you use division, multiplication, or printf/sprintf in your applications, these functions are pulled in from the real-time library. These processor intensive functions should also be relocated to RAM to optimize your application for power.
You can find out whether your application uses many of these
functions by looking at the output map file and searching for
rts430*.lib. For example
rts430xl.lib : mult16_f5hw.obj (.text)
rts430xl.lib : div16u.obj (.text)
rts430xl.lib : sprintf.obj (.text:sprintf)
sprintf.obj (.text:_outs)
sprintf.obj (.text:_outc)
Add the following lines to the linker command file to redirect these objects into the FLASH_EXECUTE//RAM_EXECUTE area
Option 1
.text:rts430.lib_div : { rts*.lib<div16u.obj>(.text) } load = FLASH_EXECUTE, run = RAM_EXECUTE
.text:rts430.lib_mult : { rts*.lib<mult16_f5hw.obj>(.text) } load = FLASH_EXECUTE, run = RAM_EXECUTE
.text:rts430.lib_printf : { rts*.lib<*printf.obj>(.text) } load = FLASH_EXECUTE, run = RAM_EXECUTE
Option 2, if you have defined the .run_from_ram section
.text:rts430.lib_div : { rts*.lib<div16u.obj>(.text) } .run_from_ram
.text:rts430.lib_mult : { rts*.lib<mult16_f5hw.obj>(.text) } .run_from_ram
.text:rts430.lib_printf : { rts*.lib<*printf.obj>(.text) } .run_from_ram
Refer to File:RAM
Function Example.zip for an example in CCS on how to move a
function to RAM for execution.
In IAR, the keyword __ramfunc can be placed in front of the function declaration to enable the function be copied from Flash to RAM during startup and the function will be referenced from the rest of the code in RAM.
See the rest of the code examples for all MSP430 devices here!
Want to squeeze a few more nanoAmps out of your application? Leverage the e2e (Engineer-to-Engineer) online community to get all of your ULP questions answered! Or, if you are an Ultra-Low Power pro, give back to the community with your expertise.
Go to MSP430's e2e online forum!
If you are posting on the forums in relation to this rule, try using the tag "ULP_5.3"
For technical support please post your questions at http://e2e.ti.com. Please post only comments about the article Compiler/diagnostic messages/MSP430/1532 here. |