2021-04-15 03:04 PM
I'm currently using TIM2 on an STM32F373 as a 32bit quadrature encoder interface, however I need to extend this to 64 bits. Can I cascade a second 32bit counter (e.g. TIM5) as a slave whilst still maintaining the ability to count up & down ? Thanks
Solved! Go to Solution.
2021-04-15 04:04 PM
2021-04-15 04:04 PM
No.
You'll have to extend it in software.
JW
2021-04-15 11:28 PM
Thanks for that. So amongst the registers associated with TIM2 are there flag bits which indicate a recent overflow or underflow condition?
2021-04-16 06:36 AM
TIMx_SR.UIF as for any other mode of timer. However, I wouldn't use that to extend the counter; rather, I would observe the counter's value periodically and count overflows/underflows based on comparison of previous and new value.
JW
2021-04-16 07:02 AM
OK, thanks again. I'll do that.
2021-04-16 12:53 PM
I've been trying to develop a function to do what you suggest and read the TIM2 CNT register at a regular fast rate and extend its 32 bit value into 64 bits whilst coping with rollovers in both the up and down directions. The code I have so far is shown below, where enc and enc_old are both int32, whilst enc_long is the intended int64 output value, all defined and initialized to zero elsewhere. It works for rollovers around zero, but messes up at the higher order rollovers. I think the problem is that I don't fully understanding how C is handling the different sized integers. So is there a simpler and more elegant way to do this job compared to the mess I am currently making of it?
void encoder(void)
{
int64_t diff;
enc = htim2.Instance->CNT;
diff = abs(enc - enc_old);
enc_long = enc_long & 0xFFFFFFFF00000000;
if (diff < 1000000 && enc < 0 && enc_old >= 0) {
enc_long = enc_long - 0x0000000100000000;
}
if (diff < 1000000 && enc >= 0 && enc_old < 0) {
enc_long = enc_long + 0x0000000100000000;
}
enc_long = enc_long | enc;
enc_old = enc;
return;
}
2021-04-16 03:00 PM
I would do something along these lines:
uint64_t get_encoder(void) {
uint32_t enc;
static uint32_t enc_old, enc_hi;
enc = TIM2->CNT;
if ((enc_old > 0xc0000000) && (enc < 0x40000000)) enc_hi++;
if ((enc_old < 0x40000000) && (enc > 0xc0000000)) enc_hi--;
enc_old = enc;
return (((uint64_t)enc_hi) << 32) + enc;
}
and I would call this whenever I would need the 64-bit encoder value, making sure it's called at least once within the minimum time it takes to make 0x4000'0000 increments to the encoder.
JW
2021-04-16 11:05 PM
Thanks JW. I can see you've used unsigned integers throughout and I think this is where I am getting confused as I would need the function to return a signed 64 bit result which could run positive and negative either side of zero.