32bits encoder counter using 16bits TIM and a 32bits software counter

Dependents:   v1 v2 v2bis GestionPixy ... more

Software 32 bits quadrature encoder interface for STM32 targets

This library is designed to help interface quadrature encoders with STM32 targets. The base idea is to use a timer as a counter with several inputs corresponding to the A and B channels of a quadrature encoder. This is easily done with the new STM32 chips from STMicro, and of course with the Nucleo Boards.

Almost every Nucleo Board has 4 or 5 of those interfaces, that can be routed to several pins (I still have to check with every board to this day). This library provides an easy way to use these quadrature decoders, with an added feature : using software 32 bits integers to stock the counter, allowing a more efficient way to use them. In deed, most of the timers of the Nucleo Boards are 16 bits counters, and thus can limit the possibilities in some projects.

The solution provided here uses the update interrupt of the timer, set when the counter over- or underflows, and updates an 32 bits integer accordingly, allowing to track the encoder activity on a range of -(2^31) to (2^31)-1, or -2147483648 to 2147483647.

Plus, this interface allows to use a simple object, easily instantiated.

Example code

#include "mbed.h"
#include "Nucleo_Encoder_16_bits.h"


Nucleo_Encoder_16_bits encoder1(TIM3);

void main (void)
{
    printf("Start of Nucleo Encoder test program");

    for(;;)
    {
        wait(1.0);
        printf("Encoder count : %l", encoder1.GetCounter());
    }
}

Please check the header file corresponding to your target to get the physical pins to which you have to connect the signals (EncoderMspInitxx.h)

Also, please do not mind the name of the files or objects/methods in this library. Some are named "16 bits", but everything runs using 32 bits soft counters, as said above.

Committer:
kkoichy
Date:
Thu May 26 16:21:43 2016 +0000
Revision:
1:e82009479b5c
Parent:
0:ebd170807e11
V1.1 :; - Added one constructor with only one parameter

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kkoichy 0:ebd170807e11 1 #include "Nucleo_Encoder_16_bits.h"
kkoichy 0:ebd170807e11 2
kkoichy 0:ebd170807e11 3 int32_t Soft_32_Counter_TIM2, Soft_32_Counter_TIM3, Soft_32_Counter_TIM4, Soft_32_Counter_TIM5;
kkoichy 0:ebd170807e11 4
kkoichy 0:ebd170807e11 5 void Overflow_Routine_TIM2()
kkoichy 0:ebd170807e11 6 {
kkoichy 0:ebd170807e11 7 if(TIM2->SR & 0x0001)
kkoichy 0:ebd170807e11 8 {
kkoichy 0:ebd170807e11 9 printf("Overflow Routine");
kkoichy 0:ebd170807e11 10 TIM2->SR &= 0xfffe;
kkoichy 0:ebd170807e11 11 if(!(TIM2->CR1&TIM_CR1_DIR))
kkoichy 0:ebd170807e11 12 Soft_32_Counter_TIM2 += 0xffff;
kkoichy 0:ebd170807e11 13 else
kkoichy 0:ebd170807e11 14 Soft_32_Counter_TIM2 -= 0xffff;
kkoichy 0:ebd170807e11 15 }
kkoichy 0:ebd170807e11 16 }
kkoichy 0:ebd170807e11 17
kkoichy 0:ebd170807e11 18 void Overflow_Routine_TIM3()
kkoichy 0:ebd170807e11 19 {
kkoichy 0:ebd170807e11 20 if(TIM3->SR & 0x0001)
kkoichy 0:ebd170807e11 21 {
kkoichy 0:ebd170807e11 22 printf("Overflow Routine");
kkoichy 0:ebd170807e11 23 TIM3->SR &= 0xfffe;
kkoichy 0:ebd170807e11 24 if(!(TIM3->CR1&TIM_CR1_DIR))
kkoichy 0:ebd170807e11 25 Soft_32_Counter_TIM3 += 0xffff;
kkoichy 0:ebd170807e11 26 else
kkoichy 0:ebd170807e11 27 Soft_32_Counter_TIM3 -= 0xffff;
kkoichy 0:ebd170807e11 28 }
kkoichy 0:ebd170807e11 29 }
kkoichy 0:ebd170807e11 30 void Overflow_Routine_TIM4()
kkoichy 0:ebd170807e11 31 {
kkoichy 0:ebd170807e11 32 if(TIM4->SR & 0x0001)
kkoichy 0:ebd170807e11 33 {
kkoichy 0:ebd170807e11 34 printf("Overflow Routine");
kkoichy 0:ebd170807e11 35 TIM4->SR &= 0xfffe;
kkoichy 0:ebd170807e11 36 if(!(TIM4->CR1&TIM_CR1_DIR))
kkoichy 0:ebd170807e11 37 Soft_32_Counter_TIM4 += 0xffff;
kkoichy 0:ebd170807e11 38 else
kkoichy 0:ebd170807e11 39 Soft_32_Counter_TIM4 -= 0xffff;
kkoichy 0:ebd170807e11 40 }
kkoichy 0:ebd170807e11 41 }
kkoichy 0:ebd170807e11 42 void Overflow_Routine_TIM5()
kkoichy 0:ebd170807e11 43 {
kkoichy 0:ebd170807e11 44 if(TIM5->SR & 0x0001)
kkoichy 0:ebd170807e11 45 {
kkoichy 0:ebd170807e11 46 printf("Overflow Routine");
kkoichy 0:ebd170807e11 47 TIM5->SR &= 0xfffe;
kkoichy 0:ebd170807e11 48 if(!(TIM5->CR1&TIM_CR1_DIR))
kkoichy 0:ebd170807e11 49 Soft_32_Counter_TIM5 += 0xffff;
kkoichy 0:ebd170807e11 50 else
kkoichy 0:ebd170807e11 51 Soft_32_Counter_TIM5 -= 0xffff;
kkoichy 0:ebd170807e11 52 }
kkoichy 0:ebd170807e11 53 }
kkoichy 0:ebd170807e11 54
kkoichy 0:ebd170807e11 55 namespace mbed
kkoichy 0:ebd170807e11 56 {
kkoichy 1:e82009479b5c 57
kkoichy 1:e82009479b5c 58 Nucleo_Encoder_16_bits::Nucleo_Encoder_16_bits(TIM_TypeDef * _TIM)
kkoichy 1:e82009479b5c 59 {
kkoichy 1:e82009479b5c 60 TIM = _TIM;
kkoichy 1:e82009479b5c 61 // Initialisation of the TIM module as an encoder counter
kkoichy 1:e82009479b5c 62 EncoderInit(&encoder, &timer, _TIM, 0xffff, TIM_ENCODERMODE_TI12);
kkoichy 1:e82009479b5c 63
kkoichy 1:e82009479b5c 64 // Update (aka over- and underflow) interrupt enabled
kkoichy 1:e82009479b5c 65 TIM->DIER |= 0x0001;
kkoichy 1:e82009479b5c 66 // The initialisation process generates an update interrupt, so we'll have to clear the update flag before anything else
kkoichy 1:e82009479b5c 67 TIM->SR &= 0xfffe;
kkoichy 1:e82009479b5c 68
kkoichy 1:e82009479b5c 69 // Setting the ISR for the corresponding interrupt vector
kkoichy 1:e82009479b5c 70 switch((uint32_t)TIM)
kkoichy 1:e82009479b5c 71 {
kkoichy 1:e82009479b5c 72 case TIM2_BASE :
kkoichy 1:e82009479b5c 73 NVIC_SetVector(TIM2_IRQn, (uint32_t)&Overflow_Routine_TIM2);
kkoichy 1:e82009479b5c 74 NVIC_EnableIRQ(TIM2_IRQn);
kkoichy 1:e82009479b5c 75 Soft_32_Counter_TIM2 = 0;
kkoichy 1:e82009479b5c 76 break;
kkoichy 1:e82009479b5c 77
kkoichy 1:e82009479b5c 78 case TIM3_BASE :
kkoichy 1:e82009479b5c 79 NVIC_SetVector(TIM3_IRQn, (uint32_t)&Overflow_Routine_TIM3);
kkoichy 1:e82009479b5c 80 NVIC_EnableIRQ(TIM3_IRQn);
kkoichy 1:e82009479b5c 81 Soft_32_Counter_TIM3 = 0;
kkoichy 1:e82009479b5c 82 break;
kkoichy 1:e82009479b5c 83
kkoichy 1:e82009479b5c 84 case TIM4_BASE :
kkoichy 1:e82009479b5c 85 NVIC_SetVector(TIM4_IRQn, (uint32_t)&Overflow_Routine_TIM4);
kkoichy 1:e82009479b5c 86 NVIC_EnableIRQ(TIM4_IRQn);
kkoichy 1:e82009479b5c 87 Soft_32_Counter_TIM4 = 0;
kkoichy 1:e82009479b5c 88 break;
kkoichy 1:e82009479b5c 89
kkoichy 1:e82009479b5c 90 case TIM5_BASE :
kkoichy 1:e82009479b5c 91 NVIC_SetVector(TIM5_IRQn, (uint32_t)&Overflow_Routine_TIM5);
kkoichy 1:e82009479b5c 92 NVIC_EnableIRQ(TIM5_IRQn);
kkoichy 1:e82009479b5c 93 Soft_32_Counter_TIM5 = 0;
kkoichy 1:e82009479b5c 94 break;
kkoichy 1:e82009479b5c 95
kkoichy 1:e82009479b5c 96 default :
kkoichy 1:e82009479b5c 97
kkoichy 1:e82009479b5c 98 break;
kkoichy 1:e82009479b5c 99 }
kkoichy 1:e82009479b5c 100
kkoichy 1:e82009479b5c 101 }
kkoichy 0:ebd170807e11 102 Nucleo_Encoder_16_bits::Nucleo_Encoder_16_bits(TIM_TypeDef * _TIM, uint32_t _maxcount, uint32_t _encmode)
kkoichy 0:ebd170807e11 103 {
kkoichy 0:ebd170807e11 104 TIM = _TIM;
kkoichy 0:ebd170807e11 105 // Initialisation of the TIM module as an encoder counter
kkoichy 0:ebd170807e11 106 EncoderInit(&encoder, &timer, _TIM, _maxcount, _encmode);
kkoichy 0:ebd170807e11 107
kkoichy 0:ebd170807e11 108 // Update (aka over- and underflow) interrupt enabled
kkoichy 0:ebd170807e11 109 TIM->DIER |= 0x0001;
kkoichy 0:ebd170807e11 110 // The initialisation process generates an update interrupt, so we'll have to clear the update flag before anything else
kkoichy 0:ebd170807e11 111 TIM->SR &= 0xfffe;
kkoichy 0:ebd170807e11 112
kkoichy 0:ebd170807e11 113 // Setting the ISR for the corresponding interrupt vector
kkoichy 0:ebd170807e11 114 switch((uint32_t)TIM)
kkoichy 0:ebd170807e11 115 {
kkoichy 0:ebd170807e11 116 case TIM2_BASE :
kkoichy 0:ebd170807e11 117 NVIC_SetVector(TIM2_IRQn, (uint32_t)&Overflow_Routine_TIM2);
kkoichy 0:ebd170807e11 118 NVIC_EnableIRQ(TIM2_IRQn);
kkoichy 0:ebd170807e11 119 Soft_32_Counter_TIM2 = 0;
kkoichy 0:ebd170807e11 120 break;
kkoichy 0:ebd170807e11 121
kkoichy 0:ebd170807e11 122 case TIM3_BASE :
kkoichy 0:ebd170807e11 123 NVIC_SetVector(TIM3_IRQn, (uint32_t)&Overflow_Routine_TIM3);
kkoichy 0:ebd170807e11 124 NVIC_EnableIRQ(TIM3_IRQn);
kkoichy 0:ebd170807e11 125 Soft_32_Counter_TIM3 = 0;
kkoichy 0:ebd170807e11 126 break;
kkoichy 0:ebd170807e11 127
kkoichy 0:ebd170807e11 128 case TIM4_BASE :
kkoichy 0:ebd170807e11 129 NVIC_SetVector(TIM4_IRQn, (uint32_t)&Overflow_Routine_TIM4);
kkoichy 0:ebd170807e11 130 NVIC_EnableIRQ(TIM4_IRQn);
kkoichy 0:ebd170807e11 131 Soft_32_Counter_TIM4 = 0;
kkoichy 0:ebd170807e11 132 break;
kkoichy 0:ebd170807e11 133
kkoichy 0:ebd170807e11 134 case TIM5_BASE :
kkoichy 0:ebd170807e11 135 NVIC_SetVector(TIM5_IRQn, (uint32_t)&Overflow_Routine_TIM5);
kkoichy 0:ebd170807e11 136 NVIC_EnableIRQ(TIM5_IRQn);
kkoichy 0:ebd170807e11 137 Soft_32_Counter_TIM5 = 0;
kkoichy 0:ebd170807e11 138 break;
kkoichy 0:ebd170807e11 139
kkoichy 0:ebd170807e11 140 default :
kkoichy 0:ebd170807e11 141
kkoichy 0:ebd170807e11 142 break;
kkoichy 0:ebd170807e11 143 }
kkoichy 0:ebd170807e11 144
kkoichy 0:ebd170807e11 145 }
kkoichy 0:ebd170807e11 146
kkoichy 0:ebd170807e11 147 Nucleo_Encoder_16_bits::Nucleo_Encoder_16_bits(TIM_Encoder_InitTypeDef * _encoder, TIM_HandleTypeDef * _timer, TIM_TypeDef * _TIM, uint32_t _maxcount, uint32_t _encmode)
kkoichy 0:ebd170807e11 148 {
kkoichy 0:ebd170807e11 149 timer = *_timer;
kkoichy 0:ebd170807e11 150 encoder = *_encoder;
kkoichy 0:ebd170807e11 151 TIM = _TIM;
kkoichy 0:ebd170807e11 152 // Initialisation of the TIM module as an encoder counter
kkoichy 0:ebd170807e11 153 EncoderInit(&encoder, &timer, _TIM, _maxcount, _encmode);
kkoichy 0:ebd170807e11 154
kkoichy 0:ebd170807e11 155 // Update (aka over- and underflow) interrupt enabled
kkoichy 0:ebd170807e11 156 TIM->DIER |= 0x0001;
kkoichy 0:ebd170807e11 157 // The initialisation process generates an update interrupt, so we'll have to clear the update flag before anything else
kkoichy 0:ebd170807e11 158 TIM->SR &= 0xfffe;
kkoichy 0:ebd170807e11 159
kkoichy 0:ebd170807e11 160 // Setting the ISR for the corresponding interrupt vector
kkoichy 0:ebd170807e11 161 switch((uint32_t)TIM)
kkoichy 0:ebd170807e11 162 {
kkoichy 0:ebd170807e11 163 case TIM2_BASE :
kkoichy 0:ebd170807e11 164 NVIC_SetVector(TIM2_IRQn, (uint32_t)&Overflow_Routine_TIM2);
kkoichy 0:ebd170807e11 165 NVIC_EnableIRQ(TIM2_IRQn);
kkoichy 0:ebd170807e11 166 Soft_32_Counter_TIM2 = 0;
kkoichy 0:ebd170807e11 167 break;
kkoichy 0:ebd170807e11 168
kkoichy 0:ebd170807e11 169 case TIM3_BASE :
kkoichy 0:ebd170807e11 170 NVIC_SetVector(TIM3_IRQn, (uint32_t)&Overflow_Routine_TIM3);
kkoichy 0:ebd170807e11 171 NVIC_EnableIRQ(TIM3_IRQn);
kkoichy 0:ebd170807e11 172 Soft_32_Counter_TIM3 = 0;
kkoichy 0:ebd170807e11 173 break;
kkoichy 0:ebd170807e11 174
kkoichy 0:ebd170807e11 175 case TIM4_BASE :
kkoichy 0:ebd170807e11 176 NVIC_SetVector(TIM4_IRQn, (uint32_t)&Overflow_Routine_TIM4);
kkoichy 0:ebd170807e11 177 NVIC_EnableIRQ(TIM4_IRQn);
kkoichy 0:ebd170807e11 178 Soft_32_Counter_TIM4 = 0;
kkoichy 0:ebd170807e11 179 break;
kkoichy 0:ebd170807e11 180
kkoichy 0:ebd170807e11 181 case TIM5_BASE :
kkoichy 0:ebd170807e11 182 NVIC_SetVector(TIM5_IRQn, (uint32_t)&Overflow_Routine_TIM5);
kkoichy 0:ebd170807e11 183 NVIC_EnableIRQ(TIM5_IRQn);
kkoichy 0:ebd170807e11 184 Soft_32_Counter_TIM5 = 0;
kkoichy 0:ebd170807e11 185 break;
kkoichy 0:ebd170807e11 186
kkoichy 0:ebd170807e11 187 default :
kkoichy 0:ebd170807e11 188
kkoichy 0:ebd170807e11 189 break;
kkoichy 0:ebd170807e11 190 }
kkoichy 0:ebd170807e11 191
kkoichy 0:ebd170807e11 192 }
kkoichy 0:ebd170807e11 193
kkoichy 0:ebd170807e11 194
kkoichy 0:ebd170807e11 195 int32_t Nucleo_Encoder_16_bits::GetCounter()
kkoichy 0:ebd170807e11 196 {
kkoichy 0:ebd170807e11 197 uint16_t count = TIM->CNT;
kkoichy 0:ebd170807e11 198 switch((uint32_t)TIM)
kkoichy 0:ebd170807e11 199 {
kkoichy 0:ebd170807e11 200 case TIM2_BASE :
kkoichy 0:ebd170807e11 201 return (int32_t)count + Soft_32_Counter_TIM2;
kkoichy 0:ebd170807e11 202 break;
kkoichy 0:ebd170807e11 203
kkoichy 0:ebd170807e11 204 case TIM3_BASE :
kkoichy 0:ebd170807e11 205 return (int32_t)count + Soft_32_Counter_TIM3;
kkoichy 0:ebd170807e11 206 break;
kkoichy 0:ebd170807e11 207
kkoichy 0:ebd170807e11 208 case TIM4_BASE :
kkoichy 0:ebd170807e11 209 return (int32_t)count + Soft_32_Counter_TIM4;
kkoichy 0:ebd170807e11 210 break;
kkoichy 0:ebd170807e11 211
kkoichy 0:ebd170807e11 212 case TIM5_BASE :
kkoichy 0:ebd170807e11 213 return (int32_t)count + Soft_32_Counter_TIM5;
kkoichy 0:ebd170807e11 214 break;
kkoichy 0:ebd170807e11 215 }
kkoichy 0:ebd170807e11 216
kkoichy 0:ebd170807e11 217 return (int32_t)count;
kkoichy 0:ebd170807e11 218 }
kkoichy 0:ebd170807e11 219
kkoichy 0:ebd170807e11 220 TIM_HandleTypeDef* Nucleo_Encoder_16_bits::GetTimer()
kkoichy 0:ebd170807e11 221 {
kkoichy 0:ebd170807e11 222 return &timer;
kkoichy 0:ebd170807e11 223 }
kkoichy 0:ebd170807e11 224
kkoichy 0:ebd170807e11 225
kkoichy 0:ebd170807e11 226
kkoichy 0:ebd170807e11 227
kkoichy 0:ebd170807e11 228
kkoichy 0:ebd170807e11 229
kkoichy 0:ebd170807e11 230 }