Shop OBEX P1 Docs P2 Docs Learn Events
spin command equivalent to sleep ? — Parallax Forums

spin command equivalent to sleep ?

mikeamikea Posts: 283
edited 2012-04-02 15:08 in Propeller 1
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

Comments

  • pedwardpedward Posts: 1,642
    edited 2012-03-31 15:03
    WAITPEQ -- Wait Pin Equal
    WAITPNE -- Wait Pin Not Equal
  • mikeamikea Posts: 283
    edited 2012-03-31 15:13
    cool...thanks pedward -mike
  • Mike GreenMike Green Posts: 23,101
    edited 2012-03-31 15:28
    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.
  • mikeamikea Posts: 283
    edited 2012-03-31 21:11
    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 BoardJohn Board Posts: 371
    edited 2012-03-31 21:44
    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 GreenMike Green Posts: 23,101
    edited 2012-03-31 22:16
    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:

    attachment.php?attachmentid=78421&d=1297987572
  • mikeamikea Posts: 283
    edited 2012-04-01 07:29
    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 GreenMike Green Posts: 23,101
    edited 2012-04-01 08:30
    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.
  • mikeamikea Posts: 283
    edited 2012-04-01 09:12
    thanks mike, that was helpful. -mike
  • localrogerlocalroger Posts: 3,452
    edited 2012-04-01 09:52
    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 AllenTracy Allen Posts: 6,664
    edited 2012-04-01 11:37
    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.
    [SIZE=1][FONT=courier new]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[/FONT][/SIZE]
    
  • mikeamikea Posts: 283
    edited 2012-04-02 15:08
    thanks tracy and local roger for the examples
Sign In or Register to comment.