Timer Rotarty Encoder Mode not Counting Properly
- July 1, 2023
- 4 replies
- 7249 views
I am attempting to use a rotary encoder (Bourns PEC11R-4215F-S0024) with an STM32F091 Nucleo board. I would like to have it count a consist number of "counts" for every "click" of the encoder.
Hardware Setup: Pin A is connected to PA0, Pin B is connected to PA1 and Pin C (common) is connected to the ground on the nucleo board. This is all done with jumper wires.
CubeMX setup: Clock Tree set to have a max frequency of 48MHz using the internal clock. PA1 and PA2 are set to have Pull-Up Resistors, TIM2 is set to Combined Channels = Encoder Mode. All the TIM2 parameters are left at default except for Encoder Mode = Encoder Mode TI1 and TI2, Polarity of both are set to Falling Edge. I have also activated the TIM2 global interrupt.


I generated the code and added to it so that I could turn the encoder and it would copy the CNT register to a counter variable within a CaptureCallback function. I have attached my main.c file.
I would expect this to add 4 (or subtract 4 depending on the direction I turn the encoder) to the CNT register and then each time the CNT register changes it should trigger the CaptureCallback function to copy that value to the counter variable. This is not what I get though. the CNT register updates properly and it does trigger the CaptureCallback function but the counter variable rarely updates correctly. Often counter will get a completely different value than what is in the register, instead of incrementing by 4 it might increment by 2 or 10 or some other number. the CNT register is always correct, but counter variable is not.
I have checked with a logic analyzer and the encoder is clean, no glitches or anything like that on the transitions and the A and B signals are out of phase with each other as they should be. One thing I have noticed is that while the CNT register is updating properly it appears that the CaptureCallback function is called multiple times each time the CNT register updates. I've also found that if I set a breakpoint in the CaptureCallback function it will pause until I tell it to run again and then it will enter the proper value into the counter variable...every time.
Viewing the TIM2 Peripheral in Keil while I turn the encoder I see that the CNT register is accuratly increaseing/decreasing by 4 on each click, the CCR1 Register does not perfectly follow the CNT register...sometimes it does, sometimes it doesn't. Also, the value of my variable "counter" that is being set inside the capture callback function is not following the CNT register like it should be.
During testing one thing I have noticed is that the CaptureCallback function is being entered considerably more often than it the CNT value is changing. For instance, the value of CNT may increase by 4 but the CaptureCallback function is entered 5 times over when it should be entered once. My understanding is that this CaptureCallback function should only be entered once when the CNT value changes, is this not the case? I have found that if i set a breakpoint inside the CaptureCallback function and then manually run the program again after it breaks it works perfectly every time. Do I need a delay within the CaptureCallback function to make this work right?
I suspect what is happening is that the CaptureCallback function is executing too fast for the register to update properly. Can this be slowed down just enough for the register to be finished updating before the CaptureCallback function is executed?
I also noticed that the CNT register and the CCR1 register increases/decreases do not always match. Shouldn't these match? If not, could this be why I'm not getting the right value in counter?
