Forum Update - Announcement about May 10th, 2018 update and your password.

What is the proper way to handle cnt rollover in PASM

turbosupraturbosupra Posts: 1,088
edited May 2012 in Propeller 1 Vote Up0Vote Down
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
                        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

  • 15 Comments sorted by Date Added Votes
  • Mike GreenMike Green Posts: 22,712
    edited May 2012 Vote Up0Vote Down
    Neither technique will work. You want:
                        mov     cntT, cnt                     ' First compute relative time
                        sub     cntT, timeStamp
                        cmp     cntT, futureTime     wc ' Then check if within time difference
         if_c           jmp     #notYetReached
    
    futureTime might be a timeout period in system clock cycles. timeStamp is the value of cnt at the start of the time period of interest.
  • turbosupraturbosupra Posts: 1,088
    edited May 2012 Vote Up0Vote Down
    Hi Mike,

    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?


    Mike Green wrote: »
    Neither technique will work. You want:
                        mov     cntT, cnt                     ' First compute relative time
                        sub     cntT, timeStamp
                        cmp     cntT, futureTime     wc ' Then check if within time difference
         if_c           jmp     #notYetReached
    
    futureTime might be a timeout period in system clock cycles. timeStamp is the value of cnt at the start of the time period of interest.
  • Dave HeinDave Hein Posts: 5,453
    edited May 2012 Vote Up0Vote Down
    turbo, your proposed code should work fine.
  • turbosupraturbosupra Posts: 1,088
    edited May 2012 Vote Up0Vote Down
    Thanks! Since this lockup is so random, it's very hard to test and I appreciate having the response of more season forum members so that I'm not continually chasing my tail.
  • Mark_TMark_T Posts: 1,662
    edited May 2012 Vote Up0Vote Down
    If there's a reason you can't use waitcnt, then the subtract and signed comparison to zero is one correct approach. With wrapping timestamps you must always compute timestamp differences before looking at any of the bits. A >= B is definitely not the same as A-B >= 0 in modulo 2^32 arithmetic, for instance if A == $7FFFFFFF then the first comparison is trivially always true for signed comparison.

    If your problem takes 10 minutes to clear that is strange, the counter wraps round in under a minute for 80MHz clock.
  • pedwardpedward Posts: 1,467
    edited May 2012 Vote Up0Vote Down
    Another way of dealing with timestamps is the NEG instruction. If you look around, you might find some examples.
    mov _count, _delay
    neg _count, cnt
    waitcnt _count, cnt
    

    That's how I've seen it done IIRC. neg automatically handles the overflows for you because the value wraps.
  • kuronekokuroneko Posts: 3,623
    edited May 2012 Vote Up0Vote Down
    pedward wrote: »
    mov _count, _delay
    neg _count, cnt
    waitcnt _count, cnt
    
    What does this do? Or rather what is it supposed to do?
  • turbosupraturbosupra Posts: 1,088
    edited May 2012 Vote Up0Vote Down
    How does one troubleshoot an issue like this?

    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, tenthClk                                                
    
    
    phase2
                           
                            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
    
    phase3
    
  • kuronekokuroneko Posts: 3,623
    edited May 2012 Vote Up0Vote Down
    You removed the code from the other thread so I can't check. Can correctionFactor become negative? Because in phase2 you do an unsigned compare against 0 the result of which is always above (if_a) unless correctionFactor is zero. IOW you may end up adding huge (unsigned) numbers to timeStamp.
  • turbosupraturbosupra Posts: 1,088
    edited May 2012 Vote Up0Vote Down
    I tried doing cmps, but I must have instituted it incorrectly because the problem still existed in the attached code. I think that is what is happening but I'm not sure how to troubleshoot this unless I used the cmps incorrectly?

    Here 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.
  • kuronekokuroneko Posts: 3,623
    edited May 2012 Vote Up0Vote Down
    Can you describe the pictures? I mean are both wrong or only one of them, what exactly are you expecting to see ...

    Just in case, the code posted prints -7 (hard-wired) for most of the values (especially those circled in your pictures).
  • turbosupraturbosupra Posts: 1,088
    edited May 2012 Vote Up0Vote Down
    Good morning,

    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
  • xgaProp8xgaProp8 Posts: 13
    edited March 2 Vote Up0Vote Down
    Sorry to revive an old thread, but it seems to be the closest to my issue. I am working on making a PASM/SPIN controller for the ER-TFTM070-5 capacitive touchscreen LCD from BuyDisplay.com (nice display, works great!) So far so good; I'm having good success on pretty much all counts, EXCEPT for the display timeout!

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,897
    edited March 2 Vote Up0Vote Down
    Don't compare with CNT. Subtract CNT from cntDisp, and compare the result with your time increment. Otherwise roll-over is gonna mess with your comparison.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Took me a few minutes to figure out what you meant...but the results speak for themselves. It works PERFECTLY--thank you very much! Basically, I needed to subtract from CNT to get an offset (this won't have problems with rollover), and compare the offset to my "time constant." If the Propeller had an RSB (reverse subtract) instruction, I'd have been able to save one line of code ;-)

    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 ;-) )
Sign In or Register to comment.