This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430 (FR6989) explanation for different current consumption - only variable++ and additional port-access

Other Parts Discussed in Thread: MSP430FR6989, ENERGYTRACE, MSP-EXP430FR5969, MSP-FET

Hi guys, me again

http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/356755.aspx

Still using the MSP430FR6989, but this topic is different and is more general so I will start a second thread. For those who did not read my other post which I have linked in above - I'm trying to find the best settings for reducing the current consumption to minimum while still having enough computation resources to handle some tasks.
 What have I done? Well, as mentioned I'm using the MSP430FR6989 and set the DCO to work with 2.67MHz (one of the calibrated frequencies). This clock is sourcing MCLK and SMCLK. ACLK is sourced by the 10kHz VLOCLK. Now I wanted to figure out which action consumes how much power and I am a little bit confused about the result.

This is my simple code:

#include "mcu_configuration.h"
#include <stdint.h>



volatile uint16_t var_counter = 0;


void main( void )
{
  // Watchdog timer is stopped in _system_pre_init

  mcu_configure_ports();
  mcu_configure_clock_module();


  while( 1 )
  {
    var_counter++;

    if( MCU_BUTTON_LEFT_PRESSED )  TEST_LED_1_ON;
    else TEST_LED_1_OFF;

    if( MCU_BUTTON_UP_PRESSED )    TEST_LED_2_ON;
    else TEST_LED_2_OFF

    if( MCU_BUTTON_ENTER_PRESSED ) TEST_LED_3_ON;
    else TEST_LED_3_OFF

    if( MCU_BUTTON_DOWN_PRESSED )  TEST_LED_4_ON;
    else TEST_LED_4_OFF;

    if( MCU_BUTTON_RIGHT_PRESSED ) TEST_LED_5_ON;
    else TEST_LED_5_OFF;
  }
}

The definitions represent nothing more than

if( ~P6IN & 0x01 ) P6OUT |= 0x20;

There are 5 buttons and five LEDs which are switched on and off depending on the state of the buttons. Now I ran the program in four different ways:

1.: Complete program as it is listed above - result of current consumption (USBFET disconnected): 412uA

2.: Only counting up the variable, reading from inputs and writing to outputs marked out - result: 234uA (NICE!!!)

  while( 1 )
  {
    var_counter++;

    //if( MCU_BUTTON_LEFT_PRESSED )  TEST_LED_1_ON;
    //else TEST_LED_1_OFF;

    ...
  }

3.: Counting the variable and only read the inputs without doing anything on the outputs - result: 368uA

  while( 1 )
  {
    var_counter++;

    if( MCU_BUTTON_LEFT_PRESSED );  //TEST_LED_1_ON;
    //else TEST_LED_1_OFF;

    ...
  }

4.: Counting the variable and only writing to ports (without change) - result: 446uA

while( 1 )
  {
    var_counter++;

    /*if( MCU_BUTTON_LEFT_PRESSED )*/  TEST_LED_1_ON;
    //else TEST_LED_1_OFF;

    ...
  }

I cannot imagine why these current consumptions occur. Why do the port-actions require so much current and why consumes reading and writing from and to the ports less power while doing more with respect to only write the outputs while they never change?

Is there anybody of you that has an idea for that? I'm trying to reduce the current consumption to the absolute minimum - but: I need a static low current without using the low-power-modes. I'm not having a battery-powered application. I just need ultra-low-power while active.

Thanks, Dennis

  • Hi everyone!

    OK, so I have got new information for you. There is a difference in current consumption depending on the code I write, so maybe there is the problem, but in my opinion it should not make any difference...but obviously - it does!

    I'm only looking at one input button and one output LED now because it is the same behaviour for every in/out pin combination.

    Let's take P6.0 as input pin where a button is connected to which pulls the pin down to GND. There is an external pull-up-resistor (220k - the internal ones are too low value).

    Then there is P6.5 which drives the gate of an n-channel FET which controls the LED.

    Initialization:

    P6OUT  = 0x00;
    P6DIR  = 0x20;

    Then in the main() my code is (the higher current one):

    if( ~P6IN & 0x01  ) P6OUT |= 0x20;
    else P6OUT &= ~0x20;

    I'm inverting the P6IN-register which gives me a one at bit 0 if the button is pressed and AND it with 0x01 to see if there is a key-press. Works fine, but if I write:

    if( !(P6IN & 0x01) ) P6OUT |= 0x20;
    else P6OUT &= ~0x20;

    it works also fine except it draws about 100uA less current. But what is the difference between the two ways?


    Any idea?

    Dennis

  • Hi Dennis,

    One thing that you should make sure to be aware of when using FRAM devices and trying to measure active mode current consumption: your active mode current is going to depend on the cache hit ratio of your code. Because of this, I could see that even simple re-arranging of your code or commenting out lines could cause you to get slightly different active power numbers, because it could impact the cache hit ratio that you are seeing in that code.

    You can see in the MSP430FR6989 datasheet www.ti.com/lit/gpn/msp430fr6989 in section 5.4 that the active mode currents are listed for different cache hit ratio percentages. This is because when you have a cache hit, the instruction executes from the cache and there is no FRAM access, and this is lower power. If you have a cache miss, then an FRAM access occurs which consumes a little more power. This is why you can see the higher the cache hit ratio, the better the current consumption value in the chart in the datasheet.

    Some resources discussing FRAM and Cache that might help you, in addition to the device datasheet:

    It sounds like you are trying to profile particular sections of your code, but since moving the code around or isolating it is going to impact your cache hit ratio and therefore your current, this is difficult. One thing you may want to think about looking into is EnergyTrace++: www.ti.com/tool/energytrace You will need the right tool (the new MSP-FET or the MSP-EXP430FR5969 launchpad) and most recent IDE version (CCSv6 or latest IAR) to be able to use this though. With EnergyTrace++ you can see the energy used by each function in active mode, so you'd be able to let your functions all run in the context of your program so they'd be showing their real numbers for when they run within your program rather than different cache hit ratio if you isolate them, but still be able to determine which functions are your energy hogs and try to optimize them. EnergyTrace also lets you save off a profile, make changes, and then compare your new profile to your saved profile to see how your energy results changed. This could be useful for what you are doing. The EnergyTrace app note walks through how to do this: www.ti.com/lit/pdf/slaa603 www.ti.com/lit/zip/slaa603

    Regards,

    Katie

  • counting up the variable is a single instruction. And the while loop one more branch instruction. So the simple increment loop runs on  two instructions. In this specific case, the whole code execution maybe runs from the FRAM cache. The only two parts used (after the first loop) are CPU and FRAM cache. No further access to FRAM or peripherals. This would explain the low power consumption. Add two NOPs to force the loop to be larger than the FRAM cache. Just to be sure.

    Once the code gets larger, it won’t run from FRAM cache but needs constant access to FRAM. Thus the higher current.
    The difference between just reading or writing the port might be explained by the possibility that a bus read needs less than a bus read-modify-write.
    Keep in mind that current is an average value. With both, test and write, the code loops slower, so both instructions are executed less often, giving a different average current than looping over one or the other – depending on their execution time and therefore their share on total run time.

    If you add one or two NOPs to the loop in all cases, you should be able to force a cache-miss and then eliminate the plain loop time from total loop time and then extract the current needed for one or other operation. If you want to go that far.

    I must admit that I’m a bit surprised about the difference between a plain port read and a port write, but this might be partly because the port write is actually a RMW instruction, so two port accesses per loop.

    About the difference between your two IF cases, well, it would be interesting how the compiler compiles them. In the first case, you read P6IN, perform an XOR 0xFF, then AND it with 1 and do a conditional branch. In the second case, it might be that the compiler just does a bit test on P6IN and then does the branch (with inverted condition).
    However, unless you normalize your results by the number of iterations done per second, you can’t really compare the results.

**Attention** This is a public forum