Shop OBEX P1 Docs P2 Docs Learn Events
Writing a driver for two steppers is harder than I thought! — Parallax Forums

Writing a driver for two steppers is harder than I thought!

lardomlardom Posts: 1,659
edited 2011-12-30 21:04 in Propeller 1
I'm trying to write a stepper driver for differential steering and I'm getting chatter when I try to get them to run together. I used a stack of 60 longs and I only got them to run together smoothly after I put motor (1) @stack[5]. It chattered @stack[0]. The step pattern is in the DAT block which works fine for a single stepper. I think I should rewrite the driver so that both motors use a single 8-bit step pattern. I have to use 2pi to calculate the rate of turn and calling two methods in the same object with cognew/coginit does not appear to work.
I know someone has been down this road. I'm hoping that a single 8-bit variable is the way to approach this.
«1

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-12-25 21:31
    I while back, I made a simple stepper motor driver.

    I used a rotating 32 bit pattern.
    CON
     [COLOR=#ff0000] _InitialPattern = %11001100_11001100_11001100_11001100
    [/COLOR]
    VAR
      long stepPattern
      
    PUB Start(startPin, stepsInRev, globalLocation) : success
    '<snip>
    
      [COLOR=#ff0000]stepPattern := _InitialPattern
    [/COLOR]
    

    Edit: The forum eats my "%" in front of the binary _InitialPattern value.
    2nd Edit: Now it will let me add a percent sign. Strange.

    I used 32 bits instead of just 8 so I could use the bit rotation opperator.
    PRI ClockWise
      repeat until (stepCounter-- =< 0)
        [COLOR=#ff0000]stepPattern <-= 1
    [/COLOR]outa[pinD..pinA] := stepPattern
        long[globalStepsLocation] += 1
        Pause(_MinimumStepDelay + delay)
      ready := 1  
      
    PRI CounterClockWise
    
      repeat until (stepCounter-- =< 0)
        [COLOR=#ff0000]stepPattern ->= 1
    [/COLOR]outa[pinD..pinA] := stepPattern
        long[globalStepsLocation] -= 1
        Pause(_MinimumStepDelay + delay)
      ready := 1    
        
    

    I personally thought it was pretty cool to use the rotating bits to drive the motor.

    You could have two different stepPattern variables so you could rotate them independently from each other.

    Just a thought. I know there are lots of other stepper motor objects out there that are a lot better than mine.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-12-25 21:39
    Duane,

    How do you enter code blocks? I don't have issues with the "%" getting eaten:
    CON
      _InitialPattern = %1100_11001100_11001100_11001100
    
    VAR
      long stepPattern
      
    PUB Start(startPin, stepsInRev, globalLocation) : success
    '<snip>
    
      stepPattern := _InitialPattern
    

    -Phil
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-12-25 23:08
    Duane,

    How do you enter code blocks? I don't have issues with the "%" getting eaten:
    It happened when I edited the line to make it red. I tried editing it several times without the percent sign showing up.

    I usually don't have a problem with it.

    Edit: My latest attempt to edit the earlier post worked. I was (finally) able to add the "%" to my original post. It was strange that I couldn't before.
    I deleted some other tests, to see if the percent sign would show up, I had made in this post.

    My original post was missing four bits from the inital pattern. I've edited it.

    @Larry, Sorry about the distraction from stepper motors.
  • idbruceidbruce Posts: 6,197
    edited 2011-12-26 01:08
    @lardom

    I am surprised that Duane nor Phil mentioned it, but if you are seeking help, then you should post your source code so that others may try to find the source of your problem.

    Bruce
  • idbruceidbruce Posts: 6,197
    edited 2011-12-26 01:15
    @lardom

    Perhaps you may find something useful in the code below.

    Bruce

    EDIT: This is a combination of someoneelses code and mine, I forget the original author, this was just some test software for me using the HC595. I am sure you can find the original code in the OBEX. I am not trying to take credit for someoneelses work :)
  • lardomlardom Posts: 1,659
    edited 2011-12-26 06:54
    @Duane, I'm studying your 32-bit approach.
    @idbruce, I've uploaded the file and tried to comment it so someone else could understand what I was after. I'll study your file. Thanks
  • idbruceidbruce Posts: 6,197
    edited 2011-12-26 07:07
    Larry

    I don't understand.... You say that you are trying to control two steppers, but in your function calls, I only see pins 8-11 being used. Are you trying to control both steppers from the same four pins?

    Bruce
  • lardomlardom Posts: 1,659
    edited 2011-12-26 07:19
    idbruce, your code may contain the answer. The outer wheel uses 2pi * (ft in inches * (x)). The inner wheel uses 2pi * (ft in inches * (x) - 5)). which refers to a 5" wheel base. If the step differential is constant then a bit pattern array would solve the problem.

    idbruce, My naming conventions may be a bit quirky; motor #1 uses [11..8]. Motor #2 uses [15..12].
  • idbruceidbruce Posts: 6,197
    edited 2011-12-26 07:20
    Larry

    Irregardless of the last question and answer, from what I have read about differential steering, you want two independentantly operating motors.

    If I was to attempt such a thing as differential steering (according to what I have read), this is what I would try.
    • Acquire the system count value and add a future time.
    • Create two instances of the same object and pass each instance the future time for execution and the pins being used.
    Bruce
    • StefanL38StefanL38 Posts: 2,292
      edited 2011-12-26 07:25
      first comment after a quick look into your code.

      Mixing cognew and coginit is a really bad idea. You should always use cognew to start new cogs.
      There is only a handful cases where using coginit is an advantage. Most of the time you receive the disadvantage
      that you the user is responsible for starting and stopping the right cogs.

      If you do a cognew this cognew might just se cog no 2. and later on you do a coginit cog no 2 which will stop cog 2 from what is doing right now and start again with coginit cog no 2


      a stack of 4 longs is way too small.
      the real minimum is 9 longs.
      you do

      success:= cog := cognew(Full(distance,speed), @stack)

      and later on

      coginit(1, Full_Bk(R, speed), @stack[5])
      coginit (2, Full_BkL(L, speed), @stack[30])

      which means the coginit Full_Bk @stack[5] starts right in the middle of the stack of

      cognew Full @stack

      use a separate stackvariable for each cog with a size of minimum 20 longs just to assure that the stacks are big enough.

      For further analysing what is happening I would add low-current LEDs to the outputs and would run the code through
      in some kind of single-step-mode to see how the outputs are switched on off. Or as a software-replacement of the LEDs
      to send the actual bitpattern to te serial terminal.

      keep the questions coming
      best regards
      Stefan
    • lardomlardom Posts: 1,659
      edited 2011-12-26 07:49
      StefanL38, your analysis explains the weirdness that occurred when I ran the code. Lesson learned.
    • idbruceidbruce Posts: 6,197
      edited 2011-12-26 07:56
      Larry

      Something along the lines of the altered file.

      Bruce
    • idbruceidbruce Posts: 6,197
      edited 2011-12-26 08:28
      Larry

      By creating two instances of the same object, and controlling each motor seperately, you should be able to achieve a wider range of control, such as different speeds for each motor, as well as different directions.

      Bruce
    • lardomlardom Posts: 1,659
      edited 2011-12-26 09:00
      idbruce, how do you create two instances of an object?
      (Using 32-bit variables at the very least would eliminate the need to write a separate method for each wheel since I would only have to shift bits.)
    • idbruceidbruce Posts: 6,197
      edited 2011-12-26 13:13
      Larry

      Here is an example:
      CON
        CW = 0 'clockwise rotation
        CCW = 1 'counter-clockwise rotation
        FULL = 0 'Full step mode
        HALF = 1 'Half step mode
        WAVE = 2 'Wave step mode
      
      OBJ
        LeftWheel   : "Stepper for pi"
        RightWheel   : "Stepper for pi"
      
      PUB DifferentialSteering | FutureTime
        FutureTime := CNT + CLKFREQ/100
        LeftWheel.Start(5_000, 300, FutureTime, FULL, CW, 15, 12)
        RightWheel.Start(2_000, 100, FutureTime, HALF, CCW, 11, 8)
      
        {
          The parameters for speed and distance are just examples.  In this example, I
           have also added direction and mode to the previously suggested alterations.
        }
      
    • idbruceidbruce Posts: 6,197
      edited 2011-12-26 16:15
      Larry

      Here is an afterthought. Once again, if I was to attempt something like differential steering, I would use two objects, a math object to determine the movement required and a stepper object to make the movement happen.

      I would first determine the movement required, and then I would send the required movements to the stepper object to make the required movements simultaneously with both wheels as previously suggested. That way the rotation of the individual tires are not bogged down by the necessary computations.

      Bruce
    • idbruceidbruce Posts: 6,197
      edited 2011-12-27 03:47
      Larry

      I apologize for all the input, but this subject has caught my interest.

      As I mentioned in the last post, I would attempt to keep as many computations out of the stepper driver as possible. With this in mind, and keeping in mind that I would have two instances for a single object, one for each wheel, I would also design the object so that I could call the individual types of movements to start a new cog. The following code should give you a brief idea of what I would do.

      Bruce
      PUB CW_WaveMode(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)
      
        COGNEW(CW_WavePulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition), @Stack)
      
      PRI CW_WavePulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)| RampUp, RampDown
      
        WAITCNT(FutureTime)
      
        DIRA[StartingPin..EndingPin]~~
      
        {
          Insert stepper movement code
        }
      
        IF HoldPosition == FALSE
          OUTA[StartingPin..EndingPin]~
      
      PUB CCW_WaveMode(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)
      
        COGNEW(CCW_WavePulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition), @Stack)
      
      PRI CCW_WavePulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)| RampUp, RampDown
      
        WAITCNT(FutureTime)
      
        DIRA[StartingPin..EndingPin]~~
      
        {
          Insert stepper movement code
        }
        
        IF HoldPosition == FALSE
          OUTA[StartingPin..EndingPin]~
      
      PUB CW_FullMode(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)
      
        COGNEW(CW_FullPulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition), @Stack)
      
      PRI CW_FullPulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)| RampUp, RampDown
      
        WAITCNT(FutureTime)
      
        DIRA[StartingPin..EndingPin]~~
      
        {
          Insert stepper movement code
        }
      
        IF HoldPosition == FALSE
          OUTA[StartingPin..EndingPin]~
      
      PUB CCW_FullMode(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)
      
        COGNEW(CCW_FullPulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition), @Stack)
      
      PRI CCW_FullPulse(Distance, Speed, FutureTime, StartingPin, EndingPin, HoldPosition)| RampUp, RampDown
      
        WAITCNT(FutureTime)
      
        DIRA[StartingPin..EndingPin]~~
      
        {
          Insert stepper movement code
        }
        
        IF HoldPosition == FALSE
          OUTA[StartingPin..EndingPin]~
      
    • lardomlardom Posts: 1,659
      edited 2011-12-28 08:06
      I appreciate your input. I copied your code snippet and will try to implement it. Meanwhile I wrote some code to test leds blinkng at a very slow rate. I tried to copy a working object from the "P.E. Kit" lab book and I still cannot get the methods to execute in parallel.
      {Executes pins[8..11] for 3 secs. Pin[8] and pin[11] remain high.
      "Full2" executes pins[12..15]. Pin[8] and pin[11] clear and
      pin[12] and pin[15] remain high}
      
      
      CON
      
        _CLKMODE      = XTAL1 + PLL16X
        _XINFREQ      = 5_000_000         
              
      
      VAR
      
        long  stack[40], Distance, rate, RDistance, LDistance, duration
        word StartPin, EndPin, RStart, REnd,  LStart, LEnd, TimeInSecs        
      
      
      PUB start(RD, LD, Time) : success
      
              RDistance := RD          'hardcoded to eliminate object.method call
              LDistance := LD          'hardcoded to eliminate object.method call
      
              RStart := 8
              REnd := RStart + 3
              LStart := 12
              LEnd := LStart + 3
             TimeInSecs := Time        'hardcoded to eliminate object.method call 
        
              cognew(Full(10, 4, RStart, REnd), @stack[0])         ' left side
              waitcnt(clkfreq * 3 + cnt)            
              cognew(Full2(10, 4, LStart, LEnd), @stack[20])     ' right side                                                                     
        
      PUB Full(A, B, C, D)                
                                          
             Distance := A                
             duration := B
             StartPin := C
             EndPin   := D
             rate := Distance / duration         
             
             dira[StartPin..EndPin]~~
        
             repeat distance                  
               outa[StartPin..EndPin] := %0011                 
               waitcnt(clkfreq/rate + cnt)          
               outa[StartPin..EndPin] := %0110                 
               waitcnt(clkfreq/rate + cnt)           
               outa[StartPin..EndPin] := %1100                 
               waitcnt(clkfreq/rate + cnt) 
               outa[StartPin..EndPin] := %1001                 
               waitcnt(clkfreq/rate + cnt) 
      
           '  dira[StartPin..EndPin]~              'Does not change behavior
             Distance := duration := StartPin := EndPin := rate := 0   
                         '
      PUB Full2(A, B, C, D)               
      
             Distance := A
             duration := B
             StartPin := C
             EndPin   := D
             rate := Distance / duration         
             
             dira[StartPin..EndPin]~~             
      
             repeat distance                  
               outa[StartPin..EndPin] := %0011                 
               waitcnt(clkfreq/rate + cnt)          
               outa[StartPin..EndPin] := %0110                 
               waitcnt(clkfreq/rate + cnt)           
               outa[StartPin..EndPin] := %1100                 
               waitcnt(clkfreq/rate + cnt) 
               outa[StartPin..EndPin] := %1001                 
               waitcnt(clkfreq/rate + cnt) 
      
          '   dira[StartPin..EndPin]~              'Does not change behavior
             Distance := duration := StartPin := EndPin := rate := 0   
                         '
      

      I wanted to eliminate the DAT block as a possible cause.
    • idbruceidbruce Posts: 6,197
      edited 2011-12-28 13:22
      Larry

      In the code example that you provided, these cogs (wheels) will start three seconds apart.
              cognew(Full(10, 4, RStart, REnd), @stack[0])         ' left side
              waitcnt(clkfreq * 3 + cnt)  'three second difference          
              cognew(Full2(10, 4, LStart, LEnd), @stack[20])     ' right side                                                                     
      

      What you really want is for both cogs to start on the same clock cycle. That is the reason behind the FutureTime variable that I offered as a solution.

      Bruce
    • idbruceidbruce Posts: 6,197
      edited 2011-12-28 13:36
      Larry

      Try this instead:
      {Executes pins[8..11] for 3 secs. Pin[8] and pin[11] remain high.
      "Full2" executes pins[12..15]. Pin[8] and pin[11] clear and
      pin[12] and pin[15] remain high}
      
      CON
        _CLKMODE      = XTAL1 + PLL16X
        _XINFREQ      = 5_000_000         
              
      VAR
        long  stack[40], Distance, rate, RDistance, LDistance, duration
        word StartPin, EndPin, RStart, REnd,  LStart, LEnd, TimeInSecs        
      
      PUB start(RD, LD, Time) | NewWait : success
              RDistance := RD          'hardcoded to eliminate object.method call
              LDistance := LD          'hardcoded to eliminate object.method call
              RStart := 8
              REnd := RStart + 3
              LStart := 12
              LEnd := LStart + 3
              TimeInSecs := Time        'hardcoded to eliminate object.method call
              NewWait := clkfreq * 3 + cnt
               
        
              cognew(Full(10, 4, RStart, REnd, NewWait), @stack[0])         ' left side
              cognew(Full2(10, 4, LStart, LEnd, NewWait), @stack[20])     ' right side                                                                     
        
      PUB Full(A, B, C, D, FutureTime)                
                                          
             Distance := A                
             duration := B
             StartPin := C
             EndPin   := D
             rate := Distance / duration         
             
             dira[StartPin..EndPin]~~
        
             repeat distance                  
               outa[StartPin..EndPin] := %0011                 
               waitcnt(clkfreq/rate + cnt)          
               outa[StartPin..EndPin] := %0110                 
               waitcnt(clkfreq/rate + cnt)           
               outa[StartPin..EndPin] := %1100                 
               waitcnt(clkfreq/rate + cnt) 
               outa[StartPin..EndPin] := %1001                 
               waitcnt(clkfreq/rate + cnt) 
           '  dira[StartPin..EndPin]~              'Does not change behavior
           {
            Note: This changes the pins from outputs to inputs.  It should be OUTA instead of DIRA.
           }
             Distance := duration := StartPin := EndPin := rate := 0   
                         '
      PUB Full2(A, B, C, D, FutureTime)               
             Distance := A
             duration := B
             StartPin := C
             EndPin   := D
             rate := Distance / duration         
             
             dira[StartPin..EndPin]~~             
             repeat distance                  
               outa[StartPin..EndPin] := %0011                 
               waitcnt(clkfreq/rate + cnt)          
               outa[StartPin..EndPin] := %0110                 
               waitcnt(clkfreq/rate + cnt)           
               outa[StartPin..EndPin] := %1100                 
               waitcnt(clkfreq/rate + cnt) 
               outa[StartPin..EndPin] := %1001                 
               waitcnt(clkfreq/rate + cnt) 
          '  dira[StartPin..EndPin]~              'Does not change behavior
           {
            Note: This changes the pins from outputs to inputs.  It should be OUTA instead of DIRA.
           }
           
             Distance := duration := StartPin := EndPin := rate := 0   
      
      
    • idbruceidbruce Posts: 6,197
      edited 2011-12-28 13:42
      Larry

      For some reason, I cannot edit posts that contain "CODE" blocks. The previous example was missing something. Try this:
      {Executes pins[8..11] for 3 secs. Pin[8] and pin[11] remain high.
      "Full2" executes pins[12..15]. Pin[8] and pin[11] clear and
      pin[12] and pin[15] remain high}
      
      CON
        _CLKMODE      = XTAL1 + PLL16X
        _XINFREQ      = 5_000_000         
              
      VAR
        long  stack[40], Distance, rate, RDistance, LDistance, duration
        word StartPin, EndPin, RStart, REnd,  LStart, LEnd, TimeInSecs        
      
      PUB start(RD, LD, Time) | NewWait : success
              RDistance := RD          'hardcoded to eliminate object.method call
              LDistance := LD          'hardcoded to eliminate object.method call
              RStart := 8
              REnd := RStart + 3
              LStart := 12
              LEnd := LStart + 3
              TimeInSecs := Time        'hardcoded to eliminate object.method call
              NewWait := clkfreq * 3 + cnt
               
        
              cognew(Full(10, 4, RStart, REnd, NewWait), @stack[0])         ' left side
              cognew(Full2(10, 4, LStart, LEnd, NewWait), @stack[20])     ' right side                                                                     
        
      PUB Full(A, B, C, D, FutureTime)
             waitcnt(FutureTime)               
                                          
             Distance := A                
             duration := B
             StartPin := C
             EndPin   := D
             rate := Distance / duration         
             
             dira[StartPin..EndPin]~~
        
             repeat distance                  
               outa[StartPin..EndPin] := %0011                 
               waitcnt(clkfreq/rate + cnt)          
               outa[StartPin..EndPin] := %0110                 
               waitcnt(clkfreq/rate + cnt)           
               outa[StartPin..EndPin] := %1100                 
               waitcnt(clkfreq/rate + cnt) 
               outa[StartPin..EndPin] := %1001                 
               waitcnt(clkfreq/rate + cnt) 
           '  dira[StartPin..EndPin]~              'Does not change behavior
           {
            Note: This changes the pins from outputs to inputs.  It should be OUTA instead of DIRA.
           }
             Distance := duration := StartPin := EndPin := rate := 0   
                         '
      PUB Full2(A, B, C, D, FutureTime)               
             waitcnt(FutureTime)               
                                
             Distance := A
             duration := B
             StartPin := C
             EndPin   := D
             rate := Distance / duration         
             
             dira[StartPin..EndPin]~~             
             repeat distance                  
               outa[StartPin..EndPin] := %0011                 
               waitcnt(clkfreq/rate + cnt)          
               outa[StartPin..EndPin] := %0110                 
               waitcnt(clkfreq/rate + cnt)           
               outa[StartPin..EndPin] := %1100                 
               waitcnt(clkfreq/rate + cnt) 
               outa[StartPin..EndPin] := %1001                 
               waitcnt(clkfreq/rate + cnt) 
          '  dira[StartPin..EndPin]~              'Does not change behavior
           {
            Note: This changes the pins from outputs to inputs.  It should be OUTA instead of DIRA.
           }
           
             Distance := duration := StartPin := EndPin := rate := 0   
      
      
    • idbruceidbruce Posts: 6,197
      edited 2011-12-28 13:50
      Larry

      I just quickly reviewed your code and added to it. I must say that after closer examination, I don't like the way it looks. I will rewrite it and have a new piece of test code for you in a few minutes.

      Bruce
    • idbruceidbruce Posts: 6,197
      edited 2011-12-28 14:48
      Okay Larry, you may have to alter the variable values of Distance, Duration, and WaitForFutureTime, but this code should do it, unless of course I overlooked something :)

      Bruce
      CON
      
        _CLKMODE      = XTAL1 + PLL16X
        _XINFREQ      = 5_000_000         
              
      VAR
      
        LONG RightWheelStack[40]
        LONG LeftWheelStack[40]
        
      PUB SimultaneousSteppers | WaitForFutureTime
      
        WaitForFutureTime := CLKFREQ * 3 + CNT
      
        COGNEW(Full(8, 11, WaitForFutureTime), @RightWheelStack)
        COGNEW(Full(12, 15, WaitForFutureTime), @LeftWheelStack)
      
      PUB Full(StartPin, EndPin, FutureTime) | Distance, Rate, Duration
      
        WAITCNT(FutureTime)               
                                          
        DIRA[StartPin..EndPin]~~
      
        Distance := 10
        Duration := 4
        Rate := Distance / Duration
        
        REPEAT Distance  
                      
          OUTA[StartPin..EndPin] := %0011                 
          WAITCNT(CLKFREQ / Rate + CNT)          
          OUTA[StartPin..EndPin] := %0110                 
          WAITCNT(CLKFREQ / Rate + CNT)           
          OUTA[StartPin..EndPin] := %1100                 
          WAITCNT(CLKFREQ / Rate + CNT) 
          OUTA[StartPin..EndPin] := %1001                 
          WAITCNT(CLKFREQ / Rate + CNT)
       
        OUTA[StartPin..EndPin]~  'This will deenergize the coils
      
      
    • lardomlardom Posts: 1,659
      edited 2011-12-29 10:39
    • idbruceidbruce Posts: 6,197
      edited 2011-12-29 13:43
      Larry

      Did you try the last code I posted?

      Bruce
    • pedwardpedward Posts: 1,642
      edited 2011-12-29 14:37
      I figured out what's happening here.

      When you use COGNEW on an object, the compiler actually calls the function first, waits for it to return, then launches the cog with that function.

      When you call a local function in the SPIN program, it simply launches the COG with COGINIT.

      The problem is that the COGNEW is actually executing the Start methods in serial.

      The solution is to create 2 local subs that you call with COGNEW and those subs call the startup methods in the OBJ. This is a really esoteric bug and doesn't show up most times because most Start methods of OBJects return shortly after doing some setup of the COG.
    • pedwardpedward Posts: 1,642
      edited 2011-12-29 14:40
      This doesn't work:
      CON
      
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      
      OBJ
      
      pst: "Parallax Serial Terminal"
      L: "left"
      R: "right"
      
      VAR
      
        long stack[100]
      
      PUB main
        pst.start(115200)             'debug output
      '  cognew(Left,@stack)
      '  cognew(Right,@stack[50])
        coginit(1,R.Start,@stack)
        coginit(2,L.Start,@stack[50])
      
        repeat
      
      PUB Left
      
        DIRA[23..20]~~
      
        repeat
          OUTA[23..20] := %0001
          waitcnt(clkfreq >> 3 + cnt)
          OUTA[23..20] := %0010
          waitcnt(clkfreq >> 3 + cnt)
          OUTA[23..20] := %0100
          waitcnt(clkfreq >> 3 + cnt)
          OUTA[23..20] := %1000
          waitcnt(clkfreq >> 3 + cnt)
      
      PUB Right
      
        DIRA[19..16]~~
      
        repeat
          OUTA[19..16] := %0001
          waitcnt(clkfreq >> 2 + cnt)
          OUTA[19..16] := %0010
          waitcnt(clkfreq >> 2 + cnt)
          OUTA[19..16] := %0100
          waitcnt(clkfreq >> 2 + cnt)
          OUTA[19..16] := %1000
          waitcnt(clkfreq >> 2 + cnt)
      

      This DOES work:
      CON
      
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      
      OBJ
      
      pst: "Parallax Serial Terminal"
      L: "left"
      R: "right"
      
      VAR
      
        long stack[100]
      
      PUB main
        pst.start(115200)             'debug output
        cognew(Left,@stack)
        cognew(Right,@stack[50])
      '  coginit(1,R.Start,@stack)
      '  coginit(2,L.Start,@stack[50])
      
        repeat
      
      PUB Left
      
        DIRA[23..20]~~
      
        repeat
          OUTA[23..20] := %0001
          waitcnt(clkfreq >> 3 + cnt)
          OUTA[23..20] := %0010
          waitcnt(clkfreq >> 3 + cnt)
          OUTA[23..20] := %0100
          waitcnt(clkfreq >> 3 + cnt)
          OUTA[23..20] := %1000
          waitcnt(clkfreq >> 3 + cnt)
      
      PUB Right
      
        DIRA[19..16]~~
      
        repeat
          OUTA[19..16] := %0001
          waitcnt(clkfreq >> 2 + cnt)
          OUTA[19..16] := %0010
          waitcnt(clkfreq >> 2 + cnt)
          OUTA[19..16] := %0100
          waitcnt(clkfreq >> 2 + cnt)
          OUTA[19..16] := %1000
          waitcnt(clkfreq >> 2 + cnt)
      
      

      This ALSO works:
      CON
      
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      
      OBJ
      
      pst: "Parallax Serial Terminal"
      L: "left"
      R: "right"
      
      VAR
      
        long stack[100]
      
      PUB main
        pst.start(115200)             'debug output
        cognew(Left,@stack)
        cognew(Right,@stack[50])
      '  coginit(1,R.Start,@stack)
      '  coginit(2,L.Start,@stack[50])
      
        repeat
      
      PUB Left
      
        L.Start
      
      PUB Right
      
        R.Start
      

      The question is, is this OFFICIALLY a SPIN compiler BUG?
    • JonnyMacJonnyMac Posts: 9,198
      edited 2011-12-29 14:45
      @Larry: A simple problem seems to have been wound up into a complicated one. Dropping back to simple, the attached demo (which is happy running on a QuickStart) shows how to construct a simple stepper controller and then launch it into two cogs (more if you have available pins). Control is pretty straightforward, you would use the manipulation of the step count and step time in the "master" cog to control the overall behavior.

      Perhaps this "reboot" will get you back on track -- or at least get you unstuck.
    • JonnyMacJonnyMac Posts: 9,198
      edited 2011-12-29 14:50
      The question is, is this OFFICIALLY a SPIN compiler BUG?

      No -- you're doing something wrong. The problem is we don't have the source for the objects refernced in the segment that you say is not working. Now... if you're thinking that you can declare methods as objects as your listing suggests you're trying, this doesn't work.

      As as been pointed out, coginit is dangerous because it will overwrite anything in the target cog -- and that cog may be doing something you need. Use cognew instead, as I demonstrate in the working code attached above.
    • pedwardpedward Posts: 1,642
      edited 2011-12-29 14:54
      I have attached the files, you can see there is nothing hinky here.
    Sign In or Register to comment.