PDA

View Full Version : spin command equivalent to sleep ?



mikea
03-31-2012, 11:00 PM
i have a program i would like to conditionally put itself to sleep while waiting for an rfid tag "swipe" . i found "abort, return" that might posibbly work. seems like there was other ways to put prop to a low power state waiting for an i/o input to wake it up. im using multiple cogs so even if there has to be one active cog to watch for the input it might help to put the others asleep.havent yet found other options reading prop manual.are there other options?- mike

pedward
03-31-2012, 11:03 PM
WAITPEQ -- Wait Pin Equal
WAITPNE -- Wait Pin Not Equal

mikea
03-31-2012, 11:13 PM
cool...thanks pedward -mike

Mike Green
03-31-2012, 11:28 PM
You can also put a cog to sleep for a period on the order of 50 seconds, then repeat. As a result, the cog is running for a few microseconds out of just less than a minute.

waitcnt(cnt)

This will do. The WAITCNT takes a few microseconds to execute. By then, the time CNT is well past and the WAITCNT will wait for just under 2^32 clock cycles before waking up again.

mikea
04-01-2012, 05:11 AM
am i using waitpeq correctly? it is in a cog by itself. i dont think i have the command correct. from copying an example "waitpeq(%00000 , |<5 ,0)" ..........means cog sleeps until i/o 5 equals 0.what is the "0" just before the end of the parentheses related to? another question is, it sounds like this only applies to the cog that it is running on. the intent of waitpeq in the code below is to hold up the entire program until i/o 5 equals zero. there are parallel cogs so i have to put this "sleep" method in them all right? or is it enough that it is ahead of "pub main" where the other cogs get started from? once the waitpeq command below is corrected (im sure im using it wrong) if "main" is the next line below it , should it return up to "pub main" and run like normal? or is that accomplished differently? sorry, lot of questions. thanks in advance for any help! -mike


code: [ _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz
_xinfreq = 5_000_000
baud=19_200
TX_pin = 0
obj
LCD : "FullDuplexSerial.spin"
var long stack[50]
long stack1[50]
long stack2[50]
pub go
cognew(sleep,@stack2)
pub main
cognew(lcd1,@stack)
cognew(restart,@stack1)

repeat
'
dira[9]~~
dira[8]~~
dira[28]~


if ina[28]==1
repeat
outa[8]~
!outa[9]
waitcnt(clkfreq/4+cnt)

else
outa[8]~~

Pub lcd1
LCD.start(TX_PIN, TX_PIN, %1000, 19_200)
waitcnt(clkfreq / 100 + cnt) ' Pause for FullDuplexSerial.spin to initialize
LCD.tx(22) 'set diplay no cursor, no blink
LCD.tx(17) 'turn on back light
dira[28]:=0
repeat
if ina[28]==1
repeat 3
' LCD.tx(212) 'tone length
'LCD.tx(221)
' LCD.tx(220) 'note
repeat
LCD.tx(12) 'clear screen
LCD.str(string("motion detected by girls room ")) 'display messageo
waitcnt(clkfreq/2+cnt) 'slow down so screen doesnt pulse
else

LCD.tx(12) 'clear screen
LCD.str(string("house is secure.")) 'display message
waitcnt(clkfreq/2+cnt) 'slow down
pub restart
dira[2]~
repeat
if ina[2]==0
waitcnt(clkfreq+cnt) 'ina[2] is a pushputton simulating system reset/arm ...future rfid replaces pushbutton
reboot

pub sleep
dira[1]~
waitpeq(%00000 , |<5 ,0)
main

]

John Board
04-01-2012, 05:44 AM
Although you've allready been told, here's my bit:

Waitcnt(cnt) This waits for a certain amount of time, example: waitcnt(clkfreq/X+cnt). X is the devision of seconds - so if x was "2" then it would wait 500ms, because 500 is half (1/2) of 1000ms (1 second). Or waitcnt(clkfreq*X+cnt). Where it would wait the number of seconds defined by "X". So if "X" was 3, then it would wait 3 seconds.

Although that might not be what you want, its a tiny snippet about waiting in SPIN.

-John

Mike Green
04-01-2012, 06:16 AM
When you post code, you can't just cut and paste it into a message window. The forum software eats the indenting unless you protect it with [ code ] [ /code ] tags and you have to have the indenting. See here:

http://forums.parallax.com/attachment.php?attachmentid=78421&d=1297987572 (http://forums.parallax.com/showthread.php?129690&p=978076&viewfull=1#post9780 76)

mikea
04-01-2012, 03:29 PM
i apologize about the code formatting above, hopefully the indents remain after i submit this post. in this code will the sleep method put the entire code to sleep since its before main? or does the order not matter since there are multiple cogs? also in this line , waitpeq(%000000, |< 5, 0) what does the zero at the end just before the parentheses represent?





CON
_clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz
_xinfreq = 5_000_000
baud=19_200
TX_pin = 0
obj
LCD : "FullDuplexSerial.spin"
var long stack[50]
long stack1[50]
long stack2[50]
pub go
cognew (sleep,@stack2)
pub main
cognew(lcd1,@stack)
cognew(restart,@stack1)
repeat
'
dira[9]~~
dira[8]~~
dira[28]~


if ina[28]==1 ' read motion sensor state , if high....alarm
repeat
outa[8]~ 'green led off
!outa[9] 'flash red
waitcnt(clkfreq/4+cnt)

else
outa[8]~~ 'no motion, steady green led

Pub lcd1
LCD.start(TX_PIN, TX_PIN, %1000, 19_200)
waitcnt(clkfreq / 100 + cnt) ' Pause for FullDuplexSerial.spin to initialize
LCD.tx(22) 'set diplay no cursor, no blink
LCD.tx(17) 'turn on back light
dira[28]:=0
repeat
if ina[28]==1
repeat 3
LCD.tx(212) 'tone length 'brief tone to draw attention to lcd screen
LCD.tx(221)
LCD.tx(220) 'note
repeat
LCD.tx(12) 'clear screen
LCD.str(string("motion detected by girls room ")) 'display message
waitcnt(clkfreq/2+cnt) 'slow down so screen doesnt pulse
else

LCD.tx(12) 'clear screen
LCD.str(string("house is secure.")) 'display message
waitcnt(clkfreq/2+cnt) 'slow down
pub restart
dira[2]~
repeat
if ina[2]==0 'pushbutton to reset program
reboot
waitcnt(clkfreq+cnt)
pub sleep
dira[5]~
dira[6]~
if ina[6]~ 'if pushbutton makes i/o 6 low
waitpeq(%000000, |< 5, 0) 'sleep cog until additional pushbutton makes i/o 5 low
main 'go to beginning of program and run normal

Mike Green
04-01-2012, 04:30 PM
It's best that you don't think of this stuff as "sleep". They're statements that cause the program to wait as suggested by the names. When a cog is executing a WAITCNT or WAITPxx, that cog goes into a low power mode until the condition is satisfied. As shown in the Propeller datasheet, the power consumption of the chip depends on how many cogs are executing normally vs. low power mode or stopped plus some fixed power overhead for things like the memory and the system clock. In order to "put the chip to sleep", all the cogs have to either be stopped or waiting for something, so they're in low power mode. Another thing you can do to save power is to slow down the system clock. Instead of running the Propeller at 80MHz with a 5MHz crystal and PLL16X mode, you can use PLL8X or PLL4X and run the whole thing at 40MHz or 20MHz and that saves power (see the datasheet graphs).

The bootloader transfers control (calls) to the first method in the program, "go" in your case. The first thing that does is to start another cog with a call to "sleep", then it stops itself because "go" exits which does a COGSTOP. Similarly the IF in "sleep" probably doesn't succeed the first time it's executed, so "sleep" ends up exiting without doing the WAITPEQ or call to "main" and that does a COGSTOP.

It looks like you need to understand what's going on before you unnecessarily complicate your program. Don't worry about power consumption. If you want to understand how cogs work and how WAITxxx statements work, use a simple test program, as simple as possible. Make sure you understand it at each step. You can experiment with the WAITxxx stuff without starting any new cog and you can experiment with multiple cogs without using the WAITxxx statements. I'd recommend the Propeller Education Kit labs for an introduction.

The last parameter of the WAITPxx statements specifies whether the I/O pins are in the first bank of I/O pins (0-31) or the second bank of I/O pins (32-63) which don't exist in the current Propeller. It's ignored in the current Propeller.

mikea
04-01-2012, 05:12 PM
thanks mike, that was helpful. -mike

localroger
04-01-2012, 05:52 PM
If you're trying to reduce power consumption, you might want to reconsider using FullDuplexSerial, since that starts a cog that runs full-speed regardless of what the foreground cog (your app) is doing.

If the baud rate isn't too high (it probably isn't for a RFID reader) you can use something like Simple_Serial written in Spin to wait for the start bit of the first character via WAITPEQ, then clock in the message and act on it before going back to sleep. One cog, nearly all of its time spent sleeping, overall power consumption under a milliamp.

Tracy Allen
04-01-2012, 07:37 PM
mikea,

The BASIC Stamp SLEEP command takes the current down to less than 50 ľA, that is, assuming an efficient voltage regulator. To achieve that level or better on the Prop, the main trick is to drop the clock frequency down to its RCslow setting of 20kHz, where it can still watch for transitions on inputs pins and then wake up to the higher frequency when need be. It is not hard to do that. The program can leave the fullDuplexSerial cog running, because at 20kHz each cog adds only about 4 ľA to the operating current. The total operating current with a good low Iq regulator can be around 20ľA. When waking up, there has to be a delay of about 10ms to let the crystal come up to speed, and after that (but NOT during sleep) fullDuplexSerial will be ready to send and receive. The waitxxx commands by themselves can get down to the milliamp floor, but it takes the change to RCslow to really get down to the basement. Here is a little demo program of how to change the clock frequency in response to a transition on WAKE_PIN, although I set up this program to sleep for 2 seconds.


CON
_clkmode = xtal1 + pll16x '
_xinfreq = 5_000_000

CLK_HZ = 80_000_000 ' _clkfreq, but have to state it
CLK_SELECT = >| (CLK_HZ / _xinfreq) + 2 ' e.g. clksel bits=%111 when _clkfreq/_xinfreq = 80MHz / 5MHz

WAKE_PIN = 27
LED_PIN = 15

OBJ
fds : "fullDuplexSerial"

PUB main | x
' initialize all pins here
fds.start(31,30,0,9600)
waitcnt(clkfreq/10+cnt)
dira[LED_PIN]~~
outa[LED_PIN]~~ ' LED on while awake
repeat
fds.str(string(13,"testing 123... "))
fds.dec(x++)
waitcnt(clkfreq/2 + cnt) ' could do other tasks here
' set all pins to lowest Iq state here before sleep
' be sure all serial buffers are flushed
outa[LED_PIN]~ ' LED off while asleep
doRCslow ' drop to sleep state
waitcnt(clkfreq*2+cnt) ' sleeps two seconds
'waitpne(ina[WAKE_PIN] << WAKE_PIN, |< WAKE_PIN, 0) ' or, wake on pin transitiion
doClockUp ' go back to original 80MHz clock
outa[LED_PIN]~~ ' led ON

' ---- clock modes --------------------------------------------
' note 75 us global delay when switching clock sources

PRI doRCslow
clkset(%0_00_00_001, 20_000) ' drop to RCSLOW 20 KHz

PRI doClockUp ' transition to fast stable clock
clkset(%01101000, 12_000_000) ' running on RCfast, but xtal and pll are warming up
waitcnt(clkfreq/100 + cnt) ' wait 10 milliseconds
clkset(%0_11_01_000 | CLK_SELECT, CLK_HZ) ' switch to xtal1+pll

mikea
04-02-2012, 11:08 PM
thanks tracy and local roger for the examples