Subversion Repositories libIgnTiming

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
// code to compute RPM
2
#include "stdint.h"
3
 
4
#include "libIgnTiming/rpm.h"
5
#if defined RPMTIMER
6
 
7
extern "C"
8
{
9
    typedef enum
10
    {
11
        PULSE_LOW = 1,
12
        PULSE_HIGH = 2,
13
        PULSE_BOTH = 3
14
    } pulseState_t;
15
    // with a dwell angle of 45 degrees , 4 cylinders and a maximum RPM of 5000
16
    // freq = 5000/60 * 2 = 166Hz.
17
    // the TIM2 counter counts in 10uS increments,
18
    // Need to accumulate low level for a 400th of a second before accepting it as a pulse
19
    const uint16_t ACCUM_MAX = (RPM_COUNT_RATE / 400);
20
 
21
    // shared variables used in calculation - a pipeline of samples
22
    static volatile unsigned long RPM_Time[RPM_SAMPLES]; // sampled on both edges
23
    static volatile unsigned long RPM_Count;             // incremented every reading
24
 
25
    void TIMER_IRQ_HANDLER(void)
26
    {
27
        static char level = 0;
28
        char valid = 0;
29
        uint16_t high_count = 0;
30
        uint16_t low_count = 0;
31
        // rising edge CB pulse
32
        if (__HAL_TIM_GET_FLAG(&TIMER_HANDLE, TIM_FLAG_CC1))
33
        {
34
            __HAL_TIM_CLEAR_FLAG(&TIMER_HANDLE, TIM_FLAG_CC1);
35
            low_count = __HAL_TIM_GET_COMPARE(&TIMER_HANDLE, TIM_CHANNEL_1);
36
            valid = PULSE_LOW; // record we have a low_count val
37
 
38
            // trigger any other event at rising edge
39
            AUXILIARY_HIGH;
40
        }
41
        // falling edge trigger CB pulse
42
        if (__HAL_TIM_GET_FLAG(&TIMER_HANDLE, TIM_FLAG_CC2))
43
        {
44
            __HAL_TIM_CLEAR_FLAG(&TIMER_HANDLE, TIM_FLAG_CC2);
45
 
46
            high_count = __HAL_TIM_GET_COMPARE(&TIMER_HANDLE, TIM_CHANNEL_2);
47
            valid |= PULSE_HIGH;
48
            // trigger any other event at falling edge
49
            AUXILIARY_LOW;
50
        }
51
 
52
        switch (valid)
53
        {
54
        case pulseState_t::PULSE_LOW:
55
            // count width of a low period
56
            RPM_Time[RPM_Count] = low_count;
57
            RPM_Count = (RPM_Count + 1) % RPM_SAMPLES;
58
            level = 0; // remember level
59
            break;
60
        case pulseState_t::PULSE_HIGH:
61
            // count width of a high period
62
            RPM_Time[RPM_Count] = high_count | RPM_FLAG;
63
            RPM_Count = (RPM_Count + 1) % RPM_SAMPLES;
64
            level = 1; // remember level
65
            break;
66
            // there has been both a high level and a low level
67
        case pulseState_t::PULSE_BOTH:
68
            if (level == 1) // next level = 0 ,then 1 again
69
            {
70
                RPM_Time[RPM_Count] = low_count;
71
                RPM_Count = (RPM_Count + 1) % RPM_SAMPLES;
72
                RPM_Time[RPM_Count] = high_count | RPM_FLAG;
73
                RPM_Count = (RPM_Count + 1) % RPM_SAMPLES;
74
            }
75
            else
76
            {
77
                RPM_Time[RPM_Count] = high_count | RPM_FLAG;
78
                RPM_Count = (RPM_Count + 1) % RPM_SAMPLES;
79
                RPM_Time[RPM_Count] = low_count;
80
                RPM_Count = (RPM_Count + 1) % RPM_SAMPLES;
81
            }
82
            break;
83
        default:
84
            break;
85
        }
86
    }
87
 
88
    int CalculateRPM(void)
89
    {
90
        // compute the timer values
91
        // snapshot timers
92
 
93
        // Next state of pulse high/low
94
        static unsigned char RPM_State = 1;
95
        // Current state of pulse high/low
96
        static unsigned char RPM_State_Curr = 1;
97
 
98
        // variables used in calculation of RPM value
99
        static uint16_t last_dwell_end = 0;
100
        static uint16_t RPM_Period[RPM_AVERAGE];
101
        static unsigned int RPM_Period_Ptr = 0;
102
 
103
        static uint16_t RPM_Count_Latch = 0;
104
 
105
        // accumulators
106
        static int16_t RPM_Pulsecount = 0;
107
 
108
        __disable_irq(); // copy the counter value
109
        // current RPM pulse next slot index
110
        uint16_t RPM_Count_Val = RPM_Count;
111
        __enable_irq();
112
        // do calculations
113
 
114
        // if there is only one entry, cannot get difference
115
        if (RPM_Count_Latch != RPM_Count_Val)
116
        {
117
            while (1)
118
            {
119
                unsigned int base_time;
120
                unsigned int new_time;
121
                // if we are at N-1, stop.
122
                unsigned int next_count = (RPM_Count_Latch + 1) % RPM_SAMPLES;
123
                if (next_count == RPM_Count_Val)
124
                {
125
                    break; // completed loop
126
                }
127
                char pulse_level = (RPM_Time[RPM_Count_Latch] & RPM_FLAG) ? 1 : 0;
128
                base_time = RPM_Time[RPM_Count_Latch] & ~RPM_FLAG;
129
                new_time = RPM_Time[next_count] & ~RPM_FLAG;
130
                RPM_Count_Latch = next_count;
131
 
132
                uint16_t RPM_Pulsewidth = new_time - base_time;
133
 
134
                if (pulse_level == 0 && (RPM_Pulsewidth > ACCUM_MAX))
135
                    RPM_State = 1;
136
                if (pulse_level == 1)
137
                    RPM_State = 0;
138
 
139
                // low pulse has reached at least minimum width, count it.
140
                if ((RPM_State == 1) && (RPM_State_Curr == 0))
141
                {
142
                    // Rev counter processing from original RevCounter Project
143
                    uint16_t RPM_Diff = new_time - last_dwell_end;
144
 
145
                    RPM_Period[RPM_Period_Ptr] = RPM_Diff;
146
                    RPM_Period_Ptr = (RPM_Period_Ptr + 1) % RPM_AVERAGE;
147
                    if (RPM_Pulsecount < RPM_AVERAGE)
148
                        RPM_Pulsecount++; // count one pulse
149
                    last_dwell_end = new_time;
150
                }
151
                RPM_State_Curr = RPM_State;
152
            }
153
        }
154
 
155
        if (RPM_Pulsecount == RPM_AVERAGE)
156
        {
157
            // now have time for N pulses in clocks
158
            // 1Hz is 30 RPM
159
            int i;
160
            unsigned int RPM_FilteredWidth = 0;
161
            for (i = 0; i < RPM_AVERAGE; i++)
162
                RPM_FilteredWidth += RPM_Period[i];
163
 
164
#if !defined MY_DEBUG
165
            // reset here unless we want to debug
166
            RPM_Pulsecount = 0;
167
#endif
168
            return (Scale * 30.0 * RPM_AVERAGE * RPM_COUNT_RATE) / (RPM_FilteredWidth);
169
        }
170
        else
171
        {
172
            return -1; // flag no reading
173
        }
174
    }
175
}
176
#endif // RPMTIMER