Shop OBEX P1 Docs P2 Docs Learn Events
cognew, cogstop help — Parallax Forums

cognew, cogstop help

TCTC Posts: 1,019
edited 2014-02-03 17:18 in Propeller 1
Hello all.

I have personally never used cognew, or cogstop. Well I am giving it a shot. I still do not fully understand yet, but I am learning. I have hit a road block that I have no idea why.
con

  CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
  MS_001   = CLK_FREQ / 1_000
  US_001   = CLK_FREQ / 1_000_000


var
  word  _timer        'Timer output
  byte  timerID       'Timer COG ID 
  long  TimerStack[128]

pub pause(ms) | t

'' Delay program ms milliseconds

  t := cnt - 1088                                               ' sync with system counter
  repeat (ms #> 0)                                              ' delay must be > 0
    waitcnt(t += MS_001)

PRI Timer                       'Timer

  repeat
    pause(1000)
    _timer := _timer - 1

PRI start_timer

  stop_timer
  timerID := cognew(timer,@TimerStack)

PRI stop_timer

  if timerID > -1
    cogstop(timerID)

The way it sits. the code will frezze at "start_timer"
but if I comment out
stop_timer
from the start_timer object, my program will run.

I copied "stop_timer" right the manual (page 81), I just changed the CogID to timerID.

Could someone please tell me why it will not work, and what is going on so I can better understand it.

Thanks
TC

Comments

  • SRLMSRLM Posts: 5,045
    edited 2014-02-03 15:08
    Isn't timerID initialized to 0? So, on the first time through it will call cogstop(0), which stops the main cog?

    Usually what people do is store cognew+1 to get around this. Then use "if timeID > 0".
  • TCTC Posts: 1,019
    edited 2014-02-03 15:14
    SRLM wrote: »
    Isn't timerID initialized to 0? So, on the first time through it will call cogstop(0), which stops the main cog?

    Usually what people do is store cognew+1 to get around this. Then use "if timeID > 0".

    Ahh, that makes sense. The manual doesn't say anything about that. That is why I was getting confused. Thanks.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-03 16:08
    As we say during awards season here in Hollywood... for your consideration.

    This simple object (I'm assuming that's what you were going for) uses the essential architecture (start, stop, public methods, private methods/pasm) of most objects.
    var
    
      long  timercog
      long  timerstack[16]
    
      long  ms
    
    
    pub start
    
    '' Start millisecond countdown timer
    '' -- returns 1..8 (true) if successful
    
      stop                                                          ' stop if already running
    
      timercog := cognew(timer, @timerstack) + 1                    ' launch timer
    
      return timercog
      
    
    pub stop 
    
      if (timercog)
        cogstop(timercog - 1)
        timercog := 0
    
    
    pub read
    
      return ms
    
    
    pub set(value)
    
      ms := value
         
        
    pri timer | t                                                   ' launch with cognew
    
      t := cnt                                                      ' sync loop timing
      repeat                                                
        waitcnt(t += (clkfreq / 1000))                              ' wait 1ms
        if (ms)                                                     ' if still running
          --ms                                                      '  decrement
    


    You'll want to get comfortable with synchronized loops -- as in my version of the timer method. This is discussed in the section on waitcnt in the manual. Your original version has a loop longer than 1ms; the delay is that long, plus you have loop overhead that was not accounted for. The synchronized loop structure takes care of that (this is one of the best features of waitcnt)

    BTW, you don't need a stack that big for a simple method. It's not perfect, but I tend to use this formula for calculating stack space

    8 + # of local variables + 4 per external call + (add up # of locals in external calls)

    ...though I tend to use 16 as a minimum.
  • TCTC Posts: 1,019
    edited 2014-02-03 16:49
    JonnyMac wrote: »
    This simple object (I'm assuming that's what you were going for) uses the essential architecture (start, stop, public methods, private methods/pasm) of most objects.

    You are exactly right. It is for a simple object for my main program.
    You'll want to get comfortable with synchronized loops -- as in my version of the timer method. This is discussed in the section on waitcnt in the manual. Your original version has a loop longer than 1ms; the delay is that long, plus you have loop overhead that was not accounted for. The synchronized loop structure takes care of that (this is one of the best features of waitcnt)

    I did see that, but I am having trouble understanding it. lets say;
    pri timer | t                                                   ' launch with cognew
    
      t := cnt                                                      ' sync loop timing
      repeat                                                
        waitcnt(t += (clkfreq / 1000))                              ' wait 1ms
        if (ms)                                                     ' if still running
          --ms                                                      '  decrement 
    

    ~if cnt = 500
    ~then waitcnt= 500 + (80,000,000 / 1000) = 80,500
    ~do stuff
    ~repeat
    ~then waitcnt= 80,500 + (80,000,000 / 1000) = 160,500

    How does it account for the stuff in the middle?

    I am so sorry if I am WAY off base, I am just trying to get a better grasp on this.
    BTW, you don't need a stack that big for a simple method. It's not perfect, but I tend to use this formula for calculating stack space

    8 + # of local variables + 4 per external call + (add up # of locals in external calls)

    ...though I tend to use 16 as a minimum.

    I completely agree, it is. But it was a starting point for me, I was planing on using "Stack Length object" to get a better stack amount.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2014-02-03 17:02
    Remember that waitcnt is waiting for a specific value in the cnt register, it is not waiting a specific number of system ticks. That is to say that waitcnt is NOT the Spin equivalent of pause().

    Think of it this way: we look at where the cnt register is now, then add the number of ticks in 1ms to that -- then wait for that value in the cnt register.

    Agian, the manual (page 219) has a good explanation; you should read that.
  • TCTC Posts: 1,019
    edited 2014-02-03 17:18
    JonnyMac wrote: »
    Remember that waitcnt is waiting for a specific value in the cnt register, it is not waiting a specific number of system ticks. That is to say that waitcnt is NOT the Spin equivalent of pause().

    Think of it this way: we look at where the cnt register is now, then add the number of ticks in 1ms to that -- then wait for that value in the cnt register.

    Agian, the manual (page 219) has a good explanation; you should read that.

    Now see, your explanation makes more sense to me. I was having so much trouble understanding what the manual was talking about.
    Since the System Clock is a global resource that changes every clock cycle, to delay for a certain number of cycles from “now” we need a value that is added to the current System Counter value. The cnt in “50_000 + cnt” is the System Counter Register variable; it returns the value of the System Counter at that moment in time. So our code says to wait for 50,000 cycles plus the current value of the System Counter; i.e.: wait 50,000 cycles from now. Assuming that an external 5 MHz crystal is being used, 50,000 cycles is about 10 ms (1/100th second) of time.

    But now it makes sense.
    Thanks
Sign In or Register to comment.