Question on Rotary obj
In special cases I need to reverse the input pins on the rotary encoder object to get it to count in reverse. Currently I just flip A and B at the encoder, but this is sometimes not easy to access. I want to create an option to do this so that the object can be launched with the pins in either configuration ie:
PUB Start(StartPin, PinB, NumEnc, NumDelta, PosAddr)
Looking at the object trying to see where to make changes, something doesn't make sense. What is inb doing here?
PUB Start(StartPin, PinB, NumEnc, NumDelta, PosAddr)
Looking at the object trying to see where to make changes, something doesn't make sense. What is inb doing here?
:PinSrc mov St2, inb ' Sample encoders (St2 = B2:A2 left shifted by first encoder offset)
VAR
byte Cog 'Cog (ID+1) that is running Update
byte TotDelta 'Number of encoders needing deta value support.
long Pos 'Address of position buffer
PUB Start(StartPin, NumEnc, NumDelta, PosAddr): 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
longfill(Pos, 0, TotEnc+TotDelta)
Pass := (Cog := cognew(@Update, Pos) + 1) > 0
PUB Stop
''Stop the encoder-reading cog, if there is one.
if Cog > 0
cogstop(Cog-1)
PUB ReadDelta(EncID): DeltaPos
''Read delta position (relative position value since last time read) of EncID.
DeltaPos := 0 + -(EncID < TotDelta) * -long[Pos][TotEnc+EncID] + (long[Pos][TotEnc+EncID] := long[Pos][EncID])
'************************************
'* Encoder Reading Assembly Routine *
'************************************
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
: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
orig :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 reverse :IPos sub 0, Diff 'Add to encoder position value wrlong 0, MPosAddr 'Write new position to main memory sub IPosAddr, #1 'Increment encoder position addresses(illustration only, this wont work) PUB GetPrefs 'load presets OBJ if direction == 1 enc : "rotary" if direction == 0 enc : "rotaryreverse"Or C. Store the direction mode in eeprom, then have the PASM actual contain two sets of the same code in DAT with alternate names for each section, one set is using the sub versus add function:
If directionFlag == 1 'find a PASM version of the SPIN example shown :IPos sub 0, Diff else :IPos add 0, DiffIf this is what you are suggesting then I can figure out how to write this in PASM. I am not sure how else you would cause the add or sub lines to act except for a condition right before the summing to choose which one to perform. Except for the option I mentioned earlier which is to copy and paste all the DAT section and rename the pasted parts with an indicator they are the reverse section, only changing the add to sub. Obviously this is wasteful.
if PosAddr < 0 AMask[-8] |= |< 26 ' sub else AMask[-8] &= !|< 26 ' addThe long in cog location AMask-8 is :IPos (local labels are not visible in SPIN). An add differs from a sub insn only in bit 26. So for a negative address (bit 31 set) bit 26 will be set (sub) otherwise reset (add). The Start method will then be called like this: Also, the Stop method needs fixing (cogstop(Cog~ -1)).: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 AMask long $55555555 'A bit maskYou find the "add" by counting backwards in DAT from AMask 8 longs to find the address for the ADD instruction. Then, since the instruction for add is only different from sub by 1 bit, you are using AMask as simply an address to work from to reach the long holding the add instruction. The add instruction is 100000 and the sub instruction is 100001, and these instructions obviously are stored at a bitshift left location of 26, since you are working from that offset.
This is a big help, much appreciated!
On a side note, this exercise really helps visualize how PASM works. I can see more clearly the PASM as linear column or memory addresses of instructions and variables parked in ram at a starting point, where instructions run top to bottom acting on either a real number it is presented with on that line, or an address of a number. When the bottom is reaching, an instruction tells the code where to go to start the repeat over.