2
\$\begingroup\$

I am developing mobile robot. Hear i required to read quadrature encoder.So i am using stm32F401 using 16bit timer(encoder mode) to read the count.After 65535 count goes to 0. My question is how to make the counter larger.

Thanks

\$\endgroup\$
1
  • \$\begingroup\$ You can't. However, you can just a predivider, although I have never gotten it to work properly. The less complicated way is to to have an interrupt trigger on rollover that counts how many times rollover has happened (or subtract rollovers if going in the other direction). Or you can directly accumulate or de-accumulate the + or - 65536 value of the register every time it rolls over. \$\endgroup\$
    – DKNguyen
    Jan 21, 2022 at 16:44

3 Answers 3

7
\$\begingroup\$

I can see 2 solution :

  1. Use a 32 bit timer instead of a 16 bit timer : you haven't specifyed the exact micro-controler you use, but at least for STM32F401xB/STM32F401xC (section 3.19.2), there are 2 timers with 32 bits (TIM2 and TIM5), which seem to be capable of encoder mode. That way, you get twice the number of bits. It might (or not) be enough for you to garantee that you will never exceed the limit. NB : I didn't checked if all other stm32F401 version have those 323 bits timers.

  2. If you need more than 2 encoders, if TIM 2 or TIM5 are needed for something else (or your specific micro-controler don't have them), or if anyway even 32 bits is not enough, then you can solve the problem in software :

  • you usually know the maximal speed of your motor, so you know the maximal number of pulses per second : just sample the timer often enough (using another timer with interupt), and modify a "global" timer accordigly
  • or, there is probably a way to get an interruption on timer overflow/underflow : you just use this interruption to increment a counter that represent the most significant bits (the timer beeing the least significant bits). Nb : I haven't checked if you can indeed have an interupt on overflow, nor if you can separate overflow from underflow)
\$\endgroup\$
3
  • 1
    \$\begingroup\$ There is indeed a rollover interrupt on the STM32. Without it you could only ever use 65546 count encoders. . It does not need to trigger on an overflow. You can trigger it on the period you set it to (at which point it wraparound/rollover). \$\endgroup\$
    – DKNguyen
    Jan 21, 2022 at 16:48
  • 1
    \$\begingroup\$ @DKNguyen even better, these chips have "timer link" feature that allows chaining timers together, essentially doubling (and on some chips even tripling) the resolution. \$\endgroup\$
    – Maple
    Jan 21, 2022 at 23:36
  • \$\begingroup\$ @Maple Yeah but I think that's by far the most confusing even though on paper it sounds like the neatest one. I'm not even sure if it's set up to properly with in encoder mode. I think I took at look at it once and something didn't seem quite right about. Like the timers that were chained didn't chain together with the timer with encoder mode or something like that. \$\endgroup\$
    – DKNguyen
    Jan 22, 2022 at 4:15
5
\$\begingroup\$

A better way (in the general case) to solve this problem than hard coding checks for jumps in value:

#define ONE_PERIOD 65536
#define HALF_PERIOD 32768


int32_t unwrap_encoder(uint16_t in, int32_t * prev)
{
    int32_t c32 = (int32_t)in - HALF_PERIOD;    //remove half period to determine (+/-) sign of the wrap
    int32_t dif = (c32-*prev);  //core concept: prev + (current - prev) = current

    //wrap difference from -HALF_PERIOD to HALF_PERIOD. modulo prevents differences after the wrap from having an incorrect result
    int32_t mod_dif = ((dif + HALF_PERIOD) % ONE_PERIOD) - HALF_PERIOD;
    if(dif < -HALF_PERIOD)
        mod_dif += ONE_PERIOD;  //account for mod of negative number behavior in C

    int32_t unwrapped = *prev + mod_dif;
    *prev = unwrapped;  //load previous value

    return unwrapped + HALF_PERIOD; //remove the shift we applied at the beginning, and return
}

This is essentially doing output = previous + (current - previous). The magic happens in the (current-previous) part, by using modulo. Modulo allows you to determine the correct difference between two values, after a wrap has occurred.

For instance, if you're sampling an encoder and your current position is 3 radians, and the previous angle was -3 radians, you know that you probably made a jump of -0.2832 radians (as opposed to +6 radians).

So all this algorithm is doing is finding the 'nearest difference' between the last two samples and adding that difference to the previous value, thus restoring the true encoder count.

This method also implicitly turns an unsigned angle count (0 to 65535) into a signed angle count, whose size is capped by the max value of whatever container you use in the function (i.e. int32). So if you started at zero and spun the encoder backwards, the output of this function will give you a negative value without any additional logic needed.

\$\endgroup\$
2
  • \$\begingroup\$ The maximum "step" this function can decode is 2^15 if I understand correctly. Might be worth mentioning \$\endgroup\$
    – Jeroen3
    Jan 21, 2022 at 21:02
  • \$\begingroup\$ This function expects inputs from 0-65535, i.e. for 16bit unsigned encoder ticks. It removes jumps in value for inputs in that range. If you have a 14 bit encoder, for instance, you'd need to adjust the values of ONE_PERIOD and HALF_PERIOD accordingly. \$\endgroup\$
    – Ocanath
    Jan 21, 2022 at 22:01
0
\$\begingroup\$

Simple solution, if you see that the count jumps such a large value, it means in really just increased by one and rolled over.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.