MSP430 Low Power Modes in FreeRTOS

dave_marsden wrote on Wednesday, August 20, 2008:

Greets to all,

I would like to ask if anyone has experience with the low power modes of the MSP430, I’m using the demo code available on this site with CrossStudio 1.4 and the associated SoftBaugh evaluation board for the 449 variant.

I’ve tried calling the low power modes the MSP430 offers starting with the simplest mode (LPM0) that still allows the system to wake on an interrupt from the various timers, hence expecting the system to wake on the next scheduler tick (which it does). The issue is that the task that contains the low power mode call becomes non-functional (perhaps suspended?, blocked? or disabled?) and its respective code is never executed again. I am currently examining the stack as well as sifting through the scheduler code to try and work out what is going on.

But if anyone else has any knowledge of what is going on and a means to enable low power modes in the MSP430 without killing off the operation of the executing task/code I’d be interested to hear their views. I’ve checked out much of the forum and have not found any other discussion concerning low power operation, so any such info on the topic might be of interest to others as well.

Thanks in advance,
Dave

davedoors wrote on Wednesday, August 20, 2008:

It is normal to put the micro into sleep mode from the idle task so there is no reason why it should not work.

dave_marsden wrote on Thursday, August 21, 2008:

Hi Dave,

Did some further monitoring of the situation and discovered that the ISR used by FreeRTOS has a low power issue with the micro on wakeup.

Using the MSP430F449 on the evaluation board, should any of the low power modes be referenced by any task or via the idle task, the actual state of the CPU remains set to that of low power operation even after the interrupt fires, making it impossible for the task that launched the mode change to progress on. A quick check of the SR register shows that the CPU core and the oscillators for the respective power mode were not restored to operation after interrupts fired. upon calling such a mode the CPU and oscillators were correctly turned off, but upon an interrupt firing the CPU and oscillators were never restored in any mode. I suspect that the scheduler was attempting to restore the SR register with the value placed on the stack by LMPx operation.

I checked low power operation for modes LPM0 to LPM3 and they all suffered from this problem, after some study of the FreeRTOS ISR routine and scheduler operation it was decided to add a single line of assembler at the start to ensure that once an interrupt fires the micro will be fully operational (which it should be).

This problem only affects the original task that launched the low power mode operation only, other tasks continue to operate normally. The fix below will correct this issue.

The file to modify in the Rowley CrossStudio 1.4 demo code for the MSP430F449 is called
"portext.asm" and the following addition enables low power operation to work as intended :

Before :

MSPINT    macro name
_##name::
        call    #_portSAVE_CONTEXT       
        call    #_ISR##name                      
        br    #_portSWITCH_EXIT           
        endm

After :

MSPINT    macro name
_##name::
        bic      #(SCG1+SCG0+OSCOFF+CPUOFF),0(SP) /* ensure CPU is operational */
        call    #_portSAVE_CONTEXT       
        call    #_ISR##name                      
        br    #_portSWITCH_EXIT           
        endm

I suspect this problem might exist in SafeRTOS as well but won’t know till I buy it.

Thanks

rtel wrote on Thursday, August 21, 2008:

This is an interesting thread, but I don’t quite understand the implication here.  Correct me where I go wrong:

1) A task is running, probably the idle task as its going to put the processor to sleep.

2) The task places the processor into a sleep mode, so the code stops executing (a context switch does not occur so no registers are saved, the code just stops).

3) An interrupt occurs and wakes the processor.  System registers are restored to their awake state, and the code starts executing again.

4) The first thing the processor does is go into the interrupt entry sequence, where the registers may get saved - but by this time the registers should show that a power down state is not currently existing.

5) Another task is chosen to run, and its registers are restored - this task knew nothing about power down.

6) The original task may at some time in the future have its context restored.

So where does it go wrong?  Does the task that places the processor into a sleep state have to manually clear this action when the processor wakes up (I could go and look at the manual of course)?  In which case immediately entering the interrupt would prevent the the flag being cleared - but the processor must have already woken up otherwise the code would not be executing?

Regards.

richard_damon wrote on Thursday, August 21, 2008:

It is possible that a chip designer decides that the "sleep state" of the processor is part of the state saved by the interupt waking the processor up, so that by default, when the interrupt returns the processor goes back to sleep. If this is so, there may need to be some code added to clear this state so the processor continues on the return from interrupt. I am not familiar with this processor to know if this is the case for this one, but it would be worth looking into.

davedoors wrote on Thursday, August 21, 2008:

-----in which case either the interrupt code itself would need to clear this state or only interrupt code would ever execute once the processor was in power down. In the former case the interrupt code can still do this but it would as a minimum have to be part of the context switch code.

david_farrell wrote on Friday, August 22, 2008:

There can be more to sleep than the waking interrupt .  What if you turn off some peripheral clocks?
Or drive a pin to turnoff the power to external circuits.  Someone (the same task) has to know to restore
this.  So I would vote  the task that places the processor into a sleep state does  has to manually clear this action.
I also wonder what should happen with something like a power fail interrupt.   The logic starts to spread
out to many places. Maybe reset should marshal all of these.  I will soon have to implement this is a product I am
currently working on and I am most concerned about how hard this is going to be for me to troubleshoot.
David.

woops_ wrote on Friday, August 22, 2008:

How about you suspend the scheduler, put the thing to sleep, when you wake up due to interrupt do any manual clean up necessary, then unsuspend the scheduler.

or

Raise your priority to highest, put the thing to sleep, when you wake up doe to interrupt do any manual clean up necessary, then set priority back down.

either way you want to ensure the task that runs first after wake up is the task that was running when sleep was entered.

dave_marsden wrote on Saturday, August 23, 2008:

Greetings Gents,

I feel that the main issue overall is that the switch to any of the low power modes causes changes to the stack of the currently running task which FreeRTOS is not aware of, this in turn then affects that task each subsequent task switch.

The MSP430 saves the program counter and the status register to the stack just prior to halting the micro & oscillators as it enters any of it’s four low power modes. The RTOS maintains it’s own stack & custom ISR which is affected by this operation.

Somewhere along the line the status bits of the SR register that keep the CPU core turned off and oscillators off are transferred to the local stack for the calling task and are never restored with subsequent interrupts.

When system tick of the RTOS finally results in another context switch to another task the CPU powers back up as the status bits of the SR register for that tasks stack are still correctly saved, hence other tasks remain unaffected, only the original calling task.

That one line of assembler I listed early on in this thread will fix the issue and ensure the SR register of the MSP430 is correctly set at wake-up. I am curious if the developers of FreeRTOS have looked into this issue, as it may well affect other CPUs that directly modify the stack without any external intervention before carrying out some form of mode change.

Thanks

david_farrell wrote on Saturday, August 23, 2008:

Sorry about Hijacking the thread, the low power theme is of great interest to me.

What you are describing is more significant than just your low power problem.  I think
you are saying that the complete context is not saved and your solution is
overriding this error.  You should examine the stack to see what SR is pushed. I suspect
the SR is pushed twice, once by the halt which is the correct one, and once
by the port code which is the SR of the low power state.  Maybe a fault is occurring
and the SR of the NMI is somehow being used.

Some of what you are doing is supposed to happen automatically. Maybe errata?

slau056g.pdf  p.32 "6) The SR is cleared with the exception of SCG0, which is left unchanged.
This terminates any low-power mode. Because the GIE bit is cleared,
further interrupts are disabled."

For my application (SAM9XE) I can see where the context save and restore may have to
include several hw register to preserve the power state of the instrument I
am designing.

You may want to try contacting Milos Prokic

davedoors wrote on Sunday, August 24, 2008:

In most processors when you request a low power mode you just set a bit in a register. When the low power mode exits the bit gets set back to its normal state. From what you say here this is not the case in the MSP430, and in fact the MSP430 somewhat translates a request to sleep into something like the following sequence.

a push current status
b sleep
c ?
d pop old status

so an interrupt occurring after sleep has been called will execute in step c, before the old status has been popped. Assuming it does not actually generate this code sequence it must have some sort of non atomic microcode sequence.

This does not make sense to me in so many different ways. I cannot see how the interrupt can execute in line c without the processor being awake. I cannot see how it will restore the processor state after the interrupt has executed (and potentially switched to another task). There is only one thing for it, I need to read the MSP430 manual!

dave_marsden wrote on Monday, August 25, 2008:

Essentially with FreeRTOS on an MSP430 if a task enters any of the low power modes it modifies the SR to reflect the mode chosen.  The highest power down mode stops the CPU clock (CPU OFF).  The "stopped" CPU state is locked into the status register.

When an interrupt occurs, the status register is preserved on the task’s stack by the MSP430 hardware.  The CPU then clears the power down registers to allow the interrupt service routine to run.  The OS then save the remaining CPU context and proceeds with the interrupt handler.

Eventually the executive attempts to run the task that invoked the low power mode.  The processor context is restored including the status register which has the CPU “stop” state and the processor stops without executing and of the task’s code.  This repeats indefinitely, effectively suspending the task.

The resolution is to modify the task stack to clear the low power mode flags, in particular the CPU off within the interrupt handler so the task can resume execution when the next interrupt occurs.  This must occur before any attempt is made by the OS to resume a task that put the system into low power mode.

The key to all this is the CPU preserves the CPU OFF state of the interrupted task before the interrupt service routine executes and restores the task to that state before executing any instructions.  Unless the CPU OFF, SCG1 and OSCOFF bits are cleared before trying to run the task, it will never proceed beyond the low power command.

david_farrell wrote on Tuesday, August 26, 2008:

My opinion is that the interrupt occurring for wake would only use the ARM stack, low level
code and should not be passed on to the RTOS. The RTOS state (context) should restored
to exactly the same as when the power down occurred.  The entry/exit for power down
should not even consider any RTOS is present, and the RTOS should not know the power
down occurred. For the overall system not to know, time may have to  be added to the
tick counter, but this gets complicated by anything scheduled in between.
Most hardware designs support this, automatic store of the state prior to power down
and restore of that same state on wake.

dave_marsden wrote on Wednesday, August 27, 2008:

There is a distinction between power down, brown out and LPM0 through LPM3.  LPM0 through LPM3 do not cause the processor to restart, but rather allow for resumption of execution with the CPU context intact.  To the execution unit time appears to have stopped.  The actual low power mode determines which internal clocks remain active.  If the internal timers are configured to a clock source which remains active in the low power mode, then there is no need to compensate for the interval that the CPU was in the low power state.  This also allows the OS’s tick timer to wake up the system at the same tick interval regardless of low power or full speed operation.

It is quite normal for a battery powered MSP430 system to enter the power down mode as quickly as practical and resume equally promptly.  Normally the idle task defines to the system what should occur if no task require servicing.  In a battery powered system, the thing to do when idle is conserve energy and to be ready to resume activity as efficiently (time and energy) as possible.

Performing system power up initialization would be extremely energy inefficient if it occurred every few milliseconds, hence the requirement to have the system enter a low power mode immediately in the event of no other actions required, to wait until the next clock tick or other system relevant event before resuming execution.

david_farrell wrote on Thursday, August 28, 2008:

I have 2 goals. (1) reduce dynamic current as much as possible to save my primary battery. Halt or reducing processor speed during the idle task would do this. (2) reduce static current as much as possible. This requires a marshaling task for me.  This is a state where essentially the product is off and a key press wakes it up.  A backup battery would be capable of supplying power in this mode (while one replaces the primary battery).
Maybe I’m misunderstanding parts of FreeRTOS but I think there would be some ambiguity trying to do (part 2) in the idle task as to which tasks were suspended to cause entry to idle that is not there when using a marshaling task.  Again, sorry for hijacking it has been interesting food for thought.

dave_marsden wrote on Friday, August 29, 2008:

You could use the idle task for this function if you don’t require any timers to be active.

Essentially you would create an idle task which would take the following actions:

1.  Put all peripherals into lowest power mode.
2.  Configure the system so the wake up source can generate an interrupt.
2.  Enter LPM3 (disabling all clocks except ACLK (usually a 32.768KHz crystal).

The interrupt handler would reset the registers cleared by the LPM3 command to the status register on the stack.  This should be done before any other stack operations might occur.  When the interrupt handler exits, the idle task will be activated.

After the LPM3 instruction, add instructions to activate any peripherals that might need to be activated (the timers will resume operation automatically), especially those the RTOS is reliant upon.  At this point the RTOS is again in control of your system.

jwestmoreland wrote on Friday, August 29, 2008:

Dave,

I suppose you haven’t ‘tested’ this yet - but I think that is an awesome suggestion.  It’s one that I’ve thought about as well.

It would be interesting to see how the MSP430 performs w/FreeRTOS switching in and out of LPM modes - something I’ve wanted to ‘play’ with.

Regards,
John W.

dave_marsden wrote on Monday, September 01, 2008:

The LPM0 through LPM3 modes work with the MSP430, provided you make the interrupt handler changes outline earlier.  The powering up and down of peripherals is pretty standard, but you have to use some intelligence there - going to low power mode of every tick could mean a lot of peripheral re-initialization which may not always give the lowest power draw.  It might be worth 0.5 nA to just leave the A/D idle for example.

As always your mileage may vary.