cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 - rotary encoder TIM - INT generation

nicola
Associate
Posted on April 07, 2014 at 12:39

Hi.

I successfully configured my STM32F103VC custom HW to use a rotary encoder by following the code suggested in this forum. So first of all: thank you! When I wrote ''successfully'' I mean that the counter gets updated for every encoder rotation.

//GPIO & other init code intentionally omitted...
TIM_TimeBaseStructure.TIM_Prescaler = 0; // No prescaling
TIM_TimeBaseStructure.TIM_Period = 32;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned3;
TIM_TimeBaseInit(ENCODER_TIM, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(ENCODER_TIM, TIM_EncoderMode_TI1,TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);

In my application the encoder is used as input device for the human interface, so I must intercept every action on the knob in order to update the UI. QUESTION: Is there a way to generate an interrupt for every increment/decrement of the timer by the encoder?

RM0008 - REV14 - section 3.2 states:

Center-aligned mode is active when the CMS bits in TIMx_CR1 register are not equal to '00'. The Output compare interrupt flag of channels configured in output is set when: the counter counts down (Center aligned mode 1, CMS = ''01''), the counter counts up (Center aligned mode 2, CMS = ''10'') the counter counts up and down (Center aligned mode 3, CMS = ''11''). So it would seem that the Output Compare feature is doing the job, but it is evidently not working as the INT triggers only on CNT=CCR1 (or CNT>CCR1) matches. I imagine that I rather need an Input Capture feature for this (note also that the CC1S[1:0] are set to 01 - so Input Capture) by the TIM_EncoderInterfaceConfig call even if apparently that is NOT necessary to drive the timer slave controller). I tried then to set the IC1 prescaler to /2 and I tried to latch the CNT value: I get almost every time an overcapture flag rather that it INT flag. I suspect that feeding the CNT and latching the capture compare basically with the same signal is not working properly (latencies?). Do you experts have any idea? Thank you in advance for your help. PS: As the code shows I'm not using the prescaler yet so the counter counts twice for each notch as, when setting it != 0 the counter gets crazy - even using the input filter [maybe the latter is not configured properly...]
5 REPLIES 5
Posted on April 07, 2014 at 20:12

What human interface device would conceivably care about reporting events occurring at 100 Hz, or 1000 Hz?

If you have to account for EACH and every change, consider using an EXTI, otherwise consider a 10 Hz task (or whatever is convenient) and track if the counter has changed from the last inspection.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
nicola
Associate
Posted on April 07, 2014 at 21:16

Thank you for your reply, clive1.

Why 100 or 1000 Hz?

I would expect rather to receive a event every now and then, just when the user turn it.

(Imagine the control knob of a not-touch screen radio car or a satellite navigator).

Anyway the suggestion to use an EXTI is very likely the best one.

I wanted to try this timer feature but looks like is not the best approach.

Posted on April 07, 2014 at 23:30

I was just trying to gauge some scale, because beyond a certain point individual increment messages get to be pointless. For instance a mouse devices typically give you a distance since last report (think 100 or 300 dpi, or gaming mice 5000 dpi), and track ball type devices can generate pulses at incredibly high rates. Hardware decoding using a TIM saves you from losing counts, and you can integrate over a longer observation period, which you'd want to be longer than the minimum report packet delivery time.

Doing it with a regular SysTick also means the system behaves in a predictable way, regardless if someone does something stupid with the knob input, or it malfunctions in some fashion.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
tuan
Associate II
Posted on June 17, 2014 at 07:02

Hi, zandona

Can you post your code about GPIO configuration?

I'm stuck with encoder interface. 

Below are my GPIO configuration:

      GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;

//GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

  //GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

if this is wrong, please revise for me.

Thanks 

gallso
Associate
Posted on September 24, 2016 at 11:56

Yes, I have had success with an interrupt from the CLK line of the encoder. Put a 0.22uF capacitor (or similar) on this line to ground. Set the external interrupt to be on the falling edge.

There is a lot of noise on the CLK and DT lines, so I did some simple filtering in my callback routine.

See code below for a simple scenario...

volatile uint16_t Forward_Count;

volatile uint16_t Reverse_Count;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){

    // Need a 0.22uF capacitor on the CLK of the encoder for this interrupt line only.

    

    // Interrupt is on falling edge of CLK pin.

    // For switch, take 3.3V through 10K resistor to switch contact

    // Use PA0 for interrupt & PA1

    GPIO_PinState state;

    uint8_t i;

    uint8_t Temp_Forward_Count=0;

    uint8_t Temp_Reverse_Count=0;

    if(GPIO_Pin == ENCODER_INT_Pin)        // CLK pin

    {

           for (i=0; i<10; i++){

               state=HAL_GPIO_ReadPin(ENCODER_DIR_GPIO_Port, ENCODER_DIR_Pin);            // DT pin

               if ( state == GPIO_PIN_RESET){

                   Temp_Forward_Count++;

               }

               else {

                   Temp_Reverse_Count++;

                }

           }

           if (Temp_Forward_Count>Temp_Reverse_Count){

            Forward_Count++;

           }

           else {

            Reverse_Count++;

           }

    }

    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

}