Skip to main content
Ariel G
Associate II
April 3, 2018
Question

Encoder mode and rotary encoder

  • April 3, 2018
  • 6 replies
  • 6513 views
Posted on April 03, 2018 at 11:10

Hi,

I'm using STM32F072RB and a rotary encoder (with 30 dentet) connected to TIM2 in 'encoder mode' and I can see in TIM2->CNT that it is actually counting correctly.

I trying to get an interrupt on each detent rotation but unsuccessfully

To start the encoder in interrupt mode in the main function I'm using:

HAL_TIM_Encoder_Start_IT(&htim2, TIM_ENCODERMODE_TI2);

And the callback:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

if(htim->Instance == TIM2)

counterISR++;

}

but the counterISR is not equal to TIM2->CNT.

How to get an interrupt of each detent rotation? or what is the correct way to implement such thing?

Timer 2 init:

/* TIM2 init function */

static void MX_TIM2_Init(void)

{

TIM_Encoder_InitTypeDef sConfig;

TIM_MasterConfigTypeDef sMasterConfig;

htim2.Instance = TIM2;

htim2.Init.Prescaler = 0;

htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

htim2.Init.Period = 29;

htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

sConfig.EncoderMode = TIM_ENCODERMODE_TI2;

sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;

sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;

sConfig.IC1Prescaler = TIM_ICPSC_DIV1;

sConfig.IC1Filter = 0x0F;

sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;

sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;

sConfig.IC2Prescaler = TIM_ICPSC_DIV1;

sConfig.IC2Filter = 0x0F;

if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}

}

Note: this post was migrated and contained many threaded conversations, some content may be missing.
    This topic has been closed for replies.

    6 replies

    waclawek.jan
    Super User
    April 3, 2018
    Posted on April 03, 2018 at 16:43

    The encoder may be bouncing at the pulses boundaries and the filter you set may be insufficient. Try hardware filtering.

    Nevertheless, in principle, the encoder when stopped, may oscillate on one of its inputs, that will cause mutliple interrupts, but the counter will correctly stay at one of two succeeding values.

    JW

    Ariel G
    Ariel GAuthor
    Associate II
    April 4, 2018
    Posted on April 04, 2018 at 08:59

    Thank you I'll check that out

    T J
    Senior III
    April 3, 2018
    Posted on April 04, 2018 at 01:15

    Are you using Dials or Knobs ?

    Some of us like Dials...

    Tesla DeLorean
    Guru
    April 4, 2018
    Posted on April 04, 2018 at 03:19

    Mine go to 11

    0690X00000604JNQAY.jpg
    Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
    Julien FAUCHER
    Associate III
    April 4, 2018
    Posted on April 04, 2018 at 10:26

    If i remember correctly, you just have to setup an interrupt on the Update event on your timer and then handle it like you would do for any interrupt.

    I'm not familiar (at all) with HAL, but this is the event you should look for. (It's triggered on each timer value update)

    EDIT : Also, could you tell us the ratio between 'counterISR' and TIM2->CNT ? 

    Ariel G
    Ariel GAuthor
    Associate II
    April 4, 2018
    Posted on April 04, 2018 at 10:39

    you mean to set an interrupt on timer overflow?

    The ratio between counterISR and TIM2->CNT  is not constant, counterISR can move by 1/2/3 while TIM2->CNT move by 1 (constantly) on each step rotation

    Julien FAUCHER
    Associate III
    April 4, 2018
    Posted on April 04, 2018 at 11:09

    Ariel G wrote:

    you mean to set an interrupt on timer overflow?

    No, I mean on timerupdate that is, each time its value (TIMx->CNT) changes.

    Also, be aware that the timer will count both upwardand backward following the rotation direction of your encoder.

    You may try to check if you are updating your value only when the encoder is rotating 'upward' with a code like the following :

    unsigned int previousValue = 0;
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
     if(htim->Instance == TIM2)
     {
     if(previousValue < TIM2->CNT || TIM2->CNT == 0)
     {
     counterISR++;
     previousValue = TIM2->CNT;
     }
     }
    }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

    This is a very basicway of handling the issue but it should provide a better result if you rotate the encoder in only one direction, not too fast, etc...

    Please note that you have to handle the case when there is an overflow (the best way is to also trigger an interrupt on overflow interrupt)

    I'm assuming that your

    HAL_TIM_IC_CaptureCallback

    function is called on the right interrupt (which may not be the case).

    Finally, if I remember correctly, you can set the capture to trigger on falling, rising or even all edges from one or both of your signals. If you got a x2 or x4 ratio, you should look into that.

    Jeff Tenney
    Senior
    July 31, 2018

    How to get an interrupt of each detent rotation? or what is the correct way to implement such thing?

    I'm looking at the same question right now.

    Unfortunately, the timers don't seem to offer an interrupt on the "count" event (CK_CNT). That would have been very helpful for rotary encoders with detents.

    So I'm using CCR3 and CCR4 in compare mode, where CCR3 is set to CNT-1 and CCR4 is set to CNT+1. That way, if CNT changes, you get an interrupt.

    I also thought about capturing "both" rising and falling edges into CCR1 and/or CCR2, but the reference manual specifically says not to set CC1NP / CC2NP, which is required to capture both edges.

    Jeff

    Tesla DeLorean
    Guru
    July 31, 2018

    Perhaps you could use an EXTI off the input?

    Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
    Jeff Tenney
    Senior
    July 31, 2018

    Hi Clive - Yes that would work but in my case the timer is also providing filtering (debounce).