Shop OBEX P1 Docs P2 Docs Learn Events
How can you sync two cogs/frequencies? — Parallax Forums

How can you sync two cogs/frequencies?

turbosupraturbosupra Posts: 1,088
edited 2013-02-22 11:44 in Propeller 1
I have two cogs transmitting frequencies and would like to sync the frequencies. I'm using "frequency" generically as the rising to falling edge of a digital square wave

The cog A transmits 72 times before it repeats itself
The cog B transmits 3 times before it repeats itself

I would like for the cog B to transmit its 1st frequency when the cog A transmits its 19th frequency and based on timing the cog B should then transmit its 3rd frequency when the cog A transmits its 55th frequency. (rising edges aligned)


I spent the entire weekend rewriting these objects in PASM because of speed, I've tried having cog B read a frequency count value on Cog A, but I'm having timing errors because it will freeze.

Has anyone tried to sync two cogs this way, or is there a better way? I don't need a resolution of 10 clock cycles, but 1000 clock cycles or less would be nice. Unfortunately, I cannot attach an archive of the project until I get home (unless I could email it to someone), but here is the object for cog B. I've been at this for many hours and am not sure how to troubleshoot this. If someone is kind enough to look at this, and would like the whole project, please let me know your email address and I'll email it to you.

Thanks for reading.


CON

  _CLKMODE      = XTAL1 + PLL16X                        
  _CLKFREQ      = 80_000_000
  ' current code only allows from 1Hz upwards 
  MIN_FREQUENCY = 1
  ' dunno which upper limit can be achieved by the SPIN-code        
  MAX_FREQUENCY = 9200
  BAUDRATE   = 115_200


OBJ

  pst : "Parallax Serial Terminal"
   
VAR
  'byte   pin, presentTeeth, missingTeeth, cog
  'long   frequencyRate

  long  l_cog
  long  l_pst1
  long  l_pst2
  long  l_pst3
  long  l_pst4
  long  l_pst5
  long  l_pst6
  long  l_pst7
  long  l_pst8
  long  l_pst9
  long  l_pst10
  long  l_pst11
  long  l_pst12
  long  l_pst13
  long  l_pst14
  long  l_pst15
  long  l_pst16

  
  long  l_pin
  long  l_pinAddr
  long  l_rpm
  long  l_rpmAddr
  long  l_rotationalRatio
  long  l_rotationalRatioAddr
  long  l_teeth
  long  l_teethAddr
  long  l_missingTeeth
  long  l_missingTeethAddr
  long  l_gap1
  long  l_gap1Addr
  long  l_gap2
  long  l_gap2Addr
  long  l_gap3
  long  l_gap3Addr
  long  l_trigger
  long  l_triggerAddr
  long  l_correction
  long  l_correctionAddr
  long  l_crankToothNum
  long  l_crankToothNumAddr
  

  

  long  l_rpmTemp
  long  l_pinTemp
  long  l_tmp
  long  l_pinAddrTest
  long  l_rpmAddrTest
  long  l_rotationalRatioAddrTest
  long  l_teethAddrTest
  long  l_missingTeethAddrTest
  long  l_gap1AddrTest
  long  l_gap2AddrTest
  long  l_gap3AddrTest
  long  l_triggerAddrTest
  long  l_correctionAddrTest
  long  l_crankToothNumAddrTest

pub main

  pst.Start( BAUDRATE )

 

        l_tmp:=-1
        repeat while l_tmp==-1
          pst.str( string( " ",$0d,"== please press key to start ==",$0d ) )
          l_tmp:=pst.rxcheck
          if l_tmp==-1
             waitcnt( clkfreq+cnt )
         
        pst.Clear
        pst.str( string( "Starting COG!",$0d ) )
  
  pstInitScreen
  

  l_pin := 9 ' quick start
  l_pinAddrTest := @l_pin
  'l_rpm := 11000
  l_rpm := 700
  l_rpmAddrTest := @l_rpm
  l_rotationalRatio := 2
  l_rotationalRatioAddrTest := @l_rotationalRatio
  l_teeth := 3
  l_teethAddrTest := @l_teeth
  l_missingTeeth := 1
  l_missingTeethAddrTest := @l_missingTeeth
  l_gap1 := 72
  l_gap1AddrTest := @l_gap1
  l_gap2 := 72
  l_gap2AddrTest := @l_gap2
  l_gap3 := 159
  l_gap3AddrTest := @l_gap3
  l_trigger := 19
  l_triggerAddrTest := @l_trigger
  l_correction := 0
  l_correctionAddrTest := @l_correction
  l_crankToothNum := 19
  l_crankToothNumAddrTest := @l_crankToothNum
  
  
  ' (p, r, rots, one, two, three, trig, degDiff, autoCorr, crTthAddr, caTthAddr, crToothRpmAddr)
  'init(l_pinTemp, 1000, 2, 72, 72, 159, 19, 0, false, 21, 3, @l_rpmTemp)
  init(l_pinAddrTest, l_rpmAddrTest, l_rotationalRatioAddrTest, l_gap1AddrTest, l_gap2AddrTest, l_gap3AddrTest, l_triggerAddrTest, l_teethAddrTest, l_missingTeethAddrTest, l_correctionAddrTest, l_crankToothNumAddrTest)
  
  pst.char(13)
  pst.char(13)

  
  
  repeat

    pstCom
    'l_rpm += 1
    'l_crankToothNum += 1
    
 
    
pub init(pinAddr, rpmAddr, rotsAddr, oneAddr, twoAddr, threeAddr, trigAddr, teethAddr, missingTeethAddr, correctionAddr, crankToothNumAddr) 
                   
  waitcnt((clkfreq*1) + cnt)    ' let screen initialize
  
  l_pinAddr := pinAddr
  l_rpmAddr := rpmAddr
  l_rotationalRatioAddr := rotsAddr
  l_gap1Addr := oneAddr
  l_gap2Addr := twoAddr
  l_gap3Addr := threeAddr
  l_triggerAddr := trigAddr
  l_TeethAddr := teethAddr
  l_missingTeethAddr := missingTeethAddr                                               
  l_correctionAddr := correctionAddr
  l_crankToothNumAddr := crankToothNumAddr
  {
  pst.char(13)
  pst.char(13)                                                 
  pst.dec(long[l_pinAddr])
  pst.char(13)
  pst.dec(long[l_rpmAddr])
  pst.char(13)
  pst.dec(long[l_rotationalRatioAddr])
  pst.char(13)
  pst.dec(long[l_gap1Addr])
  pst.char(13)
  pst.dec(long[l_gap2Addr])
  pst.char(13)
  pst.dec(long[l_gap3Addr])
  pst.char(13)
  pst.dec(long[l_triggerAddr])
  pst.char(13)
  pst.dec(long[l_TeethAddr])
  pst.char(13)
  pst.dec(long[l_missingTeethAddr])
  pst.char(13)
  pst.dec(long[l_correctionAddr])
  pst.char(13)
  pst.dec(long[l_crankToothNumAddr])
  pst.char(13) 
  }
  return l_cog := cognew(@camsim, @l_cog) + 1
  

PUB pstCom | lpcnt1,lpcnt2

  lpcnt1:=0                                
  lpcnt2:=0

 
  'repeat
    charAt( 12,2 , proc[ lpcnt1 ] )
    lpcnt1 := (lpcnt1+1) & 3

      
      charAt( 28,2 , proc[ lpcnt2 ] )
      lpcnt2 := (lpcnt2+1) & 3
    
      charAt( 12, 4, " " )  ' ("object1 cog:") )
      pst.Dec(l_cog)    
      pst.str(@spaces)
                                                                
      charAt( 43, 4, " " )  ' ( "caGap RPM:" ) )
      pst.Dec(-7)   
      pst.str(@spaces)

      charAt( 72, 4, " " )  ' ( "+Degrees:" ) )
      pst.Dec(-7)     
      pst.str(@spaces)

      charAt( 102, 4, " " )  ' ( "Tar Ang:" ) )
      pst.Dec(-7)    
      pst.str(@spaces)
      
      charAt( 12, 5, " " )  ' ("crGap RPM:") )
      pst.Dec(-7)    
      pst.str(@spaces)
                                                                
      charAt( 43, 5, " " )  ' ( "caGap RPM:" ) )
      pst.Dec(-7)   
      pst.str(@spaces)

      charAt( 72, 5, " " )  ' ( "+Degrees:" ) )
      pst.Dec(-7)     
      pst.str(@spaces)

      charAt( 102, 5, " " )  ' ( "Tar Ang:" ) )
      pst.Dec(-7)    
      pst.str(@spaces)

      charAt( 12, 6, " " )  '  ("crTth RPM:") ) 
      pst.dec(-7)   
      pst.str(@spaces)

      charAt( 43, 6, " " )  ' ( "caTth RPM:" ) )
      pst.dec(-7)
      pst.str(@spaces)

      charAt( 72, 6, " " )  ' ( Not used ) )
      pst.dec(-7)
      pst.str(@spaces)
      
      charAt( 102, 6, " " )  ' ( "angDiff:" ) )
      pst.Dec(-7)     
      pst.str(@spaces)

      charAt( 12, 7, " " )  ' ("crGapTime:" ) )
      pst.dec(-7)
      pst.str(@spaces)

      charAt( 43, 7, " " )  ' ("caGapTime:") )
      pst.dec(-7)
      pst.str(@spaces)

      charAt( 72, 7, " " )  ' ("cr-CaTime:") )
      pst.dec(-7)
      pst.str(@spaces)

      charAt( 102, 7, " " )  ' ( "hz:" ) )
      pst.Dec(-7)     
      pst.str(@spaces)

      charAt( 12, 8, " " )  ' ("crAvgCyc:" ) )
      pst.dec(-7)
      pst.str(@spaces)

      charAt( 43, 8, " " )  ' ("caAvgCyc:") )
      pst.dec(-7)
      pst.str(@spaces)                      

      charAt( 72, 8, " " ) ' ("Cycl/Deg:") )
      pst.dec(-7)
      pst.str(@spaces)

      charAt( 102, 8, " " )  ' ( "hzCycles:" ) )
      pst.Dec(-7)     
      pst.str(@spaces)

      charAt( 12, 9, " " )  ' ("toothNum:" ) )
      pst.dec(-7)
      pst.str(@spaces)
      

      
      charAt( 12, 21, " " )  ' ("Pst1:") )
      pst.bin(getPst1, 32)
      pst.str(@spaces)

      charAt( 12, 22, " " )  ' ("Pst2:") )
      pst.dec(getPst2)
      pst.str(@spaces)

      charAt( 12, 23, " " )  ' ("Pst3:") ) 
      pst.dec(getPst3)
      pst.str(@spaces)

      charAt( 12, 24, " " )  ' ("Pst4:") )
      pst.dec(getPst4)
      pst.str(@spaces)

      charAt( 12, 25, " " )  ' ("Pst5:") )
      pst.dec(getPst5)
      pst.str(@spaces)
      
      charAt( 12, 26, " " )  ' ("Pst6:") )
      pst.dec(getPst6)
      pst.str(@spaces)

      charAt( 12, 27, " " )  ' ("Pst7:") )
      pst.dec(getPst7)
      pst.str(@spaces)
      
      charAt( 12, 28, " " )  ' ("Pst8:") )
      pst.dec(getPst8)
      pst.str(@spaces)
      
      charAt( 12, 29, " " )  ' ("Pst9:") )
      pst.dec(getPst9)
      pst.str(@spaces)

      charAt( 12, 30, " " )  ' ("Pst10:") )
      pst.dec(getPst10)
      pst.str(@spaces)
      
      charAt( 12, 31, " " )  ' ("Pst11:") )
      pst.dec(getPst11)
      pst.str(@spaces)

      charAt( 12, 32, " " )  ' ("Pst12:") )
      pst.dec(getPst12)
      pst.str(@spaces)
      
      charAt( 12, 33, " " )  ' ("Pst13:") )
      pst.dec(getPst13)
      pst.str(@spaces)
      
      charAt( 12, 34, " " )  ' ("Pst14:") )
      pst.dec(getPst14)
      pst.str(@spaces)
       
      charAt( 12, 35, " " )  ' ("Pst15:") )
      pst.dec(getPst15)
      pst.str(@spaces)

      charAt( 12, 36, " " )  ' ("Pst16:") )
      pst.dec(getPst16)'getPst16)
      pst.str(@spaces)
    

  




PUB pstInitScreen
  printAt( 1,2, string("Main loop [ ]") )
  printAt( 20,2, string("Update [ ]") )
  printAt( 3,4, string("cog:") )
  printAt( 33, 4, string( "cog:" ) )
  printAt( 63,4, string("cog:") )
  printAt( 93,4, string("cog:") )
  printAt( 3,5, string("crGap RPM:") )
  printAt( 33, 5, string( "caGap RPM:" ) )
  printAt( 63,5, string("+Degrees:") )
  printAt( 93,5, string("Targ Ang:") )
  printAt( 3,6, string("crTth RPM:") )
  printAt( 33, 6, string( "caTth RPM:" ) )
  printAt( 63, 6, string( ":" ) )
  printAt( 93, 6, string( "angDiff:" ) )
  printAt( 3,7, string("crGapTime:" ) )
  printAt( 33,7, string("caGapTime:") )
  printAt( 63,7, string("cr-CaTime:") )
  printAt( 93,7, string("hz:") )    
  printAt( 3,8, string("crAvgCyc:") )
  printAt( 33,8, string("caAvgCyc:") )
  printAt( 63,8, string("Cycl/Deg:") )
  printAt( 93,8, string("hzCycles:") )
  printAt( 3,9, string("toothNum:") )  
  {printAt( 33,8, string("T Cnt Max") )
  printAt( 3,9, string("Min") )
  printAt( 33,9, string("Max") )
  printAt( 3,10, string("Gap Cnt") )
  printAt( 33,10, string("Gap Cnt/Sec") )

  printAt( 33,11, string("Gap Rpm:") ) }

  printAt( 3,21, string("Pst1:") )
  printAt( 3,22, string("Pst2:") )
  printAt( 3,23, string("Pst3:") )
  printAt( 3,24, string("Pst4:") )
  printAt( 3,25, string("Pst5:") )
  printAt( 3,26, string("Pst6:") )
  printAt( 3,27, string("Pst7:") )
  printAt( 3,28, string("Pst8:") )
  printAt( 3,29, string("Pst9:") )
  printAt( 3,30, string("Pst10:") )
  printAt( 3,31, string("Pst11:") )
  printAt( 3,32, string("Pst12:") )
  printAt( 3,33, string("Pst13:") )
  printAt( 3,34, string("Pst14:") )
  printAt( 3,35, string("Pst15:") )
  printAt( 3,36, string("Pst16:") )


dat
spaces byte "     ",0
proc   byte "-/|\"


pub charAt( x,y,c )
  ' output a character if it's in screen-range and if it's a printable character
  if x>0 and x<109 and y>0 and y<75 and c>31 and c<128
    posbuf[1]:=x
    posbuf[2]:=y
    posbuf[3]:=c
    pst.str(@posbuf)

pub printAt( x, y, text)
  ' set cursor position and print string
  posbuf[1]:=x
  posbuf[2]:=y
  posbuf[3]:=0
  pst.str(@posbuf)
  pst.str( text )
        
dat
' a buffer to assemble the bytestream for positioning
posbuf byte 2, 0, 0, 0, 0
      
    
    
pub getCog
  result := l_cog


pub setCorrection(val)
  l_correction := val
      
pub getPst1
  result := l_pst1

pub getPst2
  result := l_pst2

pub getPst3
  result := l_pst3

pub getPst4
  result := l_pst4

pub getPst5
  result := l_pst5

pub getPst6
  result := l_pst6

pub getPst7
  result := l_pst7

pub getPst8
  result := l_pst8                     

pub getPst9
  result := l_pst9                     

pub getPst10
  result := l_pst10                     

pub getPst11
  result := l_pst11                     

pub getPst12
  result := l_pst12                     

pub getPst13
  result := l_pst13                     

pub getPst14
  result := l_pst14

pub getPst15
  result := l_pst15                     

pub getPst16
  result := l_pst16



    
DAT

                        org     0

camsim
                      

                        add     cogPtr, par
                        add     pstPtr1, par
                        add     pstPtr2, par
                        add     pstPtr3, par
                        add     pstPtr4, par
                        add     pstPtr5, par
                        add     pstPtr6, par
                        add     pstPtr7, par
                        add     pstPtr8, par
                        add     pstPtr9, par
                        add     pstPtr10, par
                        add     pstPtr11, par
                        add     pstPtr12, par
                        add     pstPtr13, par
                        add     pstPtr14, par
                        add     pstPtr15, par
                        add     pstPtr16, par                       
                        add     pinPtr, par
                        add     pinAddrPtr, par
                        add     rpmPtr, par
                        add     rpmAddrPtr, par
                        add     rotationalRatioPtr, par
                        add     rotationalRatioAddrPtr, par
                        add     teethPtr, par
                        add     teethAddrPtr, par
                        add     missingTeethPtr, par
                        add     missingTeethAddrPtr, par
                        add     gap1Ptr, par
                        add     gap1AddrPtr, par
                        add     gap2Ptr, par
                        add     gap2AddrPtr, par
                        add     gap3Ptr, par
                        add     gap3AddrPtr, par
                        add     triggerPtr, par
                        add     triggerAddrPtr, par
                        add     correctionPtr, par
                        add     correctionAddrPtr, par
                        add     crankToothNumPtr, par
                        add     crankToothNumAddrPtr, par
  
                        rdlong  pinAddrPtr, pinAddrPtr
                        rdlong  rpmAddrPtr, rpmAddrPtr
                        rdlong  rotationalRatioAddrPtr, rotationalRatioAddrPtr
                        rdlong  teethAddrPtr, teethAddrPtr
                        rdlong  missingTeethAddrPtr, missingTeethAddrPtr
                        rdlong  gap1AddrPtr, gap1AddrPtr
                        rdlong  gap2AddrPtr, gap2AddrPtr
                        rdlong  gap3AddrPtr, gap3AddrPtr
                        rdlong  triggerAddrPtr, triggerAddrPtr
                        rdlong  correctionAddrPtr, correctionAddrPtr
                        rdlong  crankToothNumAddrPtr, crankToothNumAddrPtr

                      

                        

initialize
                       

                        'mov     pinMask, #1                     ' create mask from pin #
                        'shl     pinMask, pinAddrPtr
                        mov     dira, pinMask
                        
                        

syncCr
                        rdlong  crankToothNumSync, crankToothNumAddrPtr            ' waits for the rising edge
                        cmp     crankToothNumSync, #19 WC, WZ
'if_e                    wrlong  phaseTwo, pstPtr12
'if_e                    jmp     #syncCa
if_ne                   jmp     #syncCr


                        mov     timeStamp, cnt
restart
                        
                        mov     startTime, cnt
                        
                        'rdlong  rpm, rpmAddrPtr           ' waits for the rising edge

                        rdlong  pin, pinAddrPtr
                        rdlong  rpm, rpmAddrPtr
                        rdlong  rotationalRatio, rotationalRatioAddrPtr
                        rdlong  teeth, teethAddrPtr
                        rdlong  missingTeeth, missingTeethAddrPtr
                        rdlong  gap1, gap1AddrPtr
                        rdlong  gap2, gap2AddrPtr
                        rdlong  gap3, gap3AddrPtr
                        rdlong  trigger, triggerAddrPtr
                        rdlong  correction, correctionAddrPtr
                        rdlong  crankToothNum, crankToothNumAddrPtr
                        
                        wrlong  pinMask, pstPtr1
                        wrlong  rpm, pstPtr2
                        wrlong  rotationalRatio, pstPtr3
                        'wrlong  teeth, pstPtr4
                        'wrlong  missingTeeth, pstPtr5
                        'wrlong  gap1, pstPtr6
                        'wrlong  gap2, pstPtr7
                        'wrlong  gap3, pstPtr8
                        'wrlong  trigger, pstPtr9
                        'wrlong  correction, pstPtr10
                        wrlong  crankToothNum, pstPtr9
                        
                        
                        mov     LNMultiplyMultiplicand, rpm        '         
                        mov     LNMultiplyMultiplier, #10                     ' * 10  
                        call    #LNMultiply
                        mov     currentCrankRpm, multiplicationResult        ' cycles per 10 degrees of rotation
                        
                        mov     LNDivideDividend, currentCrankRpm     
                        mov     LNDivideDivsor, #60             
                        call    #LNDivide                                       
                        mov     crankRpmPerSec, divisionResult                  ' crank rpm per second

                        mov     LNDivideDividend, crankRpmPerSec    
                        mov     LNDivideDivsor, #2             
                        call    #LNDivide                                       
                        mov     camRpmPerSec, divisionResult                    ' cam rpm per second

                        mov     LNDivideDividend, clk                           ' 80000000
                        mov     LNDivideDivsor, camRpmPerSec                    ' /5000
                        call    #LNDivide                                       
                        mov     cyclesDegOfRot, divisionResult                  
                        mov     LNDivideDividend, cyclesDegOfRot                ' 960000 cycles   
                        mov     LNDivideDivsor, #360                            ' /360
                        call    #LNDivide                                       
                        mov     cyclesDegOfRot, divisionResult                ' cycles per degree of rotation
                         
                        mov     LNMultiplyMultiplicand, cyclesDegOfRot        '         
                        mov     LNMultiplyMultiplier, #10                     ' * 10  
                        call    #LNMultiply
                        mov     cyclesDegOfRot, multiplicationResult        ' cycles per degree of rotation
                       
                        mov     LNMultiplyMultiplicand, cyclesDegOfRot        '         
                        mov     LNMultiplyMultiplier, #10                     ' * 10  
                        call    #LNMultiply
                        mov     cycles10DegOfRot, multiplicationResult        ' cycles per 10 degrees of rotation        

                        mov     LNMultiplyMultiplicand, cyclesDegOfRot              
                        mov     LNMultiplyMultiplier, gap1                     
                        call    #LNMultiply
                        mov     empty1Wait, multiplicationResult              ' gap wait 1

                        mov     LNMultiplyMultiplicand, cyclesDegOfRot              
                        mov     LNMultiplyMultiplier, gap2                    
                        call    #LNMultiply
                        mov     empty2Wait, multiplicationResult              ' gap wait 2

                        mov     LNMultiplyMultiplicand, cyclesDegOfRot              
                        mov     LNMultiplyMultiplier, gap3                     
                        call    #LNMultiply
                        mov     empty3Wait, multiplicationResult              ' gap wait 3

                        mov     LNDivideDividend, empty3Wait                ' 960000 cycles   
                        mov     LNDivideDivsor, #2                            ' /360
                        call    #LNDivide                                       
                        mov     empty3HalfWait, divisionResult                ' cycles per degree of rotation
                        

                        mov     LNMultiplyMultiplicand, cyclesDegOfRot              
                        mov     LNMultiplyMultiplier, trigger                     
                        call    #LNMultiply
                        mov     trig1Wait, multiplicationResult               ' trigger 1 wait 

                        mov     LNMultiplyMultiplicand, cyclesDegOfRot              
                        mov     LNMultiplyMultiplier, trigger                     
                        call    #LNMultiply
                        mov     trig2Wait, multiplicationResult               ' trigger 2 wait 

                        mov     LNMultiplyMultiplicand, cyclesDegOfRot              
                        mov     LNMultiplyMultiplier, trigger                     
                        call    #LNMultiply
                        mov     trig3Wait, multiplicationResult               ' trigger 3 wait

                        wrlong  trig1Wait, pstPtr4
                        wrlong  trig2Wait, pstPtr5
                        wrlong  empty1Wait, pstPtr6
                        wrlong  empty2Wait, pstPtr7
                        wrlong  empty3Wait, pstPtr8
                        mov     prevTimeStamp, timeStamp
                        add     loopCount, #1
                        wrlong  loopCount, pstPtr10

                        {mov     endTime, cnt
                        sub     endTime, startTime
                        wrlong  endTime, pstPtr12}
                        wrlong  timeStamp, pstPtr11
                        mov     cnt, cnt
                        wrlong  cnt, pstPtr12
                        
:synctooth19                        
                        'rdlong  crankToothNumAddrPtr, crankToothNumAddrPtr            ' waits for the rising edge
'                        cmp     crankToothNum, #19 WZ, WC
'if_ne                   jmp     #:synctooth19                        
                        {calculate how long to wait after tooth 19 to tooth 24, which is a 50 degree spread}

                        add     toothNumber, #1
                        or      outa, pinMask                     ' set pin high
                        add     timeStamp, trig1Wait         ' add the amount of cycles that the pulseWidth should be HIGH to timeStamp, so cmp is not true until after that
                        waitcnt timeStamp, #0         
                        andn    outa, pinMask                 ' set pin low
                        add     timeStamp, empty1Wait        ' add the amount of cycles that the pulseWidth should be LOW to timeStamp, so cmp is not true until after that    
                        waitcnt timeStamp, #0
                        
                        add     toothNumber, #1
                        or      outa, pinMask                     ' set pin high
                        add     timeStamp, trig2Wait         ' add the amount of cycles that the pulseWidth should be HIGH to timeStamp, so cmp is not true until after that
                        waitcnt timeStamp, #0         
                        andn    outa, pinMask                 ' set pin low
                        add     timeStamp, empty2Wait        ' add the amount of cycles that the pulseWidth should be LOW to timeStamp, so cmp is not true until after that    
                        waitcnt timeStamp, #0

                        add     toothNumber, #1
                        or      outa, pinMask                     ' set pin high
                        add     timeStamp, trig3Wait         ' add the amount of cycles that the pulseWidth should be HIGH to timeStamp, so cmp is not true until after that
                        waitcnt timeStamp, #0         
                        andn    outa, pinMask                 ' set pin low
                        add     timeStamp, empty3Wait        ' add the amount of cycles that the pulseWidth should be LOW to timeStamp, so cmp is not true until after that
                        mov     toothNumber, #0    
                        waitcnt timeStamp, #0
                        
 
                        jmp     #restart


                        

' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'                       Unsigned Divide
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

LNDivide                mov     LNDivideQuotient,       #0                           ' Setup to divide.
                        mov     LNDivideBuffer,         #0                           '
                        mov     LNDivideCounter,        #32                          '

                        cmp     LNDivideDivsor,         #0 wz                        ' Clear if dividing by zero.
if_z                    mov     LNDivideDividend,       #0                           '
if_z                    jmp     #LNDivide_ret                                        '
                     
LNDivideLoopPre         shr     LNDivideDivsor,         #1 wc, wz                    ' Align divisor MSB and count size.
                        rcr     LNDivideBuffer,         #1                           '
if_nz                   djnz    LNDivideCounter,        #LNDivideLoopPre             '
                                                  
LNDivideLoopPost        cmpsub  LNDivideDividend,       LNDivideBuffer wc            ' Preform division.
                        rcl     LNDivideQuotient,       #1                           '
                        shr     LNDivideBuffer,         #1                           '
                        djnz    LNDivideCounter,        #LNDivideLoopPost            '
                          
                        'wrlong  LNDivideQuotient, pstptr7
                        'wrlong  LNDivideDividend, pstptr8
                        mov     divisionResult, LNDivideQuotient  
LNDivide_ret            ret                                                          ' Return. Remainder in dividend on exit.

' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'                       Unsigned Multiply                            
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

LNMultiply              mov     LNMultiplyProduct,      #0                           ' Clear product.

LNMultiplyLoop          shr     LNMultiplyMultiplicand, #1 wc                        ' Preform multiplication.
if_c                    add     LNMultiplyProduct,      LNMultiplyMultiplier         '
                        shl     LNMultiplyMultiplier,   #1                           '     
                        tjnz    LNMultiplyMultiplicand, #LNMultiplyLoop              '  
                        mov     multiplicationResult, LNMultiplyProduct
LNMultiply_ret          ret                                                          ' Return.

' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'                       Data
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


                  
' --------------------------------------------------------------------------------------------------

cogPtr                  long    0 
pstPtr1                 long    4
pstPtr2                 long    8
pstPtr3                 long    12
pstPtr4                 long    16
pstPtr5                 long    20
pstPtr6                 long    24
pstPtr7                 long    28
pstPtr8                 long    32
pstPtr9                 long    36
pstPtr10                long    40
pstPtr11                long    44
pstPtr12                long    48
pstPtr13                long    52
pstPtr14                long    56
pstPtr15                long    60
pstPtr16                long    64
pinPtr                  long    68
pinAddrPtr              long    72
rpmPtr                  long    76
rpmAddrPtr              long    80
rotationalRatioPtr      long    84
rotationalRatioAddrPtr  long    88
teethPtr                long    92
teethAddrPtr            long    96
missingTeethPtr         long    100
missingTeethAddrPtr     long    104
gap1Ptr                 long    108
gap1AddrPtr             long    112
gap2Ptr                 long    116
gap2AddrPtr             long    120
gap3Ptr                 long    124
gap3AddrPtr             long    128
triggerPtr              long    132
triggerAddrPtr          long    136
correctionPtr           long    140
correctionAddrPtr       long    144
crankToothNumPtr        long    148
crankToothNumAddrPtr    long    152

                 
  




' Standard variables here

divisionResult          long    0
multiplicationResult    long    0
camSimPin               long    0
crankRpmPerSec          long    0
camRpmPerSec            long    0        
cyclesDegOfRot          long    0
cycles10DegOfRot        long    0
toothWaitDel            long    0
trig1Wait               long    0
trig2Wait               long    0
trig3Wait               long    0
empty1Wait              long    0
empty2Wait              long    0
empty3Wait              long    0
empty3HalfWait          long    0
skewableWait            long    0  
phaseState              long    0
timeStamp               long    0
currentCrankRpm         long    0
syncPauseCycles         long    0
camSimPinMask           long    0
camPwmMonitorPin        long    0
camPwmMonitorPinMask    long    0
lowCycles               long    0
highCycles              long    0
wait                    long    0
tmptime1                long    0
tmptime2                long    0
ontix                   long    40000000
offtix                  long    40000000
timer                   long    0
loopCnt                 long    0
pinsState               long    0
                                                                            'pin 17/led                      pin 9
pinMask                 long    %00000000000000000000001000000000'%00000000000000100000000000000000'%00000000000000000000001000000000
toothNumber             long    0
pin                     long    0
rpm                     long    0
rotationalRatio         long    0
teeth                   long    0
missingTeeth            long    0
gap1                    long    0
gap2                    long    0
gap3                    long    0
trigger                 long    0
correction              long    0
crankToothNum           long    0
crankToothNumSync       long    0        


' Variables with non 0 values here

clk                     long    80000000
phaseOne                long    1
phaseTwo                long    2
phaseThree              long    3
phaseFour               long    4
phaseFive               long    5
phaseSix                long    6
phaseSeven              long    7
POS_DETECT              long    %01000 << 26 
NEG_DETECT              long    %01100 << 26
oneHunFiftyThou         long    150000


' Temporary troubleshooting values here
prevTimeStamp           long    0
loopCount               long    0
startTime               long    0
endTime                 long    0


' Reserved variables here

tmp1                    res     1
tmp2                    res     1
mask                    res     1                               ' mask for frequency input pin


' //////////////////////Math Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
LNDivideBuffer          res     1
LNDivideCounter         res     1
LNDivideDividend        res     1
LNDivideDivsor          res     1
LNDivideQuotient        res     1

LNMultiplyMultiplicand  res     1
LNMultiplyMultiplier    res     1
LNMultiplyProduct       res     1


                        fit     492






{PUB simulateCamWheel(simCamWheelPinNum, engineRPM, crankRotsToCamRots, degreeOfTrigger1, degreeOfTrigger2, degreeOfTrigger3, camTriggerDegreeWidth, autoCorrectVvti, degreesDiff, crTooth) | localIndex, crankRpmPerSecond, camRpmPerSecond, localCnt, trigger1Wait, trigger2Wait, trigger3Wait, emtpySpace1Wait, emtpySpace2Wait, emtpySpace3Wait, cyclesPerDegOfRot, toothWaitDelay, startTooth, autoRangeChangesPerSecond, advancing, retarding, degreesShifted, updateCnt, tenDeg, fiftyDeg, emtpySpace3WaitSansDelay, variableDelay, loopCnt, prevLoopCnt, degAdv, crankTooth

  

  
  
  dira[simCamWheelPinNum]~~
  outa[simCamWheelPinNum]~
  localIndex := 0

  'if (engineRPM >= 720)
    'crankRpmPerSecond := (engineRPM/60)                   ' 166.667 crank rots per second at 10k rpm
    camRpmPerSecond := (((engineRPM*100)/60)/2)                 ' 83.333 cam rots per second at 10k rpm
    cyclesPerDegOfRot := ((((clkfreq/camRpmPerSecond))*10/36))'0)*10)  ' 960000/360 at 10k or 2660
    'toothWaitDelay := (clkfreq/(crankRpmPerSecond*36))
    'autoRangeChangesPerSecond := (clkfreq/degreeChangesPerSecond)
  {else
    'camRpmPerSecond := (((engineRPM*1000)/60)/2)
    'cyclesPerDegOfRot := (((clkfreq/camRpmPerSecond)/360)*1000)  ' 960000/360 at 10k or 2660      1600000000 at 6rpm
     cyclesPerDegOfRot := 444444}
     
  trigger1Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 19 degrees
  trigger2Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 19 degrees
  trigger3Wait := (camTriggerDegreeWidth*cyclesPerDegOfRot)                     ' 19 degrees
  emtpySpace1Wait := (degreeOfTrigger1*cyclesPerDegOfRot)                       ' 72 degrees
  emtpySpace2Wait := (degreeOfTrigger2*cyclesPerDegOfRot)                       ' 72 degrees 
  emtpySpace3Wait := (degreeOfTrigger3*cyclesPerDegOfRot)                       ' 159 degrees
  tenDeg  := (10*cyclesPerDegOfRot)  
  'emtpySpace3WaitSansDelay := (emtpySpace3Wait-tenDeg)
  fiftyDeg := (50*cyclesPerDegOfRot) 
  emtpySpace3WaitSansDelay := (emtpySpace3Wait-fiftyDeg)                         

  {
    if rpm is < 1000, then leave cam at 0, if above 1000 check the pulse width of the factory ecu
    0 is the rising edge of 0 crank tooth 26, the start needs to be aligned with this
    factory ecu is 300hz
    100% pulse width is 266666 cycles
    50% is 133333
    75% is 200000
    25% is 66666
    if pulse high of pin is measured at > 150000 cycles, you need to advance, meaning pulse 75% high / 25% low 
    if pulse high of a pin is measured between 100000 and 150000, you stay, meaning pulse 50% high / 50% low
    if pulse high of a pin is measured < 100000, you retard, meaning pulse 25% high / 75% low
    may be able to set up a cntr in this cog and then call it and test
  }                                                                            

  'l_pst1 := trigger1Wait
  'l_pst2 := trigger2Wait
  'l_pst3 := trigger3Wait
  'l_pst4 := emtpySpace1Wait
  'l_pst5 := emtpySpace2Wait
  'l_pst6 := emtpySpace3Wait
  'l_pst9 := tenDeg
  l_pst15 := camRpmPerSecond
  l_pst16 := cyclesPerDegOfRot
  'l_pst12 := fiftyDeg

  repeat until (crankTooth == 26)

    crankTooth := long[crTooth] 
                                       
  'startTooth := 26
  localCnt := cnt                                      

  repeat

    prevLoopCnt := loopCnt
    loopCnt := cnt
    l_pst7 := (loopCnt - prevLoopCnt)
    degAdv := long[degreesDiff]
    l_pst6 := degAdv

    if (degAdv > 35)
      l_variableDegreeDelay := 5

    if (degAdv < 15)
      l_variableDegreeDelay := -5
    
    if (l_variableDegreeDelay <> 0)
      variableDelay := (l_variableDegreeDelay * cyclesPerDegOfRot)
      l_variableDegreeDelay := 0

    waitcnt(localCnt += (variableDelay + fiftyDeg))
    variableDelay := 0
     
    outa[simCamWheelPinNum]~~                           ' pin high
    waitcnt(localCnt += trigger1Wait)                   ' wait cnt time stamp plus trigger degree width in cycles                    
    outa[simCamWheelPinNum]~                            ' pin low
    'waitcnt(localCnt += (clkfreq/521))                 
    waitcnt(localCnt += emtpySpace1Wait)                ' wait cnt time stamp plus first empty space degree width in cycles
    outa[simCamWheelPinNum]~~                           ' pin high
    waitcnt(localCnt += trigger2Wait)                   ' wait cnt time stamp plus trigger degree width in cycles              
    outa[simCamWheelPinNum]~                            ' pin low
    'waitcnt(localCnt += (clkfreq/521))                  
    waitcnt(localCnt += emtpySpace2Wait)                ' wait cnt time stamp plus second empty space degree width in cycles
    outa[simCamWheelPinNum]~~                           ' pin high
    waitcnt(localCnt += trigger3Wait)                   ' wait cnt time stamp plus trigger degree width in cycles            
    outa[simCamWheelPinNum]~                            ' pin low
    'waitcnt(localCnt += (clkfreq/521))               
    'waitcnt(localCnt += emtpySpace3Wait)                ' wait cnt time stamp plus third empty space degree width in cycles
     waitcnt(localCnt += emtpySpace3WaitSansDelay)

}     
                        

Comments

  • pik33pik33 Posts: 2,367
    edited 2012-05-14 09:21
    One method of synchronizing cogs is using cnt. Cnt is the same for all cogs. If uou use waitcnt, in both cogs, you will have your cogs synchronized

    In my first tries to write a video driver I used waitpeq to synchronize cogs. First cog displays a picture. Second cog waits for Vsync pin low, then do its work, counting Hsync pins low, also with waitpeq.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-14 10:10
    Hello,

    Thanks for the reply. I'm not sure how I would implement that, since I need to sync with a specific event and keep sync based on that specific event (with a small skew)? Maybe I'm not understanding and you can elaborate?

    Do I need to pass a cnt value from the main cog to all of my other cogs that I want to sync?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-14 10:48
    pik33 ... thank you.

    You spurred me to a thought that I wouldn't have come up with on my own. I sync my timeStamp for the waitcnt of cog B, when cog A frequency count = 19. I sync them by obtaining the system count when frequency count = 19 ... similar to what you suggested.

    This worked at 500hz and 6500hz, which is roughly the window I need : D.

    In case someone comes across this in a search, here is my code adjustment. The way it works is that cog B reads a frequency count address from cog A. Cog B does the things it needs to do and then loops around to the synctooth19 synchronization loop and sits there until the frequency count address from cog A = 19. Then it does what it needs to do and repeats.

    I'm going to create a skew value after that, so I can shift it back and forth a little right after count = 19.
    :synctooth19                        
                            rdlong  crankToothNum, crankToothNumAddrPtr            ' waits for the rising edge
                            wrlong  crankToothNum, pstPtr16
                            cmp     crankToothNum, #19 WZ, WC
    if_ne                   jmp     #:synctooth19
    if_e                    mov     timeStamp, cnt                            
    
    
  • jmgjmg Posts: 15,173
    edited 2012-05-14 14:16
    turbosupra wrote: »

    The cog A transmits 72 times before it repeats itself
    The cog B transmits 3 times before it repeats itself

    I would like for the cog B to transmit its 1st frequency when the cog A transmits its 19th frequency and based on timing the cog B should then transmit its 3rd frequency when the cog A transmits its 55th frequency. (rising edges aligned)

    Do these Generators have the same frame-rates ?
    From the above, it reads like B spins at 1/24 the NewFreq rate of A ? - but the 55-19 is 36, which does not quite match a fixed-ratio ?

    If the master can calculate a known future time (which it should be able to do ?) it can pass that value to the slave, as #2 says, waitcnt reads a common counter across all cogs.
    This would require matched frame rate, as one edge is considered a 'master edge', that other slave edges time relative to.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-14 15:08
    Hi,

    I over simplified the initial explanation as to not turn people away, but the more technical explanation is that cog A puts out 72 frequencies to cog B's 3 frequencies. Technically, at least in the calculations, cog A is oscillating at a hz that is twice that of cog B's hz. But realistically, the way that it works is that:

    cog A puts out 34 square waves and is low for the equivalent of 2 square waves in 80,000,000 clk cycles
    cog B puts out 3 square waves and is low for the equivalent of 1 square wave in 160,000,000 clk cycles

    cog A has a square wave width of X
    cog B has a square wave width of 2x

    So cog A oscillates (36-2) square waves and cog B oscillates a frequency at tooth 19, at tooth 1 and at tooth 19 again before it repeats (the next one would be at 19 since it is silent for an equivalent tooth), because of the 2:1 ratio. So if X is the frequency, cog B is high at tooth#, at tooth#+0.5x and at tooth#+1x and silent at tooth#+1.5x.

    Is that what you mean by frame rate? Am I explaining that well?
  • jmgjmg Posts: 15,173
    edited 2012-05-14 15:47
    turbosupra wrote: »
    cog A puts out 72 frequencies to cog B's 3 frequencies. Technically, at least in the calculations, cog A is oscillating at a hz that is twice that of cog B's hz. But realistically, the way that it works is that:

    cog A puts out 34 square waves and is low for the equivalent of 2 square waves in 80,000,000 clk cycles
    cog B puts out 3 square waves and is low for the equivalent of 1 square wave in 160,000,000 clk cycles

    I think you mean pulses, rather than frequencies ?
    Also, it is easier to move this into the time domain.

    So A has a frame (repetition rate) of 80M clks divided into 36 slots, 34 of which have a pulse SlotA/2 wide ?
    and B has a frame of 160M cycles, divided into 4 slots, 3 of which have a pulse SlotB/2 wide
    Pulse A is then 1111111.1111 clks wide, pulse B is 20000000 Wide.

    There you have one issue, Pulse A does not quite fit, so you may need to do something like this
    Pw=round(80e6/36/2) = 1111111
    80e6-(Pw*34*2) = 4444452 (80e6-(Pw*34*2))/Pw = 4.0000072...
    - ie just over 4 exact half cycles of pause time.

    Once you have same/integer ratio frames, you can lock then to any desired phase. Usually the slower one would be master, and the code for A repeats twice to match the frame rate of B.

    One single COG could generate these numbers, but I guess you have 'other stuff' going on.. ?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-14 18:16
    Hello,

    You are right, pulse is a better word for it and time domain is probably easier to use. I'm glad you are following, this has taken me quite some time to get straightened out.

    To make things more complicated, the rate of slots per 80m clks, will vary in the real world greatly. I used 36 slots per 80m clk cycles as an example for cog A, but realistically it is anywhere between 300 and 6900 slots per 80m clock, with each slot having 45% of the slot as a high and 55% of the slot as a low.

    So if frame A is 300 slots per 80m clk, each of those slots is 45% high/55%low, except for the "-2" portion which is 2 complete slots that are 100% low.

    The object I am working on tonight, will calculate the time difference between pulse 26 and pulse 3 and convert it into degrees.

    This was my biggest challenge, to sync them even when the slots per frame rate was quite variable. I'm sure a very good programmer could manage to squeeze all of this into 1 cog, but that isn't me so I'm still using two : ) . I do have other calculations and reads going on as well.
  • dr hydradr hydra Posts: 212
    edited 2013-02-22 08:59
    @pik33

    In my first tries to write a video driver I used waitpeq to synchronize cogs. First cog displays a picture. Second cog waits for Vsync pin low, then do its work, counting Hsync pins low, also with waitpeq...written by pik33

    Do you have a schematic or program example that shows how the sync cogs waitpeq works? Do you tie the Vsync line to both the VGA display and another propeller line? Is it safe to have the propeller pin send a signal to another propeller pin? I have been working on syncing many COGS and additional propeller chips and the waitpeq looks like a simple solution.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-02-22 11:44
    Usually, the initialization routine for the two cogs calculates a system clock value in the near future and passes that as a parameter to each of the cogs as it starts them. The future time has to take into account the time needed to start up both cogs including any initialization time. The last thing the cogs do is a WAITCNT on the passed value. When they exit the WAITCNT, they're synchronized. The code obviously has to stay in sync from that point onwards depending on what the code does. If necessary, the two cogs can re-sync as needed by using the passed system time value and adding the same value to each cog's copy of the value for use in another WAITCNT.
Sign In or Register to comment.