3 ms·
The question was not how quadrature encoding works, but how to implement it with the limited PIO instructions
by MatthiasWandel 6y ago
The question was not how quadrature encoding works, but how to implement it with the limited PIO instructions
- dragontamer 6y agoHmmm. 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.