Shop OBEX P1 Docs P2 Docs Learn Events
PASM and cogs — Parallax Forums

PASM and cogs

blake_machoblake_macho Posts: 5
edited 2009-03-23 06:15 in Propeller 1
I am clearly a newbie here, and I realize that this code sucks in a variety of ways (e.g. redundancy between the x and y servo routines). Please look past that as I try to ask my first question, then help me with that as you address my second question =).

#1. Whichever repeat 10 loop I list first in the code is the only one that works, the second one does nothing. They both work fine independently. Order of the cognew functions has no impact. What am I missing?
#2. Obviously, I ideally want to pass in two parameters to a single 'servo' PASM block. The first being a servo pin, the second being a position. How do I go about that? (I believe I am to pass a memory address and then do some fancy PASM to look it up and pull out the necessary values). I am a total ASM and PASM noob, sadly. So I have no clue on how to go about that. Any tutorials/links/example code?

Thanks for helping out. Much appreciated.

CON
  _xinfreq=5_000_000            
  _clkmode=xtal1+pll16x
  LASER = 26                                             
                                                                                                                         
VAR                                                                                                                      
  long  x_position          
  long  y_position                                  
                                                                                                                           
PUB Main
  cognew(@y_servo,@y_position)
  cognew(@x_servo,@x_position)
            
  laser_toggle(1)

'The new cog that is started above continuously reads the "position" variable as it's changed by the example Spin code below
  repeat 10
    y_position:=70_000
    waitcnt(clkfreq+cnt)
    y_position:=105_000
    waitcnt(clkfreq+cnt)

  repeat 10                                                                                                                
    x_position:=96_000                       'Start sending 1ms servo signal high pulses (80_000 * 1/(80MHz clock freq) = 1ms)                                                     
    waitcnt(clkfreq+cnt)                   'Wait for 1 second (1ms high pulses continue to be generated by the other cog)                                                                
    x_position:=168_000                      'Start sending 1.375ms servo signal high pulses (Center position)                                                 
    waitcnt(clkfreq+cnt)                   'Wait for 1 second (1.5ms high pulses continue to be generated by the other cog)
  
                                                   
PUB laser_toggle(on)
  dira[noparse][[/noparse]LASER]~~
  outa[noparse][[/noparse]LASER] := on
DAT
'The assembly program below runs on a parallel cog and checks the value of the "position" variable in the main Hub RAM (which 
' other cogs can change at any time). It then outputs a servo high pulse for the "position" number of system clock ticks and 
' sends a 10ms low part of the pulse. It repeats this signal continuously and changes the width of the high pulse as the
' "position" variable is changed by other cogs.

              org                          'Assembles the next command to the first cell (cell 0) in the new cog's RAM
x_servo       mov       dira,XPin     'Set the direction of the "ServoPin" to be an output (and all others to be inputs)                                 
                                                                                                                      
LoopX         rdlong    HighTimeX,par      'Read the "position" variable (at "par") from Main RAM and store it as "HighTime"
              mov       counterX,cnt       'Store the current system clock count in the "counter" cell's address   
              mov       outa,AllOnX        'Set all pins on this cog high (really only sets ServoPin high b/c rest are inputs)            
              add       counterX,HighTimeX  'Add "HighTime" value to "counter" value
              waitcnt   counterX,LowTimeX   'Wait until "cnt" matches "counter" then add a 10ms delay to "counter" value 
              mov       outa,#0           'Set all pins on this cog low (really only sets ServoPin low b/c rest are inputs)
              waitcnt   counterX,0         'Wait until cnt matches counter (adds 0 to "counter" afterwards)
              jmp       #LoopX             'Jump back up to the cell labled "Loop"                                      
                                                                                                                    
'Constants and Variables:
XPin          long      |<      5 '<------- This sets the pin that outputs the servo signal (which is sent to the white wire
                                          ' on most servomotors). Here, this "7" indicates Pin 7. Simply change the "7" 
                                          ' to another number to specify another pin (0-31).
                                          
AllOnX         long      $FFFFFFFF         'This will be used to set all of the pins high (this number is 32 ones in binary)
LowTimeX       long      1_600_000           'This works out to be a 10ms pause time with an 80MHz system clock. If the
                                          ' servo behaves erratically, this value can be changed to 1_600_000 (20ms pause)                                  
counterX      res                         'Reserve one long of cog RAM for this "counter" variable                     
HighTimeX     res                         'Reserve one long of cog RAM for this "HighTime" variable
              fit                         'Makes sure the preceding code fits within cells 0-495 of the cog's RAM
DAT
              org                          'Assembles the next command to the first cell (cell 0) in the new cog's RAM
y_servo       mov       dira,YPin     'Set the direction of the "ServoPin" to be an output (and all others to be inputs)                                 
                                                                                                                      
LoopY         rdlong    HighTimeY,par      'Read the "position" variable (at "par") from Main RAM and store it as "HighTime"
              mov       counterY,cnt       'Store the current system clock count in the "counter" cell's address   
              mov       outa,AllOnY        'Set all pins on this cog high (really only sets ServoPin high b/c rest are inputs)            
              add       counterY,HighTimeY  'Add "HighTime" value to "counter" value
              waitcnt   counterY,LowTimeY   'Wait until "cnt" matches "counter" then add a 10ms delay to "counter" value 
              mov       outa,#0           'Set all pins on this cog low (really only sets ServoPin low b/c rest are inputs)
              waitcnt   counterY,0         'Wait until cnt matches counter (adds 0 to "counter" afterwards)
              jmp       #LoopY             'Jump back up to the cell labled "Loop"                                      
                                                                                                                    
'Constants and Variables:
YPin          long      |<      0 '<------- This sets the pin that outputs the servo signal (which is sent to the white wire
                                          ' on most servomotors). Here, this "7" indicates Pin 7. Simply change the "7" 
                                          ' to another number to specify another pin (0-31).
                                          ' servo behaves erratically, this value can be changed to 1_600_000 (20ms pause)                                  
AllOnY         long      $FFFFFFFF         'This will be used to set all of the pins high (this number is 32 ones in binary)
LowTimeY       long      1_600_000           'This works out to be a 10ms pause time with an 80MHz system clock. If the
                                          ' servo behaves erratically, this value can be changed to 1_600_000 (20ms pause) 

counterY      res                         'Reserve one long of cog RAM for this "counter" variable                     
HighTimeY     res                         'Reserve one long of cog RAM for this "HighTime" variable                                                                       
              fit                         'Makes sure the preceding code fits within cells 0-495 of the cog's RAM

Comments

  • JetfireJetfire Posts: 34
    edited 2009-03-17 17:29
    I'm not sure what is causing your first problem. One thing that I noticed is that the second waitcnt is:
    waitcnt   counterX,0
    


    This is adding the value of register 0 to counterX, not "0". Change it to:
    waitcnt   counterX,#0
    



    As for choosing the pin, you have everything in place. What you want to do is change XPin in Spin before you start the cog.
    XPin := |< 3
    cognew(@x_servo,@x_position)
    


    This change the value of XPin in the hub, when the cog starts this is brought into cog memory.

    You should also then be able to start two cogs using the same assembly by choosing the pin before you start them and giving them different parameter variables.
    XPin := |< 3
    cognew(@x_servo,@x_position)
    XPin := |< 5
    cognew(@x_servo,@y_position)
    
  • blake_machoblake_macho Posts: 5
    edited 2009-03-17 17:41
    JetFire, thanks for the info. I fixed the 0 to #0 issue (though it seemed to operate identically either way). And I had no idea I could change variables via Spin then call the PASM via cogs. So that helped as well.

    Sadly my original problem still exists, and I'm not sure why. Was wondering if anyone had any thoughts? The repeat 10 loop that is run first in the code works as expected, the second one doesn't. It basically does nothing. If you re-order the repeat 10 loops the other will work. I must be missing something just I'm not sure what. Also appears that the order of the cognew functions does not matter as well. Here is the updated code.

    CON
      _xinfreq=5_000_000            
      _clkmode=xtal1+pll16x                    'The system clock is set at 80MHz (this is recommended for optimal resolution)
      LASER = 26                                             
                                                                                                                             
    VAR                                                                                                                      
      long  x_position                           'The assembly program will read this variable from the main Hub RAM to determine
                                               ' the servo signal's high pulse duration
      long  y_position                                  
                                                                                                                               
    PUB Main                                                                                                                 
      Pin := |< 0
      cognew(@servo,@y_position)
      Pin := |< 5
      cognew(@servo,@x_position)        
      laser_toggle(1)
    
    'The new cog that is started above continuously reads the "position" variable as it's changed by the example Spin code below
    
      repeat 10                                                                                                                
        x_position:=96_000                       'Start sending 1ms servo signal high pulses (80_000 * 1/(80MHz clock freq) = 1ms)                                                     
        waitcnt(clkfreq+cnt)                   'Wait for 1 second (1ms high pulses continue to be generated by the other cog)                                                                
        x_position:=168_000                      'Start sending 1.375ms servo signal high pulses (Center position)                                                 
        waitcnt(clkfreq+cnt)                   'Wait for 1 second (1.5ms high pulses continue to be generated by the other cog)
    
      repeat 10
        y_position:=70_000
        waitcnt(clkfreq+cnt)
        y_position:=105_000
        waitcnt(clkfreq+cnt)
      
                                                       
    PUB laser_toggle(on)
      dira[noparse][[/noparse]LASER]~~
      outa[noparse][[/noparse]LASER] := on
    
    DAT
                org                          'Assembles the next command to the first cell (cell 0) in the new cog's RAM
    servo       mov       dira,Pin     'Set the direction of the "ServoPin" to be an output (and all others to be inputs)                                 
                                                                                                                          
    Loop        rdlong    HighTime,par      'Read the "position" variable (at "par") from Main RAM and store it as "HighTime"
                mov       counter,cnt       'Store the current system clock count in the "counter" cell's address   
                mov       outa,AllOn        'Set all pins on this cog high (really only sets ServoPin high b/c rest are inputs)            
                add       counter,HighTime  'Add "HighTime" value to "counter" value
                waitcnt   counter,LowTime   'Wait until "cnt" matches "counter" then add a 10ms delay to "counter" value 
                mov       outa,#0           'Set all pins on this cog low (really only sets ServoPin low b/c rest are inputs)
                waitcnt   counter,#0         'Wait until cnt matches counter (adds 0 to "counter" afterwards)
                jmp       #Loop            'Jump back up to the cell labled "Loop"                                      
                                                                                                                        
    'Constants and Variables:
    Pin          long      |<      5 '<------- This sets the pin that outputs the servo signal (which is sent to the white wire
                                              ' on most servomotors). Here, this "7" indicates Pin 7. Simply change the "7" 
                                              ' to another number to specify another pin (0-31).
                                              
    AllOn        long      $FFFFFFFF         'This will be used to set all of the pins high (this number is 32 ones in binary)
    LowTime      long      1_600_000           'This works out to be a 10ms pause time with an 80MHz system clock. If the
                                              ' servo behaves erratically, this value can be changed to 1_600_000 (20ms pause)                                  
    counter      res                         'Reserve one long of cog RAM for this "counter" variable                     
    HighTime     res                         'Reserve one long of cog RAM for this "HighTime" variable
                 fit                         'Makes sure the preceding code fits within cells 0-495 of the cog's RAM
    
    {Copyright (c) 2008 Gavin Garner, University of Virginia}
    

    Post Edited (blake_macho) : 3/17/2009 5:47:16 PM GMT
  • TreeLabTreeLab Posts: 138
    edited 2009-03-17 17:59
    Changing the 0 to #0 has no effect because at the top of the loop you explicitly set the value of counter to cnt, so it does not matter what was added at the end of the loop. #0 is better practice though because the value is well defined, where as register 0 may not be

    When you say it 'does nothing', does this mean that it does not execute, or the motors do not twitch, or ... ? If you do debug printing on each iteration of each repeat 10 loop, does it appear like the spin component is running as expected?

    My ignorance here : is there a limit on how many res can be listed at the end of PASM code?

    Cheers!
    Paul Rowntree

    Post Edited (TreeLab) : 3/17/2009 6:06:11 PM GMT
  • blake_machoblake_macho Posts: 5
    edited 2009-03-17 19:21
    Yes, when I say it does nothing I mean the motor does not twitch (e.g. the code running in the cog is not working correctly). The Spin code is working as expected for both loops. This is really weird and frustrating. =P

    Thanks for your help.
  • kwinnkwinn Posts: 8,697
    edited 2009-03-17 21:41
    When you swap the position of the "repeat 10" blocks does it change the servo that responds to the command? Does the X block move the X servo when it is first, and the Y block move the Y servo or does one servo move for both blocks?

    I am wondering if the Pin definition below is overriding the pin assignment before the cognew statement.

    'Constants and Variables:
    Pin long |< 5 '<
    This sets the pin that outputs the servo signal (which is sent to the white wire
  • blake_machoblake_macho Posts: 5
    edited 2009-03-23 05:21
    This was very frustrating! I resolved this by setting both x_position and y_position before the cognew commands. Then everything worked as expected.

    Thanks for the help.

    -Blake

    Post Edited (blake_macho) : 3/23/2009 5:26:29 AM GMT
  • jazzedjazzed Posts: 11,803
    edited 2009-03-23 06:15
    I bet without initializing the VAR positions, that you would eventually have movement if you wait long enough.

    Here's why:
    If VAR variable contents pre-initialized to 0 as seems to be the case by looking at the F8 output, you ended up
    getting a very long wait value for your pulse since the value you ended up waiting for with waitcnt had already
    passed by the time the instruction executed. If you use small values say <= 12 (3 instructions * 4 ticks per
    instruction) or very large values, you would have the same result.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
Sign In or Register to comment.