updated on 04-11-2012

Speed Measurement

using edge detection modes with Input Capture module
Speed Measurement

As seen in the previous page, the Input Capture module catches the time values from a 16bit timer. A motor with a closed loop control can run at a speed as low as 60 rpm and as high as 6000 rpm. In my specific case (512 cpr encoder) it means a count every 2ms at the lower speed and every 20us at the higher speed. To have a good speed control we need at least a PID cycle every 1 ms, meaning no less than an IC sample in the same period to have a real speed value. In the aforementioned situation, we have not enough counts at the lower limit and too much interrupts for the MCU at the higher limit. Using an higher CPR (Count Per Revolution) encoder is better for the low speeds but worst for the high zone.
A good compromise between precision and performance could be achieved using the different Input Capture module edge detection modes. This, in practice, acts as a prescaler allowing an higher dynamic range for IC with a motor that runs also at a very low speed.

The graph above shows the relation between the wheel speed (i.e. after the gear reduction) in rpm and the encoder period (meaning also interrupts period for the MCU) in μs, at different IC configurations. For clarity purposes the Y axis is in logarithmic scale.
The dsPIC33F series DSC Input Capture module can be configured (using ICxCON: Input Capture x Control Register) in different edge detection modes. It can capture the TMR value at each edge (rising and falling) of the encoder signal, effectively doubling the input frequency and, therefore, cutting by half the period. The 1X mode is obtained capturing at each rising edge, 1/4X every 4th edge and 1/16X every 16th edge.

ICM<2:0>: Input Capture x Mode Select bits
101 = Capture mode, every 16th rising edge
100 = Capture mode, every 4th rising edge
011 = Capture mode, every rising edge
001 = Capture mode, every edge – rising and falling
000 = Input Capture module turned off

From Microchip dsPIC33F Family reference document:
"Section 12. Input Capture" DS70198D

Let's analyze this very practical configuration. Looking to the graph at the 100 μs line on period axis, we can find some thresholds useful to achieve a good optimization between interrupts frequency and number of capture samples to average in 1ms. After the speed has been computed as explained in the previous page, the program can check if the "rpm-IC mode" pair is set up at the best, switching to another IC mode if not.
The switch cannot be simply done around a single threshold for each mode. This could lead to a very dangerous up and down oscillation if the motor runs exactly at that speed. An hysteresis is created instead, instructing the program to switch to the next mode if "max" threshold has been passed and to the previous mode only under the "min" threshold.

01 //ICM<2:0>:Input Capture Mode Select bits

02 #defineIC_MODE1 0b001 // 2X mode

03 #defineIC_MODE2 0b011 // 1X mode

04 #defineIC_MODE3 0b100 // 1/4X mode

05

06 #defineKVELLONG_1 19301945  // 2X mode

07 #defineKVELLONG_2 38603891  // 1X mode

08 #defineKVELLONG_3 154415562 // 1/4X mode

09

10 #defineMIN1 6.177  // VelLong @ 30 RPM

11 #defineMAX1 10.294 // VelLong @ 50 RPM

12 #defineMIN2 20.589 // VelLong @ 100 RPM

13 #defineMAX2 24.706 // VelLong @ 120 RPM

14

15 //Kvel = SPACE_ENC*(FCY) for speed in m/s

16 long KvelLong = KVELLONG_1; // Kvel*2^15

17 long VelLong; // speed in a "long"

18

19 ...

20 // Speed computation and PID procedure

21 // Measured Speed in m/s(fract)

22 VelLong = KvelLong*IcIndxTmp/IcPeriodTmp;

23 PID_MES=(VelLong);//PID Process Variable

24

25   switch IC1CONbits.ICM

26   {

27     case IC_MODE1:

28       if(VelLong >= MAX1)

29       {

30         IC1CONbits.ICM = 0; // turn off

31         KvelLong = KVELLONG_2;

32         IC1CONbits.ICM = IC_MODE2;

33       }

34     break;

35

36     case IC_MODE2:

37       if(VelLong < MIN1)

38       {

39         IC1CONbits.ICM = 0; // turn off

40         KvelLong = KVELLONG_1;

41         IC1CONbits.ICM = IC_MODE1;

42       }

43       else if(VelLong >= MAX2)

44       {

45         IC1CONbits.ICM = 0; // turn off

46         KvelLong = KVELLONG_3;

47         IC1CONbits.ICM = IC_MODE3;

48       }

49     break;

50

51     case IC_MODE3:

52       if(VelLong < MIN2)

53       {

54         IC1CONbits.ICM = 0; // turn off

55         KvelLong = KVELLONG_2;

56         IC1CONbits.ICM = IC_MODE2;

57       }

58     break;

59

60     default:

61       IC1CONbits.ICM = 0; // turn off

62       KvelLong = KVELLONG_1;

63       IC1CONbits.ICM = IC_MODE1;

64     break;

65 }

66 ...