So whilst reading my favorite odyssey found here I stumbled onto something I never spotted before. It turns out that the general purpose timers support hardware interfacing with an incremental encoder. This means no more interrupts and no need to increment whatever variable you had. Now all you have to do is get the value from the Count register in the timer. Did I also mention it takes care of figuring out which direction you are turning it? Amazing! Lets talk about it.
Encoder Interface Mode
Verbatim from the reference manual of the STM32F103 page 392 or Section 15.3.12
"Encoder interface mode acts simply as an external clock with direction selection. This
means that the counter just counts continuously between 0 and the auto-reload value in the
TIMx_ARR register (0 to ARR or ARR down to 0 depending on the direction). So the user
must configure TIMx_ARR before starting. In the same way, the capture, compare,
prescaler, trigger output features continue to work as normal."
What this means is that the Count (CNT) in the timer is incremented or decremented depending on which direction you turn the encoder.
Furthermore on page 393 the reference manual gives us some sample settings we can use, which are as follows:
CC1S= ‘01’ (TIMx_CCMR1 register, TI1FP1 mapped on TI1)
CC2S= ‘01’ (TIMx_CCMR2 register, TI2FP2 mapped on TI2)
SMS= ‘011’ (TIMx_SMCR register, both inputs are active on both rising and falling edges)
CEN = 1 (TIMx_CR1 register, Counter is enabled)
Steps 1 - 2 maps channel 1 and 2 as inputs to Timer inputs 1 and 2.
Steps 3 - 4 set up the channels to trigger on rising edge (non-inverted)
Step 5 you can also select if it increments based on one of the signal pulses relation to the other, or both edges of both pulses, this is done via the SMS bits in the SMCR register. I have highlighted the relevant options for those bits below:
Step 6 is to enable the timer. You also still have to setup the timer Auto reload register. This will tell the timer the max number it can count up to. Being a 16 bit register this gives you a max number of 0xFFFF (65535). After that you just enable this timer and read the count from the CNT register and that is all. Check out the video below and read through the code. In the code I have implemented both a regular interrupt driven version versus the Timer Hardware version. Obviously the Timer hardware version is much more efficient and faster because it frees up the CPU from doing calculations, jumping in and out of thread and handler mode, jumping to a handler routine etc.... Here are my connections: