ULP Advisor > Rule 5.1 Avoid processing-intensive operations: modulo, divide

ULPAdvisorBanner.PNG

ULP Advisor - Rule Table

ULP 1.1 Ensure LPM usage
ULP 2.1 Leverage timer module for delay loops
ULP 3.1 Use ISRs instead of flag polling
ULP 4.1 Terminate unused GPIOs
ULP 5.1 Avoid processing-intensive operations: modulo, divide.
ULP 5.2 Avoid processing-intensive operations: floating point
ULP 5.3 Avoid processing-intensive operations: (s)printf()
ULP 6.1 Avoid multiplication on devices without hardware multiplier
ULP 6.2 Use MATHLIB for complex math operations
ULP 6.3 Use Low Energy Accelerator (LEA) software library
ULP 7.1 Use local instead of global variables where possible
ULP 8.1 Use 'static' & 'const' modifiers for local variables
ULP 9.1 Use pass by reference for large variables
ULP 10.1 Minimize function calls from within ISRs
ULP 11.1 Use lower bits for loop program control flow
ULP 11.2 Use lower bits for port bit-banging
ULP 12.1 Use DMA for large memcpy() calls
ULP 12.1b Use DMA for potentially large memcpy() calls
ULP 12.2 Use DMA for repetitive transfer
ULP 13.1 Count down in loops
ULP 14.1 Use unsigned variables for indexing
ULP 15.1 Use bit-masks instead of bit-fields

Let us know what you think! Feedback, suggestions & comments
are welcome @ ULPAdvisorFeedback@list.ti.com

What it means

Modulo and divide functions are processor intensive and consume many instruction cycles, which waste time and energy. While the MSP430 still performs extremely well on math-intensive functions when compared to other 8-bit/16-bit micro-controllers thanks to its advanced and efficient CPU architecture, more optimization in software to minimize these types of functions could still result in even lower power consumption.

Risks, Severity

Using math functions such as modulo or divide adds a significant number of instructions to your program execution. This consequently results in additional power and energy consumption.

Why it is happening

The project code contains modulo or divide (math) operation.

Code Example

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.

  1. Reserve a memory region in FLASH to store the functions and a memory region in RAM for copy/execution.

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
...
  1.  Create a section to load from FLASH_EXECUTE & run from RAM_EXECUTE:
.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!

Code Example

Refer to 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!

More Resources

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.1"

E2e.jpg For technical support please post your questions at http://e2e.ti.com. Please post only comments about the article Compiler/diagnostic messages/MSP430/1530 here.