jump to navigation

Engine Speed Measurement 2010/03/26

Posted by Michael in 2JZduino.

[Note: This post is obsoleted by an alternate RPM measurement method using only the crank sensor. See post from June 6, 2010.]

Prior to adjusting fuel injection or ignition timing parameters of a running engine, the present operating conditions must be determined through measurement.  For a forced-induction application the most important parameters are engine rotation speed, and the air pressure in the intake manifold.  Together these parameters indicate the rate of air mass flowing through the engine, and the pressure of the combustion chamber prior to the compression stroke of the engine.  Higher combustion chamber pressures relate to delayed ignition timing to avoid detonation (higher pressure mixtures burn faster).

Engine RPM measurement is done in time with every third cam sensor signal (three cam signals arrive per full cycle of the 2JZ-GE engine).  The code used to calculate the engine speed is given below.

void setup()
  // Timer5 Control and Interrupts: : Cam Input Capture
  TCCR5A = 0;  // Set operating mode to Normal
  TCCR5B = B11000010;  // Input Capture Noise Canceler = ON, Input Capture Edge Select = RISING, Prescaler = clk/8
  TIMSK5 = B00000001; // enable overflow interrupt
  TIFR5 |= B00101111;// clear possible pending interrupts

void CalculateEngineSpeed()
  static unsigned int LastTime = 0;
  unsigned int ThisTime = TCNT5;
  // ThisTime < 1000 protects against the rare circumstance where Timer5 rollover occurs right after it is assigned (above); i.e. when ThisTime == 65535
  if (TIFR5 & B00000001 && ThisTime < 1000) { // handle TOV5 interrupt that is pending (occurs after this interrupt/function combo begins
    TIFR5 = B00000001; // clear TOV5 interrupts fired while this interrupt/function combo is being serviced
  int Period = highByte(ThisTime) - highByte(LastTime) + (CamPeriodT5RolloverCount << 8);

  // this search-loop more efficient than calculating "newEngineHz = 1 / TimePeriod"
  byte newEngineHz = EngineHz;
  for (int i = 0; i <= MAXHZ; i++) { // setup a finite for loop to avoid getting logic-trapped
    if (Period > HzPeriodTable[0]) {  // stopped engine
      newEngineHz = 0;
    else if (Period <= HzPeriodTable[newEngineHz] && Period > HzPeriodTable[newEngineHz+1]) break; // match found
    else if (Period > HzPeriodTable[newEngineHz]) newEngineHz--;  // engine has slowed down
    else if (Period < HzPeriodTable[newEngineHz]) newEngineHz++;  // engine has sped up

  EngineHz = newEngineHz;  // accept the new EngineHz
  LastTime = ThisTime;
  CamPeriodT5RolloverCount = 0;

Note the function doesn’t explicitly calculate the engine speed in Hz. Instead it searches a pre-calculated array of highbyte(Timer5) tick counts for a matching range. The index values of this array represent the corresponding engine Hz. When a match is found the index value is stored as the current engine speed.

This search algorithm is faster than performing a division calculation on the processor, especially given that the engine speed changes gradually.  With this restriction the last known engine speed provides an excellent first-guess for the new calculated engine speed.  The search loop should only need to execute once or twice before arriving at a match.

There is additional code executed when the Timer5 rollover interrupt is fired.  This code increments the variable “CamPeriodT5RolloverCount”.  It’s value is greater than 1 at slow engine speeds when one full engine cycle takes more than 65,536 Timer5 ticks.



No comments yet — be the first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: