Shop OBEX P1 Docs P2 Docs Learn Events
Weird problem with multiple cogs — Parallax Forums

Weird problem with multiple cogs

ryfitzger227ryfitzger227 Posts: 99
edited 2013-07-27 10:21 in Propeller 1
I'm running multiple cogs and I'm experiencing some weird problems. It might just be me, since I'm fairly new to the propeller, but I would like you guys to check just in case.

Here's my code I have at the moment
VAR


  long  stack[10]


PUB start(t1a, t2a, t3a, t4a, t5a, readya, xfirsta)

  cognew(mainFinish(t1a, 5, 4, readya, 24, xfirsta), @stack) ' ET Timer
  cognew(main(t2a, 5, 0, readya, 24), @stack) ' 60 Ft Timer
  'cognew(main(t3a, 1, 2, readya, 24), @stack) ' 330 Ft MPH Timer
  'cognew(main(t4a, 5, 2, readya, 24), @stack) ' 330 Ft Timer
  'cognew(main(t5a, 3, 4, readya, 24), @stack) ' MPH Timer


PUB main(tadr, tstart, tstop, readyadr, manstop) : ticks | mask1, mask2


  '--SETTING MASKS FOR WAITPNE--


  mask1 := |<tstart + |<manstop   'manstop is the pin number that the serial object sets on manual stop
  mask2 := |<tstop + |<manstop
  
  repeat 'main repeat
  
    repeat until BYTE[readyadr] == 1 'Don't monitor pin status until the computer is ready for timing
  
    waitpne(0,mask1,0) 'wait for start infrared to be broken (tstart=1 or manstop=1)
    ticks := cnt 'get timer value


    dira[16] := 1
    outa[16] := 1
    
    waitpne(0,mask2,0) 'wait for stop infrared to be broken (tstop=1 or manstop=1)
    
    LONG[tadr] := cnt - ticks 'calculate the final result
    
    if ina[manstop] 'if manual stop was set
      dira[manstop] := 1'reset manual stop..
      outa[manstop] := 0'...
      
    repeat until BYTE[readyadr] == 0 ' Don't continue until the computer says the timing is over


PUB mainFinish(tadr, tstart, tstop, readyadr, manstop, xfirstadr) : ticks | mask1, mask2


  '--SETTING MASKS FOR WAITPNE--


  mask1 := |<tstart + |<manstop   'manstop is the pin number that the serial object sets on manual stop
  mask2 := |<tstop + |<manstop
  
  repeat 'main repeat
  
    repeat until BYTE[readyadr] == 1 'Don't monitor pin status until the computer is ready for timing
  
    waitpne(0,mask1,0) 'wait for start infrared to be broken (tstart=1 or manstop=1)
    ticks := cnt 'get timer value


    dira[17] := 1
    outa[17] := 1
  
    waitpne(0,mask2,0) 'wait for stop infrared to be broken (tstop=1 or manstop=1)
    
    LONG[tadr] := cnt - ticks 'calculate the final result


    '--FINISH LINE ONLY--
    
    if ina[6] == 0 'see if other lane has already crossed
      dira[7] := 1 'tell other lane that this lane crossed first..
      outa[7] := 1 '...
      LONG[xfirstadr] := 1 'tell computer that this lane crossed first
    else
      LONG[xfirstadr] := 2 'continue... this lane didn't cross first. 
    
    if ina[manstop] 'if manual stop was set
      dira[manstop] := 1'reset manual stop..
      outa[manstop] := 0'...
      
    repeat until BYTE[readyadr] == 0 ' Don't continue until the computer says the timing is over

You'll notice that under start subroutine the last 3 cognews are commented out. That's because I'm trying to take this one timer at a time. Now, if I comment out one line (either the ET Timer or 60ft Timer cognew) the program runs as it should, but if I have both of those lines the way they are now it completely skips the line repeat until BYTE[readyadr] == 1 'Don't monitor pin status until the computer is ready for timing in the mainFinish subroutine and doesn't even poll in the main subroutine. I tried increasing the stack variable, but that didn't work. I'm really lost as to what this could be. Do you see any errors in my code that could make this happen?

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2013-07-26 13:46
    The first thing I see is that you're using the same stack area for more than one cog. You can't do that. Each cog has to have a separate stack area. You can use different portions of the same variable as with @stack[0], @stack[10], @stack[20] and so on or you can use completely different variables. Note that 10 longs probably is not enough. When starting off, use something more like 20 or 50. You can always make that smaller when you have a better idea of the actual stack usage by the various routines called by the cog.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-07-26 15:16
    I think Mike has covered your main problem.

    I'm not sure what you're trying to do here:
    if ina[manstop] 'if manual stop was set
          dira[manstop] := 1'reset manual stop..
          outa[manstop] := 0'...
    

    Does the button/switch get reset this way? If so, don't you need to set the pin back to an input after the reset?

    Maybe I'm premature with this observation since it sounds like you're trying to figure out how to launch the cogs you need before you attend to these other details.

    Be aware if one cog sets either "dira" or "outa" high a different cog isn't going to be able to change the state of the I/O pin. Each cog has a "dira" and "out" register and these registers are logically "or"ed together to determine the pins' state.
  • TappermanTapperman Posts: 319
    edited 2013-07-27 09:43
    Mike Green wrote: »
    Note that 10 longs probably is not enough. When starting off, use something more like 20 or 50. You can always make that smaller when you have a better idea of the actual stack usage by the various routines called by the cog.
    Greetings Mike ... I have a question about the stack size. If you install a 'cog' running spin. And your code does not 'call' any external methods or routines ... how big does the stack need to be?
    PRI Phase_Track | pins, m          '' (seperate cog) installs first!
      ClosedLoop~                                 ' set to false
      m := |< Sync_Pin
      repeat
        waitpne(0,MtrMask,0)                      ' hold up until mtr drvr in place
        waitpne(Charge,MtrMask,0)                 ' trap for charging condition
        waitcnt(15_000 + cnt)                     ' pin settle time
        waitpne(ina,PhaseMask,0)                  ' wait for commutation indicater
        Pace := cnt - anchor                      ' calc. speed shaft is moving
        ClosedLoop~~                              ' set to true
        xc := MDT[(ina & PhaseMask) >> Phase_Pin] ' lookup new next_vector
        waitpeq(m,m,0)                            ' hold up for reverse sync pulse
    
    

    As in this example I'm using ... I take great care not to call any external routines. It operates perfectly. However, I'm not really sure how much stack I need? Or how to estimate it from any of the documentation for the propeller?

    ... Tim
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-07-27 10:20
    I've noticed Kye lists the stack space required by the methods in many of his objects. It looks like the minimum stack space required is three longs.

    Here's a couple of methods from the FAT SD card driver.
    PRI sectorNumberInRoot ' 6 Stack Longs
    
      return (currentSectorInClusterChain // rootDirectorySectors)
    
    
    PRI currentByteInSector ' 3 Stack Longs
    
    
      return (currentByte & $1_FF)
    
    
    PRI currentSectorInClusterChain ' 3 Stack Longs
    
    
      return (currentByte >> 9)
    

    I've noticed methods that only call one method use three additional stack longs than the final method called.

    For example "readLong" requires 35 longs while the method "readLong" calls "readData" requires 32 longs.
    PUB readLong '' 35 Stack Longs
    
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Reads a long from the file that is currently open and advances the file position by four.
    '' //
    '' // Returns the next long to read from the file. Reads nothing when at the end of a file - returns zero.
    '' //
    '' // This method will do nothing if a file is not currently open for reading or writing.
    '' //
    '' // If an error occurs this method will abort and return a pointer to a string describing that error.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
      readData(@result, 4)
    

    I don't know how Kye figures out how much stack each method uses but it sure looks like he can do it pretty precisely.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-07-27 10:21
    The stack is used to hold the return address, result value, parameter values, local variables, temporary storage for expressions, and a couple of call-associated odds and ends. In your case, main takes 5 parameters and has 2 local variables. Things like WAITPxx, even though they're built-in, build their parameter lists on the stack. Right there you've got more than 10 stack levels needed even with no further calls. I tend to figure this out by looking at the deepest call chain and multiplying by 3 or 4, figuring on the worst case number of parameters and local variables in the call chain, adding maybe 10 for temporary values, and doubling that during debugging. There are some tools that initialize the stack area to a "magic value" and look during execution to see how many of these get replaced by some other value. If you exercise your program adequately during testing, you'll have a pretty good idea of how much you'll need. I usually add a minimum of 10% or 10-20 longs for slop.
Sign In or Register to comment.