The SAFEST way to handle quadrature-input decoding is a 'sampled' system, where the two inputs are simultaneously sampled and the 'difference' from a previous sample gives you the necessary counter-update info, like this, where ENC0_PT is defined as the encoder-GPIO port, and ENC0_A (and _B) are the associated bit-masks:
Diff_Enc0 = (ENC0_PT & (ENC0_A | ENC0_B)) ^ Last_Enc0; //Get encoder bit changes-must be atomic!
if( Diff_Enc0 != 0 )
{
if( (~Last_Enc0 & Diff_Enc & ENC0_A) ) //First look for A edges
{
Last_Enc0 ^= Diff_Enc; //Update the 'current' pattern
if( Last_Enc0 & ENC0_B )
Steps0--; //Current 'B' state defines CW or CCW
else
Steps0++; //Increments and decrements must be atomic
}else if( (Last_Enc0 & Diff_Enc & ENC0_A) )
Last_Enc0 ^= Diff_Enc; //Update the 'current' pattern
if( Last_Enc0 & ENC0_B ) //Opposite 'B' decode for CW or CCW
Steps0++;
else
Steps0--;
}else if( (~Last_Enc0 & Diff_Enc & ENC0_B) ) //And now B edges
{
Last_Enc0 ^= Diff_Enc; //Update the 'current' pattern
if( Last_Enc0 & ENC0_A )
Steps0++; //Current 'A' state defines CW or CCW
else
Steps0--;
}else if( (Last_Enc0 & Diff_Enc & ENC0_B) )
{
Last_Enc0 ^= Diff_Enc; //Update the 'current' pattern
if( Last_Enc0 & ENC0_A ) //Opposite 'A' decode for CW or CCW
Steps0--;
else
Steps0++;
}else //Ignore any non-tested changes
Last_Enc0 ^= Diff_Enc; //Update the 'current' pattern, ignoring confused change
}
The 'limitation' of this process is that there MUST be at most one 'useful' (not just bounce) edge-input changing per 'sample' -- otherwise no 'correct' change can be made, and the last 'else' clause kicks-in and just 'skips' the change. The Kinetis FTM1 and/or FTM2 'quadrature mode' run this kind of state machine in hardware using the bus clock for sampling, and is thus capable of edge-rates up to 2/3rds of the bus clock (based on experiments and the datasheet parameter under 'General Switching Specs' called 'GPIO pin interrupt pulse width', and note 1, of 1.5 bus-clock-cycles 'minimum' pulse widths). In software, you will be MUCH more limited in the rate you can stand -- I might see you running this on a 10KHz timer-interrupt, but personally I wouldn't expect to drive an interrupt rate much in excess of that, for a minimum of 100us between 'valid' edge changes. This kind of sampling will ignore 'bounce' on any one input, as just one edge changing 'back and forth' at the sample-times will just increment and decrement the counter each time (and 'bounces' between samples ignored entirely!), and the final 'settled' value will be correct for the total step count. And that is the 'fundamental advantage' over, say, just trying to 'interrupt' on either input-edge and decode THOSE, as the interrupt-turnaround time will define a 'window' where you may LOSE a fast edge change, and thus miscount. This method CANNOT get lost on such bounces of any one edge at a time -- it is just limited in that the valid A/B/A/B/A... interleaved rising/falling edge sequences CANNOT occur faster than the sample-rate.