Subversion Repositories libIgnTiming

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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