EmbeddedRelated.com
Forums

Low power modes and UCOS

Started by Dave McLaughlin January 26, 2010
Hi All,

I am trying to get the low power modes to work under UCOS.

At this time I can get the RCM5450W to run under mode 5, OSC/8 in the call
to set_cpu_power_mode(5, CLKDOUBLER_OFF, SHORTCS_OFF);

If I try to use anything higher than this, ie the modes 6 to 10, it restarts
after about 2 seconds, which corresponds to the 2 second timeout on the
watchdog. The documentation indicates that the watchdog has to be hit during
modes 6 to 10 as the periodic interrupt is disabled.

Prior to shutting down the power I suspend all tasks that are not needed,
except for the one that reads the digital input that is used to bring it
back out of low power mode.

In my remaining task I simply loop around and check for the input going
active, then switch to full power and resume the sleeping tasks. This works
for modes 1-5 as expected.

I have a feeling I will have to write a special handler for this where I
just loop around after shutting down the power and in between tests, I hit
the watchdog timer to prevent it timing out. It would appear that UCOS is
not running in these modes due to the periodic timer being off!!

I have looked in the samples and can find nothing in the UCOS section etc.

Cheers,

Dave...

---
Very funny Scotty, now beam down my clothes!!!
---
http://www.embeddedcomputer.co.uk
---
--- In r..., "Dave McLaughlin" wrote:

> I have a feeling I will have to write a special handler for this where I
> just loop around after shutting down the power and in between tests, I hit
> the watchdog timer to prevent it timing out. It would appear that UCOS is
> not running in these modes due to the periodic timer being off!!

This is true: if you switch to the 32KHz oscillator, then the uC-OS scheduler will stop (it is based on a timer, and the timers do not operate on the 32KHz clock). You must indeed hit the watchdog in your loop. This is how I did it:
//==================================================// This function is called when no tasks are running; its purpose is to bring the
// machine in the "sleepy mode" and check for any conditions that may wake it up
// The result is returned in the global variable wakeUpTasks

/*** BeginHeader goSleepy */
void goSleepy (void);
/*** EndHeader */

void goSleepy (void)
{
int gpscr;

gpscr = GPSCRShadow;
WrPortI(GPSCR, &GPSCRShadow, 0xE0); // enable self-timed chip select
use32kHzOsc(); // reduce procesor speed to 32 kHz
set32kHzDivider(OSC32DIV_4); // and now even slower, 8 kHz

#asm nodebug
xor a ; we assume at this point that no tasks are running
ld (wakeUpTasks),a

.wait:
ld a,05ah
ioi ld (WDTCR),a ; hit the watchdog

ld a,(wakeUpTasks) ; check if an interrupt came on ser B or C
or a
jr nz,.done ; yes, either serial B or C got an input

lcall read_rtc ; in bc and de we have the current time
ld hl,(timer1 + 2) ; no, check first timer
push hl
ld hl,(timer1)
push hl
call lessThan ; timer expired?
jr c,.done ; yes, exit

.next_timer:
ld hl,(timer2 + 2) ; else, check second timer
push hl
ld hl,(timer2)
push hl
call lessThan ; timer expired? (bc and de are unchanged)
jr nc,.wait ; no, loop back for another round
; else exit
.done:
#endasm

WrPortI(GPSCR, &GPSCRShadow, gpscr); // restore original GPSCR
useMainOsc(); // set processor speed to normal
}

The function above is called when all uC-OS tasks are iddle; it switches the processor to 8 KHz clock and then waits either for an interrupt on the one of the two serial ports, or for two separate timers to reach a pre-programmed value. The loop hits the watchdog. Note that the critical part is written in assembly because there might be not enough time to execute the loop at 8 kHz if all those compares would have been written in C. However, if you don't have to test so many conditions as in my case, you might be able to write your routine completely in C.

Hope it helps,

Lix

--- In r..., "Dave McLaughlin" wrote:

> I have a feeling I will have to write a special handler for this where
I
> just loop around after shutting down the power and in between tests, I
hit
> the watchdog timer to prevent it timing out. It would appear that UCOS
is
> not running in these modes due to the periodic timer being off!!

This is true: if you switch to the 32KHz oscillator, then the uC-OS
scheduler
will stop (it is based on a timer, and the timers do not operate on the
32KHz
clock). You must indeed hit the watchdog in your loop. This is how I did
it:

//==================================================// This function is called when no tasks are running; its purpose is to
bring the
// machine in the "sleepy mode" and check for any conditions that may
wake it up
// The result is returned in the global variable wakeUpTasks

/*** BeginHeader goSleepy */
void goSleepy (void);
/*** EndHeader */

void goSleepy (void)
{int gpscr;gpscr = GPSCRShadow;
WrPortI(GPSCR, &GPSCRShadow, 0xE0); // enable self-timed chip select
use32kHzOsc(); // reduce procesor speed to 32 kHz
set32kHzDivider(OSC32DIV_4); // and now even slower, 8 kHz
#asm nodebug
xor a ; we assume at this point that no tasks are running
ld (wakeUpTasks),a.wait:ld a,05ahioi ld (WDTCR),a ; hit the watchdogld
a,(wakeUpTasks) ; check if an interrupt came on ser B or C
or a
jr nz,.done ; yes, either serial B or C got an input

lcall read_rtc ; in bc and de we have the current time
ld hl,(timer1 + 2) ; check first timer
push hl
ld hl,(timer1)
push hl
call lessThan ; timer expired?
jr c,.done ; yes, exit
ld hl,(timer2 + 2) ; else, check second timer
push hl
ld hl,(timer2)
push hl
call lessThan ; timer expired? (bc and de are unchanged)
jr nc,.wait ; no, loop back for another round.done: ; else exit
#endasmWrPortI(GPSCR, &GPSCRShadow, gpscr); // restore original GPSCR
useMainOsc(); // set processor speed to normal}
The function above is called when all uC-OS tasks are iddle; it switches
the
processor to 8 KHz clock and then waits either for an interrupt on the
one of
the two serial ports, or for two separate timers to reach a
pre-programmed
value. The loop hits the watchdog. Note that the critical part is
written in
assembly because there might be not enough time to execute the loop at 8
kHz if
all those compares would have been written in C. However, if you don't
have to
test so many conditions as in my case, you might be able to write your
routine
completely in C.

Hope it helps,

Lix
Hi Lix,

Thanks for that. I actually now just put all tasks into suspend mode and
after a few seconds, to allow them to suspend, I call the following to
switch to the lowest power mode.

set_cpu_power_mode(10, CLKDOUBLER_OFF, SHORTCS_ON);

Then I simply loop around checking the 2 IO ports that I have that wake up
the device. After I wake up, I delay a second or so and then resume the
suspended tasks. After testing this for the last few days it works just
perfectly.

OH, I and I did it all in C code too!! :o)

Dave...

---
Very funny Scotty, now beam down my clothes!!!
---
http://www.embeddedcomputer.co.uk
---

From: r... [mailto:r...] On
Behalf Of lixpaulian
Sent: 27 January 2010 22:53
To: r...
Subject: [rabbit-semi] Re: Low power modes and UCOS

--- In r..., "Dave McLaughlin" wrote:

> I have a feeling I will have to write a special handler for this where I
> just loop around after shutting down the power and in between tests, I hit
> the watchdog timer to prevent it timing out. It would appear that UCOS is
> not running in these modes due to the periodic timer being off!!

This is true: if you switch to the 32KHz oscillator, then the uC-OS
scheduler
will stop (it is based on a timer, and the timers do not operate on the
32KHz
clock). You must indeed hit the watchdog in your loop. This is how I did it:

//==================================================// This function is called when no tasks are running; its purpose is to
bring the
// machine in the "sleepy mode" and check for any conditions that may wake
it up
// The result is returned in the global variable wakeUpTasks

/*** BeginHeader goSleepy */
void goSleepy (void);
/*** EndHeader */

void goSleepy (void)
{

int gpscr;

gpscr = GPSCRShadow;
WrPortI(GPSCR, &GPSCRShadow, 0xE0); // enable self-timed chip select
use32kHzOsc(); // reduce
procesor speed to 32 kHz
set32kHzDivider(OSC32DIV_4); // and now even slower, 8
kHz

#asm nodebug

xor a ; we assume at this point that
no tasks are running
ld (wakeUpTasks),a

.wait:

ld a,05ah

ioi ld (WDTCR),a ; hit the watchdog

ld a,(wakeUpTasks) ; check if an interrupt came on ser B or C
or a
jr nz,.done ; yes, either serial B or C got an
input

lcall read_rtc ; in bc and de we have the current
time
ld hl,(timer1 + 2) ; check first timer
push hl
ld hl,(timer1)
push hl
call lessThan ; timer expired?
jr c,.done ; yes, exit

ld hl,(timer2 + 2) ; else, check second timer
push hl
ld hl,(timer2)
push hl
call lessThan ; timer expired? (bc and de are
unchanged)
jr nc,.wait ; no, loop back for another round

.done: ; else exit
#endasm

WrPortI(GPSCR, &GPSCRShadow, gpscr); // restore original GPSCR
useMainOsc(); // set processor speed to normal

}
The function above is called when all uC-OS tasks are iddle; it switches the
processor to 8 KHz clock and then waits either for an interrupt on the one
of
the two serial ports, or for two separate timers to reach a pre-programmed
value. The loop hits the watchdog. Note that the critical part is written in
assembly because there might be not enough time to execute the loop at 8 kHz
if
all those compares would have been written in C. However, if you don't have
to
test so many conditions as in my case, you might be able to write your
routine
completely in C.

Hope it helps,

Lix