0 -> 1 -> 2 -> 3 -> 0 -> 1 -> 2 -> 3... is counting up. Formally: newstate - oldstate == 1.
0 -> 3 -> 2 -> 1 -> 0 -> ... is counting down. Formally: newstate - oldstate == 3.
0 -> 2 is ambiguous. Carry on the "same direction as the last time". Formally: newstate - oldstate == 2.
0 -> 0 is standing still, no movement. newstate - oldstate == 0
-------
Except of course: 0, 1, 2, 3 are gray coded, not normal binary coded.
* 0 == 00
* 1 == 01
* 2 == 11
* 3 == 10
Anyway, convert the 00 / 01 / 11 / 10 raw hardware bit-stream into the above numbers (0, 1, 2, 3). Then it becomes VERY easy.
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.
Ex: 00 -> 10 -> 00 is interpreted as 0 -> 3 -> 0, or -1 transition then a +1 transition.
01 -> 11 -> 01 is interpreted as 1 -> 2 -> 1, or +1 followed by a -1 transition.
All possible combinations of bounces (00 -> 01 -> 00, 00 -> 10 -> 00, 01 -> 11 -> 01, 01 -> 00 -> 01, etc. etc.) have this +1 / -1 or -1/+1 property.
Example for the ESP32: https://github.com/espressif/esp-idf/tree/73db142/examples/p...
I would not be surprised if you don't need PIO for this on this chip.
https://twitter.com/ZodiusInfuser/status/1357067388928335873