What is the proper way to handle cnt rollover in PASM
Hello,
Is the first code block the proper way to handle roll over in PASM? I'm having issues (see the second block of code) where every once in a while, when comparing cnt to a value it will freeze upon roll over and will not unfreeze until the cnt value happens to randomly land on a value smaller then what is stored when the entire thing freezes. This can take 10 minutes sometimes. I believe this is the culprit, but since it is so random, it is very hard to reproduce and it is not consistent at all.
Proposed way
Current Way
Is the first code block the proper way to handle roll over in PASM? I'm having issues (see the second block of code) where every once in a while, when comparing cnt to a value it will freeze upon roll over and will not unfreeze until the cnt value happens to randomly land on a value smaller then what is stored when the entire thing freezes. This can take 10 minutes sometimes. I believe this is the culprit, but since it is so random, it is very hard to reproduce and it is not consistent at all.
Proposed way
mov cntT, cnt
sub cntT, timeStamp
cmps cntT, #0 WC, WZ
if_b
Current Way
mov cntT, cnt
cmp timeStamp, cntT WC, WZ
if_ae

Comments
mov cntT, cnt ' First compute relative time sub cntT, timeStamp cmp cntT, futureTime wc ' Then check if within time difference if_c jmp #notYetReachedfutureTime might be a timeout period in system clock cycles. timeStamp is the value of cnt at the start of the time period of interest.One thing I should have mentioned (without posting the entire code) was that timeStamp is set upon initialization, and then when cnt surpasses it and a method/event is accessed, timeStamp is added to after that ... so it acts like a wait command, but it does not stop the entire cog, it wait/skips --> until
So timeStamp acts like a cnt milestone and when it is eclipsed it then becomes a future time, so if I understand your code correctly I believe my code ends up doing the same thing your code block does, do you agree?
If your problem takes 10 minutes to clear that is strange, the counter wraps round in under a minute for 80MHz clock.
That's how I've seen it done IIRC. neg automatically handles the overflows for you because the value wraps.
I'm still having a timing related issue that I'm trying to chase. For some reason this line of code hoses the timing synchronization in my code. It is applied in the second code block, to give a general idea of what I'm doing with the "correctionFactor" variable. Maybe it is possible that it is going too far negative, or the add operation with a negative value causes issues?
mov cntT, cnt sub cntT, timeStampCamAdjust cmps cntT, #0 WC, WZ if_b jmp #readSolenoidPulseWidth cmp highCycles, oneHunFiftyThou WC, WZ if_a sub correctionFactor, cyclesDegOfRot if_a add timeStampCamAdjust, tenthClk cmp lowCycles, oneHunFiftyThou WC, WZ if_a add correctionFactor, cyclesDegOfRot if_a add timeStampCamAdjust, tenthClkphase2 cmp correctionFactor, #0 WZ, WC if_a add timeStamp, correctionFactor ' add the amount of cycles you want the object to pause for to sync with a different tooth mov phaseState, phaseThree jmp #phase3 phase3Here is what I'm seeing on the pst
http://img804.imageshack.us/img804/3378/timingissue1.jpg
http://img13.imageshack.us/img13/9664/timingissue2.jpg
Thanks for looking at this.
Just in case, the code posted prints -7 (hard-wired) for most of the values (especially those circled in your pictures).
Sure, the pictures are from the entire project and not just the object. Each of the sections represents a cog, the top half of the screen are the seven child cogs and the bottom half with the 16 different pst labels are from the main cog, which also handles communication (see picture) . I rotate the 16 main cog psts based on which child cog I am trying to troubleshoot in more detail.
Cog1 and cog2 generate frequencies, cog4 reads cog1, cog5 reads cog2, cog6 reads cnt values from cog4 and cog5, cog7 reads values from cog6 and outputs a frequency based on that at 300hz, that is 25%, 50% or 75% duty cycle.
If it would make it easier, I could email you the whole project, the only hardware needed is a few 100ohm resistors between a few pins.
http://img402.imageshack.us/img402/1034/timingissue3.jpg
Basically, the PASM portion is in a continuous loop, checking COG RAM for a command (write text, draw shape, etc.), and reading the touchscreen controller (FT5206). It is also comparing "cntDisp" with CNT; when CNT is equal or greater than "cntDisp", a constant for one second is added to "cntDisp" (pushing it past CNT), and "tmrDisplay" is incremented. In theory, this should provide an absolute timebase off of CNT. (Once "tmrDisplay" reaches a set number of seconds, the display is turned off.) Even if a task should take several seconds, when the loop resumes, it'll "catch back up." (None of the tasks take more than 50mS, if that.)
BUT...it doesn't work that way. It methodically counts a random (unpredictable) number of seconds perfectly, then suddenly the count hesitates, and abruptly "spins" up a couple dozen seconds...hesitates...and zips out of sight, turning the display off. Sometimes it'll count 40 seconds without a problem; other times, the display blanks out instantly. What in the world is wrong with my code?!
mov tmrDisplay, #0 ' reset the counter mov cntDisp, cnt ' reset the timer base '=============================================================== '=============================================================== '=============================================================== ' Power save and auto monitor off handled here MainLoop 'call #Delay1ms 'miniscule power save (WaitCNT reduces cog power consumption by 7/8 ' mov delaycnt, cnt ' add delaycnt, DELAY_1ms 'CODE CONSTANT, NOT A LITERAL! ' waitcnt delaycnt, #0 mov temp1, par add temp1, #40 wrlong tmrDisplay, temp1 'DEBUG RETURN VALUE FOR PRINTING TMRDISPLAY TO SCREEN FROM SPIN MainLoopNoDelay cmp cntDisp, cnt wc ' C SET if "val1" is LESS than "val2" if_c add cntDisp, DELAY_1000ms 'maintaining absolute time-base to CNT. if_c add tmrDisplay, #1 'tmrDisplay has 1S resolution. ' If the screen is off, keep the display timeout cleared. test bits, #1 wz if_z mov tmrDisplay, #0 'Screen off. Reset the counter ' Has sufficient time passed to shut the screen off? NOTE: Screen will only timeout if it's on (above lines) cmp tmrDisplay, #LCDTimeout wc if_c jmp #mlPSEnd 'Nope, not timed out yet. ' Yes, the display timed out. Turn off the RA8875 backlight and display driver. (Cannot use sleep in I2C mode) mov LCD_Cmd, #$8A mov LCD_Dat, #$00 call #Write_Dir 'P1CR - PWM1 Control Register mov LCD_Cmd, #$01 mov LCD_Dat, #$00 call #Write_Dir 'PWRR - Power Control Register andn bits, #1 'Indicate the LCD is OFF. mlPSEnd '===============================================================I am relatively certain that it is NOT a variable conflict; I do not use "cntDisp" anywhere else, nor do I have any self-modifying code in the main loop. Just for the record, I DID accidentally power this Propeller on 4.6vDC (put my 3.3v regulator in backwards); however, thus far, every time I've questioned this Propeller's sanity, it's been a bug in my code (or in my sanity ;-) ).
Does anyone have any clue what's going on here?
P.S. Just saw it do something else weird: "cntDisp" zipped to 120, then stopped counting altogether. I touched the display (resets "cntDisp"), and it cleared to 0...and sat right there for about 10 seconds. Then suddenly "zipped" past 180 and turned the display off. But pretty much EVERYTHING else is working as expected, so I'm suspecting a bug in my code, not a bad Propeller.
-Phil
My revised code:
mov tmrDisplay, #0 ' reset the counter mov cntDisp, cnt ' reset the timer base '=============================================================== '=============================================================== '=============================================================== ' Power save and auto monitor off handled here MainLoop 'call #Delay1ms 'miniscule power save (WaitCNT reduces cog power consumption by 7/8 'Maintain an absolute cycle-count "ratcheting" timer with CNT. Unless CNT overflows, no matter 'how long a task might take, we will always be able to keep perfect time. MainLoopNoDelay mov temp1, cnt 'because there's no RSB (reverse subtract, with swapped operands) sub temp1, cntDisp 'get an absolute "error difference" cmp temp1, DELAY_1000ms wc if_nc add cntDisp, DELAY_1000ms 'maintain a to-the-cycle "ratcheting" timer if_nc add tmrDisplay, #1 'tmrDisplay has 1S resolution. ' If the screen is off, keep the display timeout cleared. test bits, #1 wz if_z mov tmrDisplay, #0 'Screen off. Reset the counter ' Has sufficient time passed to shut the screen off? NOTE: Screen will only timeout if it's on (above lines) cmp tmrDisplay, #LCDTimeout wc if_c jmp #mlPSEnd 'Nope, not timed out yet. ' Yes, the display timed out. Turn off the RA8875 backlight and display driver. (Cannot use sleep in I2C mode) mov LCD_Cmd, #$8A mov LCD_Dat, #$00 call #Write_Dir 'P1CR - PWM1 Control Register mov LCD_Cmd, #$01 mov LCD_Dat, #$00 call #Write_Dir 'PWRR - Power Control Register andn bits, #1 'Indicate the LCD is OFF. mlPSEnd '===============================================================(This is what forums are for ;-) )