jump to navigation

ATMega 1280 Capability 2010/03/22

Posted by Michael in 2JZduino.
trackback

Before beginning this 2JZduino project it was necessary to determine whether the ATMega 1280 processor used in Arduino Mega was capable of the task at hand; managing fuel injector scaling and ignition delay for the 2JZ-GE Toyota engine.

Most important to the project is the ability to provide sufficiently high resolution in digital signal processing for the ignition timing signals.  Typically, tuning ignition of a performance engine is done on the order of 1 degree of engine rotation.  So, I deemed it necessary that the microprocessor platform must respond to an input event in less than 1/2 a degree of engine rotation at maximum engine RPM.

The 2JZ-GE engine redline is below 7000RPM (117 Hz).  Taking this as worst case, the period of rotation at this speed is 8.57 ms.  The engine rotates 1/2 of a degree in 11.90 microseconds.

The ATMega 1280 processor has a system clock speed of 16 MHz.  In 11.90 microseconds 190 instructions are executed.

So, the requirement for the firmware is that each event must respond and return in less than 190 system clock ticks; plenty of time for simple addition and toggling digital inputs and outputs.  However no multiplication, division, floating point math, or other relatively slow operations will be permitted within the interrupt routines.

It is worth considering the overall processor load due to event response.  For each combustion cycle of the engine there are 2 revolutions, 68 crank pulses, 6 cam pulses, and 6 injector pulses.  Altogether this totals 160 ON and OFF events.  At 7000 RPM this occurs over 17.14 ms (8.57 * 2) during which time there are 274,240 instructions executed.  If each event consumes the full 190 instructions allotted, this totals 30,400 instructions due to digital events.  30,400 / 274,240 = 11% processor load.

This 11% load is an important consideration.  The interrupt handling of the ATMega 1280 is fairly primitive; the highest priority interrupt is always serviced first, and the priorities are not configurable.  If interrupts arrive faster than they can be handled a low-priority interrupt might never be serviced.  The fact that the interrupt load is on the order of 10% suggests that interrupts are unlikely to overlap significantly.

From a practical standpoint digital signals arriving at 2JZduino from the engine and/or ECU are unlikely to ever overlap more than 3 events; cam, crank, and one injector.  Crank signals are spaced mechanically by about 5 degrees, and injector signals are spaced by the mechanics of each separate piston.  In the event that a cam, crank, and injector event do arrive simultaneously the worst-case scenario is that the most critical event is serviced last and as a result is delayed by a full 2 event service periods or, one degree of engine rotation.  If the last serviced event is that which the ECU uses for ignition timing the result is harmless delayed ignition (a fail-safe condition).

Ultimately, the ATMega 1280 does seem a capable processor… but care and efficiency will be necessary in designing and verifying the firmware.

Comments»

1. Christoph - 2011/03/10

I measured the time for different IO actions by repeating them in a huge forloop and got the followin results:
unsigned long now = micros(); // 3 µsec
int ruptState=digitalRead(ruptPin); // 4usec
digitalWrite(LEDPin,LOW); // 5 µsec
function call vs. body expansion // 1-2 µsec

So timing is really worth some considerations. I am glad to hear that your project is successful.

Michael - 2011/03/10

We can agree timing is a critical consideration. But I wouldn’t recommend the approach I think you might be describing to measure execution time. First, the Arduino environment digitalRead and digitalWrite calls are much less efficient than referencing the ATmega registers directly. Search for “direct port manipulation” at http://www.arduino.cc for a thorough explanation.

Second, when you run a loop with numerous cycles you end up counting the time it takes to run the loop as well as the command you’re testing. A better way to measure timing is to record the value of one of the hardware counters before and after the code block you want to measure. Then output the difference. For example…

unsigned int tBefore = TCNT1; // ***** // the code block you want to measure // ***** unsigned int tAfter = TCNT1; … unsigned int dT = tAfter – tBefore; // output this value


Leave a reply to Christoph Cancel reply