Rotary encoder turn detection
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-21 5:57 AM
Hello!
I want to use a simple rotary encoder with STM32F429.
I programmed the TIM4 timer into 'ENCODERMODE_X4' mode.
Is there a way for me to detect the rotation of the rotary knob by interrupt?
I don't want to do periodically TIMx->CNT sampling if there is more elegant method.
Thanks!
- Labels:
-
STM32F4 Series
-
TIM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-21 6:25 AM
We use a external line interrupt configuration(on our STM32F301) on the input pins attached to the encoders pulse outputs.
Here is the setup for one of the two encoders pulse outputs(our encoder input is coming in GPIO_PC14):
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource14);
// Configure EXTI line
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
Once set up and the interrupts are enabled, you will get an EXTI15_10_IRQHandler interrupt on every falling edge of the encoder input as the user turns the encoder.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-22 12:44 AM
Thanks for the help!
In the meantime, I tried the following:
I enabled CC interrupt on TIM4 Channel1. When an interrupt occurs due to a rising edge on TI1, I read the TIM4-> CNT register in the interrupt handler.
It is working, however I have two concerns with this workaround:
- The interrupt is occurs not due to a change in CNT but to a change in one of the encoder phases
- Because of the former, the interrupt occurs just at the beginning or middle of a counting phase. This also depends on the direction of rotation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-22 5:12 AM
I remember we played around a bit before we decided on this solution. Our interrupt is triggered off encoder A and when we get the interrupt we sample the encoder B level. If the encoder B level is high during encoder A interrupt, the encoder is turning one way. If encoder B is low, it is turning the other.
Here is a sloppy example:
void EXTI15_10_IRQHandler(void)
{
volatile uint32_t encoderB;
//encoderA = GPIO_ReadInputDataBit(GPIOC, ENCODER_A);
encoderB = GPIO_ReadInputDataBit(GPIOC, ENCODER_B);
if((EXTI->IMR & EXTI_IMR_MR14) && (EXTI->PR & EXTI_PR_PR14))
{
if (encoderB)
{
tempSetPoint++;
if(tempSetPoint > flashData.setHigh)
tempSetPoint = flashData.setHigh;
}
else
{
tempSetPoint--;
if(tempSetPoint < flashData.setLow)
tempSetPoint = flashData.setLow;
}
encHead++;
encHead &= (NUM_ENCODER_SAMPLES-1);
// Clear the interrupt flag
EXTI->PR = EXTI_PR_PR14;
}
else if(EXTI->PR & EXTI_PR_PR14)
{
// Clear the interrupt flag
EXTI->PR = EXTI_PR_PR14;
}
}
Hope this helps.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-24 1:52 AM
Thanks a lot!
I was a little busy, but now I managed to deal with the topic a bit.
