Arduino timing control for V8 engine

My grandfather and I are working on making an Arduino powered timing unit that can be dropped into the wiring of a ford flathead V8 to control the spark advance.

So far I have a script that will emulate the distributor so I can test if my timing advance is working correctly.

Here is the code:

/*
V8 distributor emulator with serial input to contoll the RPM.
Ben Holleran
January 2, 2011

A V8 distributor fires four pulses per revolution at even intervals.
at 6000 RPM the pulses are 2500 microseconds apart.

This script will go as high as 11k before it fails. 
This script does not provide any advance nor is it actualy usable, it is meant to give a signal for testing the actual timing unit.
*/

void setup() 
{
  pinMode(13, OUTPUT);     
  Serial.begin(115200);
}

// set up a bunch of variables
long mic = micros();
String RPMS= "";
bool go = false;
int RPM = 6000;
long test = 0;
long micdelay = 2500;

//main progam loop
void loop() 
{
  mic = micros();
  digitalWrite(13, HIGH);   // Start pulse
  delayMicroseconds(100);              // wait for 100 microseconds of dwell (this value is probably way more than an actualy distributor)
  digitalWrite(13, LOW);    // End pulse
  while (Serial.available() >= 1) // test if new rpm data is availible
  {
   RPMS += String(char(Serial.read())); //read new rpm from serial
   go = true;
  }
  if (go == true)
  {
    Serial.println("Setting RPM to: "+ RPMS+ " RPM"); //send verification
    char this_char[RPMS.length() + 1];
    RPMS.toCharArray(this_char, sizeof(this_char));
    RPM = atoi(this_char);  // dont know how this works exactly, but it turns the rpm string into an int
    RPMS = "";
    go = false;
    micdelay = 15000000/RPM;  //find how long it *should* be between pulses
  }
  //Serial.println(micdelay);
  //Serial.println(test);     // debugging remnents
  //Serial.println(mic);
  //Serial.println(micdelay -test -4);
  delay(((micdelay)/1000)-1);  //delay for the majority of the time till the next pulse leaving *hopefully* 2000 microseconds left (this could be optimized if higer RPM values are needed)
  test = micros()- mic; //find how long the program loop took    
  delayMicroseconds(micdelay -test -4);              // wait for the remainder of the time
} // end loop

I will post the script for the final code once I have it written.

Let me know what you guys think.

~Wild_Doogy

Normal dwell is anywhere from 2.5milliseconds to 4.5milliseconds. Incase you needed to know, and weren't sure. :slight_smile: If you plan to fire the coil with one of the Arduino outputs, you want to use an IGBT, put a 7.5amp fuse inline in case the code crashes, to prevent damaging your coil. 5amp might even work, but if the 5amp blows, don't panic. If the 7.5 blows, you have too much dwell. You don't need a ballast resistor with that type of setup, the ballast resistor is there to make mechanical points last longer, and is a lot of why an electronic ignition makes more power, the coil gets full voltage, so you get a hotter spark.

UnaClocker has made some very important points.
It's very important to know the real-world parameters that are crucial to a functioning system.

Thanks, any info I can get is great.

The code above only emulated the signal I would be getting from a distributor so I can test the real program.

So far it is coming well and I am looking for someone with an oscilloscope so I can tune the timings of the program and find out how well the system is working.

I am thinking of making the module controllable from the MegaJolt software as it would save time and give me a really easy way of controlling the timing map.

~Wild_Doogy

Depending on your RPM needs, you might want to look into the following thread:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1267553811/0

...though when I saw your (this) thread yesterday, it seemed you had a comment or something where you couldn't go about 7.5K RPM before the code failed (and now the code says 11K)?

So maybe you won't need it; but keep it in mind, I suppose...

:slight_smile:

I did some code optimisation and cut 1 millisecond from the wait time between pulses. now the code goes nicely to 11k without it setting the delay to a negative number ending in a lock up.

I use direct port IO so the code is even faster than the commands in your post. The Fast IO commands are great but I need even more performance. (Setting pulse within 4 microseconds.)

I am currently working on the actual timing script and it is going well. I went and borrowed an oscilloscope from my old teacher and got an education from my grandfather on oscilloscopes and pulses.

I foresee a problem that I will have to deal with in the near future: the distributor only outputs a pulse that is ~4 uS long and my script currently has trouble catching that as I am doing polling. (I might do a interrupt based test in a minute.......) I might need to set up a pull-up resistor to lengthen the pulse length so I can catch it more reliably.

Another problem is that the pulse needs to be output BEFORE I get the timing pulse (the pulse needs to be advanced) so I have to send the pulse based on the last pulse. The problem is that if the engine speeds up significantly I might be waiting to send the output pulse and miss the input pulse.

As I wrote this the problems that I had with interrupts that caused me to leave them alone are getting dimmer in my mind and the benefits are blinking like an alarm light. time to look at interrupts again.

~Wild_Doogy

I did some code optimisation and cut 1 millisecond from the wait time between pulses. now the code goes nicely to 11k without it setting the delay to a negative number ending in a lock up.

I use direct port IO so the code is even faster than the commands in your post. The Fast IO commands are great but I need even more performance. (Setting pulse within 4 microseconds.)

Obviously, the code you posted isn't the (complete) set of code you are using; I was basing my observation only on what you posted, which contains (as far as I can tell) no direct port manipulation code...?

:-?

Sorry, I didn't add all of the modifications when I edited the post.

Here is the latest code:

/*
V8 distributor emulator with serial input to contoll the RPM.
Ben Holleran
January 2, 2011

A V8 distributor fires four pulses per revolution at even intervals.
at 6000 RPM the pulses are 2500 microseconds apart.

This script will go as high as 7.5k before it fails. 
This script does not provide any advance nor is it actualy usable, it is meant to give a signal for testing the actual timing unit.
*/

void setup() 
{
  pinMode(13, OUTPUT);     
  Serial.begin(115200);
}

// set up a bunch of variables
long mic = micros();
String RPMS= "";
bool go = false;
int RPM = 3000;
long test = 0;
long micdelay = 5000;

//main progam loop
void loop() 
{
  mic = micros();
  PORTB = B10000000;   // Start pulse
  delayMicroseconds(8);              // wait for 8 microseconds of dwell (this value is probably way more than an actualy distributor)
  PORTB = B00000000;    // End pulse
  while (Serial.available() >= 1) // test if new rpm data is availible
  {
   RPMS += String(char(Serial.read())); //read new rpm from serial
   go = true;
  }
  if (go == true)
  {
    Serial.println("Setting RPM to: "+ RPMS+ " RPM"); //send verification
    char this_char[RPMS.length() + 1];
    RPMS.toCharArray(this_char, sizeof(this_char));
    RPM = atoi(this_char);  // dont know how this works exactly, but it turns the rpm string into an int
    RPMS = "";
    go = false;
    micdelay = 15000000/RPM;  //find how long it *should* be between pulses
  }
  //Serial.println(micdelay);
  //Serial.println(test);     // debugging remnents
  //Serial.println(mic);
  //Serial.println(micdelay -test -4);
  delay(((micdelay)/1000)-1);  //delay for the majority of the time till the next pulse leaving *hopefully* 2000 microseconds left (this could be optimized if higer RPM values are needed)
  test = micros()- mic; //find how long the program loop took    
  delayMicroseconds(micdelay -test -4);              // wait for the remainder of the time
} // end loop