Hmmm.
Any I/O is basically compression. So lets think about what we're actually outputting. We're converting a raw bitstream from two GPIO pins paired (Ex: 00, 01, 01, 01, 11, 11, 10, 00, 01, 11), into a singular message: such as +6.
There are two applications of a quadrature encoder that I can think of.
1. Virtual Pot -- Converting the messages into a kind of "-100 to +100 slider", such as a volume control knob. In this case, you want a regular update schedule at human-interface speeds (~1000 updates / second or slower).
2. Rotational Velocity sensor -- Converting the messages into a speed. You're willing to batch the bitstream up as slowly as possible, maybe waiting for a rollover event (+128 or -128). And you just interrupt on those overflows.
-------
Since the input format is already set, we now think about the output format: how to represent +6 and or -12?
Based on the PIO instruction set, it seems like +6 and -12 probably would be easiest as two separate registers in two different state-machines.
Every time an "increment" is detected, the FIFO-associated with +1 gets a +1 bit added to it. Every time a "decrement" is detected, the 2nd FIFO associated with -1 gets a +1 bit added to it.
----
In pseudocode:
IncrementSide(){
currentState = 00; // default
while(1){
nextState = in(GPIO0) | in(GPIO1);
if(currentState == 00 and nextState == 01){
push 1;
}
if(currentState == 01 and nextState == 11){
push 1;
}
if(currentState == 11 and nextState == 10){
push 1;
}
if(currentState == 10 and nextState == 00){
push 1;
}
currentState = nextState;
}
}
"nextState" and "currentState" probably is just the X and Y registers of the PIO state machines. The above is "very pseudocode" as I don't really understand PIO yet.
I'm saying "push 1", but "push 1 into the OSR". It looks like the OSR has some kind of auto-push mechanism, but if that doesn't work then a manual-push might be needed in the code proper. Hard to say from the docs alone.
DecrementSide would be just the inverted if-statements:
if(currentState == 00 and nextState == 11){
push 1; // Decrement side checking for a decrement
}
--------
This above methodology would only work for #2 ("velocity"), and fails for #1 ("positional"), because the increment-side and decrement-side would be updating at varying rates.
I probably can make a positional-decoder instead of a velocity one using similar principles. Or maybe by somehow ensuring that the +1 and -1 messages go into the same FIFO to be picked up by the host CPU.
The idea is route "0" messages to /dev/null, compressing the input stream. The host still sees the important +1 and -1 messages. The exact mechanism for that is up for debate, but the simple if-else state machine above seems to accomplish that to a limited extent.
------
EDIT: Hmmm, maybe a singular FIFO can be done if we have push1 and push0 for the two kinds of messages: 1 representing +1 and 0 representing -1.
Anyway, my point is that there's lots of solutions here. It doesn't seem very difficult to me conceptually. Just a lot of experimentation needed to know exactly how those 9 instructions work and the exact mechanisms of the ISR / OSR / X reg / Y reg.