Shop OBEX P1 Docs P2 Docs Learn Events
Detect movment in an encoder — Parallax Forums

Detect movment in an encoder

LandryLandry Posts: 17
edited 2008-02-28 11:55 in Propeller 1
hey,

I'm using the the Quadrature encoder object made By Jeff martin and would like to set the pin high when the first movement from the encoder is detected (pulse).

I added a comparison in the existing code but it seems like it is not in the right place.

DAT
'Read all encoders and update encoder positions in main memory.
'See "Theory of Operation," below, for operational explanation.
'Cycle Calculation Equation:
'  Terms:     SU = :Sample to :Update.  UTI = :UpdatePos through :IPos.  MMW = Main Memory Write.
'             AMMN = After MMW to :Next.  NU = :Next to :UpdatePos.  SH = Resync to Hub.  NS = :Next to :Sample.
'  Equation:  SU + UTI + MMW + (AMMN + NU + UTI + SH + MMW) * (TotEnc-1) + AMMN + NS
'             = 92 + 16  +  8  + ( 16  + 4  + 16  + 6  +  8 ) * (TotEnc-1) +  16  + 12
'             = 144 + 50*(TotEnc-1)
                        org     0
                                                                                                
Update                  test    Pin, #$20               wc      'Test for upper or lower port
                        muxc    :PinSrc, #%1                    'Adjust :PinSrc instruction for proper port
                        mov     IPosAddr, #IntPos               'Clear all internal encoder position values
                        movd    :IClear, IPosAddr               '  set starting internal pointer
                        mov     Idx, TotEnc                     '  for all encoders...  
        :IClear         mov     0, #0                           '  clear internal memory
                        add     IPosAddr, #1                    '  increment pointer
                        movd    :IClear, IPosAddr               
                        djnz    Idx, #:IClear                   '  loop for each encoder                                                                    
                        mov     St2, ina                        'Take first sample of encoder pins
                        shr     St2, Pin                
:Sample                 mov     IPosAddr, #IntPos               'Reset encoder position buffer addresses
                        movd    :IPos+0, IPosAddr                               
                        movd    :IPos+1, IPosAddr
                        mov     MPosAddr, PAR                           
                        mov     St1, St2                        'Calc 2-bit signed offsets (St1 = B1:A1)
                        mov     T1,  St2                        '                           T1  = B1:A1 
                        shl     T1, #1                          '                           T1  = A1:x 
        :PinSrc         mov     St2, inb                        '  Sample encoders         (St2 = B2:A2 left shifted by first encoder offset)
                        shr     St2, Pin                        '  Adj for first encoder   (St2 = B2:A2)
                        xor     St1, St2                        '          St1  =              B1^B2:A1^A2
                        xor     T1, St2                         '          T1   =              A1^B2:x
                        and     T1, BMask                       '          T1   =              A1^B2:0
                        or      T1, AMask                       '          T1   =              A1^B2:1
                        mov     T2, St1                         '          T2   =              B1^B2:A1^A2
                        and     T2, AMask                       '          T2   =                  0:A1^A2
                        and     St1, BMask                      '          St1  =              B1^B2:0
                        shr     St1, #1                         '          St1  =                  0:B1^B2
                        xor     T2, St1                         '          T2   =                  0:A1^A2^B1^B2
                        mov     St1, T2                         '          St1  =                  0:A1^B2^B1^A2
                        shl     St1, #1                         '          St1  =        A1^B2^B1^A2:0
                        or      St1, T2                         '          St1  =        A1^B2^B1^A2:A1^B2^B1^A2
                        and     St1, T1                         '          St1  =  A1^B2^B1^A2&A1^B2:A1^B2^B1^A2
                        [b][color=purple]mov     $1F6,   #$80  
                     cmp     St1, 0            wz
              if_nz  mov     $1F4,   #$80
[/color][/b]                        mov     Idx, TotEnc                     'For all encoders...
:UpdatePos              ror     St1, #2                         'Rotate current bit pair into 31:30
                        mov     Diff, St1                       'Convert 2-bit signed to 32-bit signed Diff
                        sar     Diff, #30
        :IPos           add     0, Diff                         'Add to encoder position value
                        wrlong  0, MPosAddr                     'Write new position to main memory
                        add     IPosAddr, #1                    'Increment encoder position addresses
                        movd    :IPos+0, IPosAddr
                        movd    :IPos+1, IPosAddr
                        add     MPosAddr, #4                          
:Next                   djnz    Idx, #:UpdatePos                'Loop for each encoder
                        jmp     #:Sample                        'Loop forever
'Define Encoder Reading Cog's constants/variables
AMask                   long    $55555555                       'A bit mask
BMask                   long    $AAAAAAAA                       'B bit mask
MSB                     long    $80000000                       'MSB mask for current bit pair
Pin                     long    0                               'First pin connected to first encoder
TotEnc                  long    0                               'Total number of encoders
Idx                     res     1                               'Encoder index
St1                     res     1                               'Previous state
St2                     res     1                               'Current state
T1                      res     1                               'Temp 1
T2                      res     1                               'Temp 2
Diff                    res     1                               'Difference, ie: -1, 0 or +1
IPosAddr                res     1                               'Address of current encoder position counter (Internal Memory)
MPosAddr                res     1                               'Address of current encoder position counter (Main Memory)
IntPos                  res     16                              'Internal encoder position counter buffer
''
''
''**************************
''* FUNCTIONAL DESCRIPTION *
''**************************
''
''Reads 1 to 16 two-bit gray-code quadrature encoders and provides 32-bit absolute position values for each and optionally provides delta position support
''(value since last read) for up to 16 encoders.  See "Required Cycles and Maximum RPM" below for speed boundary calculations.
''
''Connect each encoder to two contiguous I/O pins (multiple encoders must be connected to a contiguous block of pins).  If delta position support is
''required, those encoders must be at the start of the group, followed by any encoders not requiring delta position support.
''
''To use this object: 
''  1) Create a position buffer (array of longs).  The position buffer MUST contain NumEnc + NumDelta longs.  The first NumEnc longs of the position buffer
''     will always contain read-only, absolute positions for the respective encoders.  The remaining NumDelta longs of the position buffer will be "last
''     absolute read" storage for providing delta position support (if used) and should be ignored (use ReadDelta() method instead).
''  2) Call Start() passing in the starting pin number, number of encoders, number needing delta support and the address of the position buffer.  Start() will
''     configure and start an encoder reader in a separate cog; which runs continuously until Stop is called.
''  3) Read position buffer (first NumEnc values) to obtain an absolute 32-bit position value for each encoder.  Each long (32-bit position counter) within
''     the position buffer is updated automatically by the encoder reader cog.
''  4) For any encoders requiring delta position support, call ReadDelta(); you must have first sized the position buffer and configured Start() appropriately
''     for this feature.
''
''Example Code:
''           
''OBJ
''  Encoder : "Quadrature Encoder"
''
''VAR
''  long Pos[noparse][[/noparse]3]                            'Create buffer for two encoders (plus room for delta position support of 1st encoder)
''
''PUB Init
''  Encoder.Start(8, 2, 1, @Pos)           'Start continuous two-encoder reader (encoders connected to pins 8 - 11)
''
''PUB Main 
''  repeat
''    <read Pos[noparse][[/noparse]0] or Pos[noparse][[/noparse]1] here>         'Read each encoder's absolute position
''    <variable> := Encoder.ReadDelta(0)   'Read 1st encoder's delta position (value since last read)
''
''________________________________
''REQUIRED CYCLES AND MAXIMUM RPM:
''
''Encoder Reading Cog requires 144 + 50*(TotEnc-1) cycles per sample.  That is: 144 for 1 encoder, 194 for 2 encoders, 894 for 16 encoders.
''
''Conservative Maximum RPM of Highest Resolution Encoder = XINFreq * PLLMultiplier / EncReaderCogCycles / 2 / MaxEncPulsesPerRevolution * 60
''
''Example 1: Using a 4 MHz crystal, 8x internal multiplier, 16 encoders where the highest resolution encoders is 1024 pulses per revolution:
''           Max RPM = 4,000,000 * 8 / 894 / 2 / 1024 * 60 = 1,048 RPM
''
''Example 2: Using same example above, but with only 2 encoders of 128 pulses per revolution:
''           Max RPM = 4,000,000 * 8 / 194 / 2 / 128 * 60 = 38,659 RPM
'____________________
'THEORY OF OPERATION:
'Column 1 of the following truth table illustrates 2-bit, gray code quadrature encoder output (encoder pins A and B) and their possible transitions (assuming
'we're sampling fast enough).  A1 is the previous value of pin A, A2 is the current value of pin A, etc.  '->' means 'transition to'.  The four double-step
'transition possibilities are not shown here because we won't ever see them if we're sampling fast enough and, secondly, it is impossible to tell direction
'if a transition is missed anyway.
'
'Column 2 shows each of the 2-bit results of cross XOR'ing the bits in the previous and current values.  Because of the encoder's gray code output, when
'there is an actual transition, A1^B2 (msb of column 2) yields the direction (0 = clockwise, 1 = counter-clockwise).  When A1^B2 is paired with B1^A2, the
'resulting 2-bit value gives more transition detail (00 or 11 if no transition, 01 if clockwise, 10 if counter-clockwise).
'
'Columns 3 and 4 show the results of further XORs and one AND operation.  The result is a convenient set of 2-bit signed values: 0 if no transition, +1 if
'clockwise, and -1 and if counter-clockwise.
'
'This object's Update routine performs the sampling (column 1) and logical operations (colum 3) of up to 16 2-bit pairs in one operation, then adds the 
'resulting offset (-1, 0 or +1) to each position counter, iteratively.
'
'      1      |      2      |          3           |       4        |     5
'-------------|-------------|----------------------|----------------|-----------
'             |             | A1^B2^B1^A2&(A1^B2): |   2-bit sign   |
'B1A1 -> B2A2 | A1^B2:B1^A2 |     A1^B2^B1^A2      | extended value | Diagnosis
'-------------|-------------|----------------------|----------------|-----------
' 00  ->  00  |     00      |          00          |      +0        |    No
' 01  ->  01  |     11      |          00          |      +0        | Movement
' 11  ->  11  |     00      |          00          |      +0        |
' 10  ->  10  |     11      |          00          |      +0        |
'-------------|-------------|----------------------|----------------|-----------
' 00  ->  01  |     01      |          01          |      +1        | Clockwise
' 01  ->  11  |     01      |          01          |      +1        |
' 11  ->  10  |     01      |          01          |      +1        |
' 10  ->  00  |     01      |          01          |      +1        |
'-------------|-------------|----------------------|----------------|-----------
' 00  ->  10  |     10      |          11          |      -1        | Counter-
' 10  ->  11  |     10      |          11          |      -1        | Clockwise
' 11  ->  01  |     10      |          11          |      -1        |
' 01  ->  00  |     10      |          11          |      -1        |

According the truth table I though that the highlighted code is at the right place but unfortunately, might is set to high anyway.

Can anybody help me with this.

Thanks.

Comments

  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-27 20:38
    I believe that your cmp line should use #0 instead of just 0 smile.gif

    Also, you should use the names for DIRA and OUTA. It just makes it easier to read.
  • LandryLandry Posts: 17
    edited 2008-02-27 21:38
    Thanksfor your answer, I will try it at work tomorrow and let you know the result.
  • LandryLandry Posts: 17
    edited 2008-02-28 07:56
    I replaced 0 by #0 but it didn't work. Even though ther is no movement the pin is still set to high. Is the right place wher I have to make the comparison in the code?
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-28 08:18
    I think that its in the right place. What code are you using to start the cog? Its possible that another cog is setting the pin high. Keep the #0 as it is still needed.
  • LandryLandry Posts: 17
    edited 2008-02-28 09:31
    here is the code that i'm running at the moment.
    [color=red]CON
      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000[/color]
    [color=red]  ZERO = 48
      NINE = 57[/color]
    [color=red]  MAX_LENGTH = 400
      DELIMITER = 13[/color]
    [color=red]  PLUS = "+"
      MINUS = "-"
      
      PIN_ENCODER_BOX_A = 3
      PIN_ENCODER_BOX_B = 4
      'PIN_ENCODER_BOX_I = 5
        
      PIN_ENCODER_PP_A = 5
      PIN_ENCODER_PP_B = 6
      'PIN_ENCODER_PP_I = 8[/color]
     
    [color=orange]OBJ
      _Numbers      : "Numbers"
      _Keyboard     : "Keyboard"
      _Encoders     : "Quadrature Encoder"
      '_TV          : "PC_Text"
      _TV           : "VGA_Text"
      _BS2          : "BS2_Functions"[/color]
      
    [color=green]VAR
      byte _dataIn[noparse][[/noparse]4]
      long _position[noparse][[/noparse]2][/color]        
                         
    [color=blue]PUB Main | triggerPosition, invalid, triggerSign[/color]
    [color=blue]  _TV.start(16)
      _TV.str(string("Position calculator...",13))[/color]
    [color=blue]  _BS2.start(31, 30)
      
      _Keyboard.start(26, 27)[/color]
    [color=blue]  'Trigger position chosen by the user
      invalid := true
      _TV.str(string("Trigger position:"))  
      repeat while invalid
        Readinput(@_dataIn, 3)
        triggerPosition := _Numbers.FromStr(@_dataIn, 10)
        _TV.out(13)[/color]
    [color=blue]    if triggerPosition => ZERO and triggerPosition =< MAX_LENGTH
          invalid := false[/color]
    [color=blue]  'Trigger sign chosen by the user         
      invalid := true
      _TV.str(string("Sign:"))
      repeat while invalid
        ReadInput(@_datain, 1)
        _TV.out(13)
        
        if strcomp(_dataIn, PLUS)
          'triggerSign := _dataIn[noparse][[/noparse]0]
          triggerPosition := 1 * triggerPosition
          invalid := false
        if strcomp(_dataIn, MINUS)
          triggerPosition := -1 * triggerPosition
          invalid := false
        
      'Encoder   
        _Encoders.start(PIN_ENCODER_BOX_A, 1, 0, @_position)
        repeat    
          _TV.dec(_position[noparse][[/noparse]0])
          if _position[noparse][[/noparse]0] > 1
            _BS2.PULSOUT_us(PIN_ENCODER_BOX_A, 500) 'send 
            quit
          _TV.out(13)[/color]
     
    [color=purple]PRI ReadInput(inputPtr, length) | value, ptr
      {{
        Accepts a string of characters - up to 3 - to be passed by reference
        String acceptance terminates with a carriage return or the defined delimiter character.
        Will accept up to 3 characters before passing back.
      }}
     
      ptr:=0[/color]
    [color=purple]  bytefill(@_dataIn, 0, length)                                                 
      value := 0
      repeat while (value <> Delimiter) and (ptr < length)
        value := _Keyboard.getkey
        _dataIn[noparse][[/noparse]ptr] := value    
        ptr++
        _TV.out(value)[/color]
    [color=purple]  _dataIn[noparse][[/noparse]ptr]:=0                                         [/color]
    [color=purple]  byteMove(inputPtr, @_dataIn, (length + 1))[/color]
    

    ·I don't think that i'm ussing pin 7 anywhere in here or I'm and didn't know about it.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-28 11:55
    I can't see anywhere where you are using another pin or anything else that would be causing a problem so its over to someone with more experience than me smile.gif The only thing might be that you are passing 0 for the number of differences (3rd argument in start for encoder).
Sign In or Register to comment.