Shop OBEX P1 Docs P2 Docs Learn Events
waitpxx & jmp — Parallax Forums

waitpxx & jmp

average joeaverage joe Posts: 795
edited 2013-07-22 23:48 in Propeller 1
While working on a particular piece of PASM I ran into problems. It took me a while to figure out the cause but it comes down to not being able to jump to a waitpxx.

This is what I started with, does not work :
:loop   waitpeq zero, trigger                           ' wait for trigger pin to be idle         
        waitpne zero, trigger                           ' wait for trigger pin to be active       
...
'do something
...

        jmp   :loop                                     ' repeat                       

This code fails after the first iteration of the loop. Correcting was as simple as adding a nop as such :
:loop   nop 
        waitpeq zero, trigger                           ' wait for trigger pin to be idle         
        waitpne zero, trigger                           ' wait for trigger pin to be active       
...
'do something
...

        jmp   :loop                                     ' repeat                       

Still, I could not find any information in the manual about this. My thought is it comes down to the pipelining? This took me a while to figure out. (and quite a bit of frustration.) Maybe I'm missing something? Any help would be greatly appreciated!

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2013-07-22 20:55
    Use jmp #:loop instead.
  • average joeaverage joe Posts: 795
    edited 2013-07-22 21:08
    Ahh, that fixed it. Thanks!
  • average joeaverage joe Posts: 795
    edited 2013-07-22 21:12
    Now I still have one problem with the code I'm working on. Full code as follows:
    {{
    //        64 bit clock source       //
    //        Author : Joe Heinz        //
    //   Copyright : Joe Heinz - 2013   //
    }}
    
    _ctr1_apin  = 16                                         ' pin to use as output from counter A to counter B
    _sample_pin = 15                                         ' pin to sample both counters phase 
    
    
    VAR
      long long1, long2                                  
         long cog                                           ' byte to store cog running timer in
    PUB TESTf
      start
      repeat
        GetSample
       
    PUB NULL                        '' not a top level object
    
    PUB Start                       '' Start timing cog
      long1 := 0'|< _sample_pin                                  ' move sample pin into longa
      long2 := 0
      outa[_sample_pin] := 0                                ' set samplePin to LOW         
      dira[_sample_pin] := 1                                ' make samplePin an output
      cog := cognew(@entry, @long1) +1                      ' start assembly cog
      result := cog
      
    PUB Stop                        '' Stop timing cog
       if cog                                               ' if cog started
         cogstop(cog ~~ -1)                                 ' stop cog and clear cog variable
    
    PUB GetSample                   '' Get a sample time
      outa[_sample_pin] := 1                                ' make samplePin HIGH
    '  if long1 < $FFFF_FFFC                                 ' if near overflow at sample
    '    long2 -= 1                                          ' subtract 1 from high 32 bits
      outa[_sample_pin] := 0                                ' make samplePin LOW
     
    PUB GetBuffer
       result := @long1                                      ' return address of longa
      
    DAT
            org
    
    entry   mov   dira, diraval                             'set APIN to output
            mov   frqa, #1                                  'set counter to increment 1 each cycle
            mov   frqb, #1                                  'set counter to increment 1 each cycle
    
            mov   wr2add, par                               ' move par address to wr2add
            add   wr2add, #4                                ' add long offset
            mov   ctrb, ctrbmode                            ' establish counter A mode and APIN                        
            mov   ctra, ctramode                            ' establish counter B mode and APIN
                                                                     
    :loop   waitpeq zero, trigger                           ' wait for trigger pin to be idle       
            waitpne zero, trigger                           ' wait for trigger pin to be active       
            mov   long_1, phsa                              ' move phsa to long1                     
            mov   long_2, phsb                              ' move phsb to long2                   
            wrlong  long_1,par                              ' write long1                           
            wrlong  long_2, wr2add                          ' write long2                         
    
            jmp   #:loop                                     ' repeat                                  
                                                        
            
    diraval       long      |< _ctr1_apin  
    ctramode      long      (%00100 << 26) + _ctr1_apin        ' PLL mode - single ended, APIN is input for counter B
    ctrbmode      long      (%01110 << 26) + _ctr1_apin                             ' neg edge triggered, APIN is output from counter A
    zero          long      0
    
    
    trigger       long  |< _sample_pin                                         ' pin to trigger sample
    long_1        res
    long_2        res
    wr2add        res
    

    While working on this I realized that if I take a sample within 4 clock of a wrap, the high 32 bits would increment. I tried using the commented out code, but does not seem to work properly. I'm still trying to figure out the right way to handle this.

    *edit*

    Think I've got it. Easier (and quicker) to do in PASM.
    :loop   waitpeq zero, trigger                           ' wait for trigger pin to be idle         
            waitpne zero, trigger                           ' wait for trigger pin to be active       
            mov   long_1, phsa                              ' move phsa to long1                      
            mov   long_2, phsb                              ' move phsb to long2                      
            cmp   wrap, long_1   wc                         ' if near overflow at sample
    if_c    sub   long_2, #1                                ' subtract 1 from high 32 bits
            wrlong  long_1,par                              ' write long1                            
            wrlong  long_2, wr2add                          ' write long2                             
            jmp   #:loop                                    ' repeat        
    
  • kuronekokuroneko Posts: 3,623
    edited 2013-07-22 21:51
    Think I've got it. Easier (and quicker) to do in PASM.
    :loop   waitpeq zero, trigger                           ' wait for trigger pin to be idle         
            waitpne zero, trigger                           ' wait for trigger pin to be active       
            mov   long_1, phsa                              ' move phsa to long1                      
            mov   long_2, phsb                              ' move phsb to long2                      
            cmp   wrap, long_1   wc                         ' if near overflow at sample
    if_nc   sub   long_2, #1                                ' subtract 1 from high 32 bits
            wrlong  long_1,par                              ' write long1                            
            wrlong  long_2, wr2add                          ' write long2                             
            jmp   #:loop                                    ' repeat        
    
    What's your wrap value? Also note that sampling an external pin may not be as exact as required, e.g. the edge may be detected one cycle late.
  • average joeaverage joe Posts: 795
    edited 2013-07-22 22:12
    For the wrap value, I used
    wrap          long      $FFFF_FFFC
    
    This would be 4 clocks or less from a wrap *overflow from low counter to high counter* If the low counter is greater or equal to wrap at the time of sample, then by the time the high counter is sampled it will have incremented. At least in theory... For my purposes, one cycle is negligible. I'm looking for accuracy to 1/10,000 of a second, or 10 microseconds. 50 nanoseconds is more than acceptable.
  • kuronekokuroneko Posts: 3,623
    edited 2013-07-22 22:38
    Let's deal with external delays first. My point is that even if you could read both registers in parallel and there would be no internal overhead you may end up with a sequence of 0:$FFFFFFFF, 0:0, 1:1, 1:2. I'd argue this is important (to know about).

    Next, internal overhead. Let's assume you read $FFFFFFFC for the low part (high is 0). This means not carry and therefore the high part is not modified. However, the high part is read 4 cycles later (low is 0). During this clock the link output goes low. Another cycle later this low makes it into the A1 counter flipflop. In the next cycle the counter increment logic sees the !A1&A2 condition which finally causes it to increment the high part. This means the change you're hoping to read is two cycles late. That said, you could use a 6 cycle DMZ to adjust for internal delays (my initial implementation) but this wouldn't protect you from external delays. In the end I increased the DMZ and simply re-read both values in case of a wrap collision (see posted example code).

    In propgcc another solution is used. IIRC, high is read first followed by low. Then high is read again, if it has changed the low part is re-read then this value is reported. I'll post a link later if I can find it again.
  • average joeaverage joe Posts: 795
    edited 2013-07-22 23:23
    I'll need to re-read your last post many times to fully understand it. I do see the potential for issues here. I did make an error in my code, the if_nc should be if_c I corrected my code in the post, but not before you started your reply. I do get the jest of your post and think that perhaps the propcgg solution is the way to go. I'll start working on this in a few. Thanks again!

    *edit*
    So I come up with something like this :
    :loop   waitpne zero, trigger                           ' wait for trigger pin to be active       
                                 
            mov   long_2, phsb                              ' move phsb to long2 
            mov   long_1, phsa                              ' move phsa to long1 
            mov   tmp, phsb                                 ' re-read phsb
            cmp   tmp, long_2     wz                        ' compare both samples of phsb
    if_nz   mov   long_1, phsa
    if_nz   mov   long_2, tmp
    
            wrlong  long_1,par                              ' write long1                            
            wrlong  long_2, wr2add                          ' write long2 
            waitpeq zero, trigger                           ' wait for trigger pin to be idle
            jmp   #:loop                                    ' repeat                              
    
    

    Not sure if I can compensate for the small delay, or if it's even necessary at this point.
  • kuronekokuroneko Posts: 3,623
    edited 2013-07-22 23:35
    I did make an error in my code, the if_nc should be if_c I corrected my code in the post, but not before you started your reply.
    Ah, so did I (the comment would only fit an if_c). With nc it's actually worse ...

    Above version slightly shorter.
    mov   long_2, phsb                              ' move phsb to long2 
            mov   long_1, phsa                              ' move phsa to long1 
            cmp   long_2, phsb wz                           ' compare both samples of phsb
    if_nz   mov   long_1, phsa                              ' re-read phsa
    if_nz   add   long_2, frqb                              ' apply increment
    
    What delay are you worried about? The compensation? That's only 12 extra cycles (which you probably already get by waiting for hub windows). You could move the long_2 adjustment between both wrlongs though.
  • average joeaverage joe Posts: 795
    edited 2013-07-22 23:48
    Good point RE hub windows. Thanks for the shorter version. This will work quite well. I think I may be shifting right by 6 in the end to get to 1/10,000 of a second anyway.
Sign In or Register to comment.