Question on Rotary obj
T Chap
Posts: 4,223
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
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 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.
You 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.