Shop OBEX P1 Docs P2 Docs Learn Events
COG and object questions — Parallax Forums

COG and object questions

idbruceidbruce Posts: 6,197
edited 2012-03-03 14:29 in Propeller 1
Hello Everyone

Due to a recent question pertaining to my stepper drivers, I have been trying to create a new variable speed stepper driver.

The new driver that I am trying to create is within a seperate object file and it starts a new cog. After initializing several values, it goes into a loop to wait for value changes. This object also has a "set" method for setting the values of which the watchdog loop is waiting for change. The "set" method has several parameters that it receives from the parent object, and I am attempting to assign these parameters to local variables within the child object. Of course this is all experimental and of course the code is not working :)

So now I wonder is it not functioning due to the fact that the child object is in an endless loop, or is it something else? I am sure there are a lot of mistakes and problems with the following code, but I am still experimenting.


Here is some code from the parent object:

OBJ
  Stepper1 : "VariableStepperDriver"
  
PUB Main
  Stepper1.Start(3, 4, 5, CLK_FREQ / 1_000_000)
  WAITCNT(CLKFREQ * 2 + CNT)
  Stepper1.SetSpeedDir(CLKFREQ / 13_000, CLK_FREQ / 1_600, CLK_FREQ / 3_200_000, 0, FALSE, FALSE)

And here is the child object file:
VAR
  LONG lDirectionPin
  LONG lStepPin
  LONG lDisablePin
    
  LONG lDirection
  LONG lNewDirection
  LONG lStopMotor
  LONG lDisableMotor
  
  'Variable for cog ID
  LONG lCog
  LONG lUpdateSpeed
  LONG lHighPulseWidth
  LONG lCounter
  LONG lNewMaxExeMotorSpeed
  LONG lNewStartStopSpeed
  LONG lNewRampIncDec
  LONG lNewRampingSteps
  
  LONG lMaxExeMotorSpeed
  LONG lStartStopSpeed
  LONG lRampIncDec
  LONG lRampingSteps
  'Stack for running seperate cog
  LONG StepperStack[100]
PUB Start(DirectionPin, StepPin, DisablePin, HighPulseWidth) : Success
  Stop
  Success := (lCog := COGNEW(Initialize(DirectionPin, StepPin, DisablePin, HighPulseWidth), @StepperStack) + 1)

PUB Stop
  IF lCog
    COGSTOP(lCog~ - 1)
PUB Initialize(DirectionPin, StepPin, DisablePin, HighPulseWidth)
  lDirectionPin := DirectionPin
  lStepPin := StepPin
  lDisablePin := DisablePin
  DIRA[lStepPin] := 1
  DIRA[lDirectionPin] := 1
  DIRA[lDisablePin] := 1
  lHighPulseWidth := HighPulseWidth
  lUpdateSpeed := FALSE
  SetupCounter
  MonitorSpeedChange
PUB SetupCounter
  'Set up the CTRMODE of Counter A for NCO/PWM single-ended.
  CTRA[30..26] := %00100
  'Set the output pin for Counter A.
  CTRA[5..0] := lStepPin
  'Set the value to be added to PHSA with every clock cycle.
  FRQA := 1
  'Set APIN as an output.
  DIRA[lStepPin] := 1
  'Get the current System Counter value and initialize the lCounter
  'global variable.
  lCounter := CNT
PUB RampUpMotorSpeed
  OUTA[lDirectionPin] := lDirection
  'Ramp up motor speed 
  REPEAT lRampingSteps
    'Send out a high pulse on the step pin for the desired duration.
    PHSA := -lHighPulseWidth
    'Wait for a specified period of time before send sending another
    'high pulse to the step pin.
    WAITCNT(lCounter += lStartStopSpeed -= lRampIncDec)
  MaintainCurrentMotorSpeed  
PUB MaintainCurrentMotorSpeed
  'Run the motor at full speed until we get contrary input and then
  'stop this iteration. 
  REPEAT WHILE lUpdateSpeed == FALSE
 
    'Send out a high pulse on the step pin for the desired duration.
    PHSA := -lHighPulseWidth
    'Wait for a specified period of time before send sending another
    'high pulse to the step pin.
    WAITCNT(lCounter += lStartStopSpeed)
PUB RampDownMotorSpeed
  OUTA[lDirectionPin] := lDirection
  'Ramp down the motor.
  REPEAT lRampingSteps
 
    'Send out a high pulse on the step pin for the desired duration.
    PHSA := -lHighPulseWidth
    'Wait for a specified period of time before send sending another
    'high pulse to the step pin.
    WAITCNT(lCounter += lStartStopSpeed += lRampIncDec)
  IF lStopMotor <> TRUE
    MaintainCurrentMotorSpeed
  ELSE
    IF lDisableMotor == TRUE
    
      'Disable the motor.
      OUTA[lDisablePin] := 0
      MonitorSpeedChange
PUB MonitorSpeedChange
  REPEAT WHILE lUpdateSpeed == FALSE
  IF lNewStartStopSpeed > lStartStopSpeed
    UpdateSpeedChange
    OUTA[lDisablePin] := 1    
    RampDownMotorSpeed
  ELSE
    UpdateSpeedChange
    OUTA[lDisablePin] := 1
    RampUpMotorSpeed
PUB SetSpeedDir(MaxExeMotorSpeed, StartStopSpeed, RampIncDec, Direction, StopMotor, DisableMotor) | RampingSteps
  RampingSteps := (StartStopSpeed - MaxExeMotorSpeed) / RampIncDec
  lNewMaxExeMotorSpeed := MaxExeMotorSpeed
  lNewStartStopSpeed := StartStopSpeed
  lNewRampIncDec := RampIncDec
  lNewDirection := Direction
  lNewRampingSteps := RampingSteps
  
  IF StopMotor == TRUE
  
    lStopMotor := TRUE
    
  ELSE
  
    lStopMotor := FALSE
    
  IF DisableMotor == TRUE
  
    lDisableMotor := TRUE
  ELSE
    lDisableMotor := FALSE 
  lUpdateSpeed := TRUE
PUB UpdateSpeedChange
  lMaxExeMotorSpeed := lNewMaxExeMotorSpeed
  lStartStopSpeed := lNewStartStopSpeed
  lRampIncDec := lNewRampIncDec
  lRampingSteps := lNewRampingSteps
  lDirection := lNewDirection
  lUpdateSpeed := FALSE

Any input?

Bruce

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-03 07:50
    So now I wonder is it not functioning due to the fact that the child object is in an endless loop, or is it something else?

    I don't see the endless loop in the child object?

    Edit: Or was your concern there is an endless loop you didn't intend to occur?

    Edit again: I suspect "MoinitorSpeedChange" doesn't have the proper indentation to loop the way you are expecting. My guess is everything after "REPEAT WHILE lUpdateSpeed == FALSE" should be indented (within that method).
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 08:45
    Bruce in the method "MaintainCurrentMotorSpeed" there is a line - REPEAT WHILE 1UpdateSpeed == FALSE, it will stick there unless that variable is defined in the cog that started that cog and it is changed there.

    Edit: Duane the way he is using repeat in that instance it is a one line instruction.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 09:32
    @Duane Degn
    Edit again: I suspect "MoinitorSpeedChange" doesn't have the proper indentation to loop the way you are expecting. My guess is everything after "REPEAT WHILE lUpdateSpeed == FALSE" should be indented (within that method).

    The final instruction of Initialize is a call to MonitorSpeedChange, and I believe REPEAT WHILE lUpdateSpeed == FALSE is an endless loop, because I don't believe the call to SetSpeedDir from the parent updates the lUpdateSpeed variable. As far as the indentation goes, my intention was to just keep looping there until lUpdateSpeed equaled TRUE and then execute the remainder of the method, so indentation was not desired. The call from the parent to SetSpeedDir is intended to initialize some variables and then change lUpdateSpeed to TRUE, which would then allow MonitorSpeedChange to exit the REPEAT WHILE lUpdateSpeed == FALSE loop and continue on in that method.

    @ratronic
    Bruce in the method "MaintainCurrentMotorSpeed" there is a line - REPEAT WHILE 1UpdateSpeed == FALSE, it will stick there unless that variable is defined in the cog that started that cog and it is changed there.

    Thanks I will try that.
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 09:40
    Bruce that goes for all the REPEAT WHILE statements including the one Duane mentioned.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 09:46
    ratronic

    All indentation is as intended.

    As long as lUpdateSpeed == FALSE, it will just sit there and loop, but when lUpdateSpeed == TRUE, the remainder of the method should excute.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-03 09:53
    I'm assuming you want to keep the cog you start with your "Start" method alive. I don't see a loop that will do this.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 09:58
    ratronic

    You are overlooking the obvious :)
    PUB MonitorSpeedChange
      REPEAT WHILE lUpdateSpeed == FALSE
    
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 10:01
    Sorry ratronic, the last post was intended for Duane
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 10:09
    Bruce not only to keep it alive but you can also add a method to update variables from the top object.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 10:14
    ratronic

    That is what PUB SetSpeedDir(MaxExeMotorSpeed, StartStopSpeed, RampIncDec, Direction, StopMotor, DisableMotor) is intended for.
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 10:35
    Bruce I haven't looked real close at your code but you need to define & update your variables in your parent program that starts the child program for the variables you want to change in your child program with the parent.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 10:44
    ratronic
    Bruce I haven't looked real close at your code but you need to define & update your variables in your parent object that starts the child object for the variables you want to change.

    Why would I need to do that?

    In the child object, the SetSpeedDir method needs values for it's parameters. From the parent method I pass that method values to it's parameters. As stated above and shown below.
    Stepper1.SetSpeedDir(CLKFREQ / 13_000, CLKFREQ / 1_600, CLKFREQ / 3_200_000, 0, FALSE, FALSE)
    
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 10:53
    But the 1UpDateSpeed cannot be changed from within the new started cog when it is stuck in a REPEAT WHILE loop. The only way to change 1UpDateSpeed is from somewhere else.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 10:59
    ratronic
    But the 1UpDateSpeed cannot be changed from within the new started cog when it is stuck in a REPEAT WHILE loop. The only way to change 1UpDateSpeed is from somewere else.

    I understand that... Look at the last instruction of the SetSpeedDir method, this is where that value is updated and it is not running in that cog.
    PUB SetSpeedDir(MaxExeMotorSpeed, StartStopSpeed, RampIncDec, Direction, StopMotor, DisableMotor) | RampingSteps
      RampingSteps := (StartStopSpeed - MaxExeMotorSpeed) / RampIncDec
      lNewMaxExeMotorSpeed := MaxExeMotorSpeed
      lNewStartStopSpeed := StartStopSpeed
      lNewRampIncDec := RampIncDec
      lNewDirection := Direction
      lNewRampingSteps := RampingSteps
      
      IF StopMotor == TRUE
      
        lStopMotor := TRUE
        
      ELSE
      
        lStopMotor := FALSE
        
      IF DisableMotor == TRUE
      
        lDisableMotor := TRUE
      ELSE
        lDisableMotor := FALSE 
      lUpdateSpeed := TRUE
    
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 11:17
    Edit: you are right, it does get set to true.

    Edit2: but if that variable is to be used in a REPEAT WHILE statement it will have to be changed from another cog to get out of that loop.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-03 12:44
    MonitorSpeedChange can call RampDownMotorSpeed which in turn can call MonitorSpeedChange and so on.

    You're treating methods as goto statements. You'll soon run out of stack space doing it this way.
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 13:15
    You're treating methods as goto statements. You'll soon run out of stack space doing it this way.



    hmmmmmm
  • ratronicratronic Posts: 1,451
    edited 2012-03-03 13:57
    Bruce here is a simple demo showing the top object setting it's A to 1 then starting a child object which starts a new cog to show it's value of A on the serial terminal. You will see A at first display as 1 then in a little bit it will start incrementing A from 0 being updated from the top object.
    Con         'parent object                                                    
                                                             
      _CLKMODE = XTAL1 + PLL16X                              
      _XINFREQ = 5_000_000  
        
    Var
      long one, two, three
      long a, b, c, d, e, f                     
    Obj                                                      
      child : "template"
                  
    Pub main
      a := 1
      child.start(a, b, c)
      waitcnt(clkfreq*4+cnt)
      repeat
        child.update(d++, e, f)
        waitcnt(clkfreq/2+cnt)
    
    Child object
    Var          'child object
      long a, b, c
      long stack[50]
    Obj
      io : "parallax serial terminal"  
              
    Pub start(x, y, z)
      io.start(115200)
      a := x
      b := y
      c := z
      cognew(loop, @stack)
      
    Pub update(one, two, three)
      a := one
      b := two
      c := three
          
    Pub loop
      
      repeat      
        io.char(1)
        io.dec(a)
        waitcnt(clkfreq/100+cnt)
    
  • idbruceidbruce Posts: 6,197
    edited 2012-03-03 14:29
    @Duane and ratronic

    I want to thank you guys for your input, so thank you. I will try to modify my code a little later and see what happens.

    Bruce
Sign In or Register to comment.