Is non contiguous possible on the Rotary Object?
In the rotary object, I have pins 21 and 22 on an encoder. I need to connect a second encoder. 23 and onwards are doing other things and can't be modified. 0/1, 15/16, 13/14 pairs are open for the second encoder. There are no more cogs. Does anyone have an opinion on the PASM as to whether the pins could be hard coded in PASM to reflect noncontiquous inputs? IE Encoder 1 = 21/22 Encoder 2 =0/1. No delta support required.
PUB Start(StartPin, NumEnc, NumDelta, PosAddr, direction): Pass
''Record configuration, clear all encoder positions and launch a continuous encoder-reading cog.
''PARAMETERS: StartPin = (0..63) 1st pin of encoder 1. 2nd pin of encoder 1 is StartPin+1.
'' Additional pins for other encoders are contiguous starting with StartPin+2 but MUST NOT cross port boundry (31).
'' NumEnc = Number of encoders (1..16) to monitor.
'' NumDelta = Number of encoders (0..16) needing delta value support (can be less than NumEnc).
'' PosAddr = Address of a buffer of longs where each encoder's position (and deta position, if any) is to be stored.
''RETURNS: True if successful, False otherwise.
Pin := StartPin
TotEnc := NumEnc
TotDelta := NumDelta
Pos := PosAddr
Stop
SetDir(direction)
longfill(Pos, 0, TotEnc+TotDelta)
Pass := (Cog := cognew(@Update, Pos) + 1) > 0
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
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
' add or substraction the count to the accumulator
: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

Comments
Each pair of pins need to be together but the pairs can be on any set you wish.
Here's the output of the demo program.
The speed is no particular units. I'm working on improving the speed section to work better at low speeds. (I don't know if you even need speed feedback.)
The encoder code is based on JonnyMac's SpinZone article Spinning It Up with Encoders (or something like that).
The encoder object receives the pin settings as a pointer.
As you can see there are a total of three address passed to the encoder object.
The pins are set as constants.
But these constants need to be placed in an array so they can be passed to the child object.
I'm pretty sure the object I posted doesn't include a provision to turn off a channel. Since it just reads the pin as an input it won't interfere with other parts of your code. You can just set extra channels to the previous channels' pins.
Edit: Both the objects in post #2 of the above linked thread are encoders only.
Use @EncPins as the parameter in start(). You can use -1 in the 2nd and 3rd pin sets, the first (encoder 0) must be defined.
I hope this helps.
PUB SetDir(direction) 'Lines that use SUBS -56 -41 -22 'Lines that use ADDS -60 -37 -18 ' ADDS = 110100 'SUBS = 110101 if direction == 1 MAX_NEG[-56] |= |< 26 'ADDS set bit 26 low for adds reversed MAX_NEG[-41] |= |< 26 'ADDS set bit 26 low for adds MAX_NEG[-22] |= |< 26 'ADDS set bit 26 low for adds MAX_NEG[-60] &= !|< 26 'SUBS set bit 26 high for SUBS MAX_NEG[-37] &= !|< 26 'SUBS set bit 26 high for SUBS MAX_NEG[-18] &= !|< 26 'SUBS set bit 26 high for SUBS elseif direction == 0 MAX_NEG[-56] &= !|< 26 'SUBS set bit 26 high for SUBS normal counting MAX_NEG[-41] &= !|< 26 'SUBS set bit 26 high for SUBS MAX_NEG[-22] &= !|< 26 'SUBS set bit 26 high for SUBS MAX_NEG[-60] |= |< 26 'ADDS set bit 26 low for adds MAX_NEG[-37] |= |< 26 'ADDS set bit 26 low for adds MAX_NEG[-18] |= |< 26 'ADDS set bit 26 low for addsThis should toggle bit 26 and swap ADDS and SUBS. I was hoping someone could confirm that this is correct thinking.
Below you can see the PASM with the numbers including for counting back from the first declared long in DAT, leaving out some info that is not needed here:
dat org 0 tri_encoders mov r1, par ' start of structure rdlong r2, r1 ' get enc0a pin mov e0amask, #1 ' create pin mask shl e0amask, r2 add r1, #4 rdlong r2, r1 ' get enc0b pin mov e0bmask, #1 shl e0bmask, r2 add r1, #4 rdlong r2, r1 ' get enc1a pin cmps r2, #0 wc, wz ' used? (< 0 = no) if_b mov e1amask, #0 if_ae mov e1amask, #1 if_ae shl e1amask, r2 add r1, #4 rdlong r2, r1 ' get enc1b pin cmps r2, #0 wc, wz if_b mov e1bmask, #0 if_ae mov e1bmask, #1 if_ae shl e1bmask, r2 add r1, #4 rdlong r2, r1 ' get enc2a pin cmps r2, #0 wc, wz ' used? (< 0 = no) if_b mov e2amask, #0 if_ae mov e2amask, #1 if_ae shl e2amask, r2 add r1, #4 rdlong r2, r1 ' get enc2b pin cmps r2, #0 wc, wz ' used? (< 0 = no) if_b mov e2bmask, #0 if_ae mov e2bmask, #1 if_ae shl e2bmask, r2 add r1, #4 ' read enc0cnt in VAR mov enc0hub, r1 ' save hub addr for results mov enc1hub, enc0hub add enc1hub, #4 ' read enc1cnt in VAR mov enc2hub, enc1hub add enc2hub, #4 ' read enc2cnt in VAR call #sample ' read starting inputs mov oldscan, newscan ' save encmain call #sample ' get sample test newscan, oldscan wz ' compare to last if_e jmp #encmain ' wait for change check0 mov r1, newscan ' copy new scan xor r1, oldscan ' compare with old and r1, #%00_00_11 wz ' isolate encoder0 if_z jmp #check1 ' skip if no change rdlong r2, enc0hub ' get current encoder value mov r1, newscan shl r1, #1 xor r1, oldscan test r1, #%00_00_10 wc ' check direction if_c jmp #dec0 inc0 cmps r2, MAX_POS wz ' at max? if_e jmp #check1 ' yes, skip update adds r2, #1 '-60 jmp #update0 dec0 cmps r2, MAX_NEG wz ' at min? if_e jmp #check1 subs r2, #1 '-56 update0 wrlong r2, enc0hub ' write updated value to hub check1 tjz e1amask, #check2 ' skip if not defined mov r1, newscan xor r1, oldscan and r1, #%00_11_00 wz ' isolate encoder1 if_z jmp #check2 rdlong r2, enc1hub mov r1, newscan shl r1, #1 xor r1, oldscan test r1, #%00_10_00 wc if_c jmp #dec1 inc1 cmps r2, MAX_POS wz if_e jmp #check2 adds r2, #1 '-41 jmp #update2 dec1 cmps r2, MAX_NEG wz if_e jmp #check2 subs r2, #1 '-37 update1 wrlong r2, enc1hub check2 tjz e2amask, #0 ' skip if not defined mov r1, newscan xor r1, oldscan and r1, #%11_00_00 wz ' isolate encoder2 if_z jmp #done rdlong r2, enc2hub mov r1, newscan shl r1, #1 xor r1, oldscan test r1, #%10_00_00 wc if_c jmp #dec2 inc2 cmps r2, MAX_POS wz if_e jmp #done adds r2, #1 '-22 jmp #update2 dec2 cmps r2, MAX_NEG wz if_e jmp #done subs r2, #1 '-18 update2 wrlong r2, enc2hub done mov oldscan, newscan jmp #encmain ' sample encoder pins ' -- updates 'now' as: e3b_e3a_e2b_e2a_e1b_e1a sample mov rawpins, ina ' snapshot of inputs test rawpins, e0amask wc ' get enc1 bits muxc newscan, #%00_00_01 test rawpins, e0bmask wc muxc newscan, #%00_00_10 test rawpins, e1amask wc ' get enc2 bits muxc newscan, #%00_01_00 test rawpins, e1bmask wc muxc newscan, #%00_10_00 test rawpins, e2amask wc ' get enc3 bits muxc newscan, #%01_00_00 test rawpins, e2bmask wc muxc newscan, #%10_00_00 sample_ret ret ' ---------------------------------------------------------------------------------------- MAX_NEG long negx ' start counting backwards here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< MAX_POS long posx