How can you sync two cogs/frequencies?
turbosupra
Posts: 1,088
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.
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
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.
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?
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.
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.
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?
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.. ?
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.
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.