Distribute a signal based on a reset (automotive applicatio)

Hello everyone :slight_smile:

I'm having a bit of a headache and would need some expertise on my plan with the adruino.

So im about to do a ignitionswap for my car where the ECU gives a igniter a IGT signal, the igniter coil the fires and sends a IGF signal back and by the help or a rotor the spark finds it's way to the right place.

The circuits looks like this.

Now to the plan, I have new coil on plugs, so all I need is the IGT signal (not the igniter and rotor)
So I was thinking of setting the IGT signal to a Arduino which then will distribute the signal to the right coil/cylinder to fire. So it will count the IGT signal from 1 to 4 and distribute it to 1-3-4-2 cylinder.

And a triggerwheel on the crank will then act like a reset/ keep the arduino right by a reset pin.
So after the last trigger cylinder been fired a hallsensor will give a signal to the arduino that a new rotation will start and so on.

Now that we know the application i will get to my coding/arduino question since this is my weakest area of expertise.

Is this posible to do? would i be able to just take a inputsignal and bypass it to a output and just get the adruino to be able to choose that output?
Will it do it quick enough?

Will i be able to do it with a simple loop counting from 1-4 with a interrupt reset from the hall? or what method should i use?

Thankfull for all respons! :slight_smile:

edit// the coil on plugs have a IGF signal so it will be joined and lead back to the IGF input.

Started to make a code. but dont really get it to work. I have tried to run it against a UNO which simulated the "car engine" with 4 pules from the IGT signal from the ECU and one signal before from the sensor just before cylinder 1 to fire.
You only need to synd to cylinder 1 one time after that it will just count 1-2-3-4.

So for each IGT pulse i want the code to move fireorder one step forward.

The IGT signal from the ecu will go into arduino as a signal but i want the arduino to output 5v to a mosfet. So the next IGT signal will then be directed to the right cylinder, and the arduino will switch and be prepared for the next..

const byte IGTsignalPin = 92;                 //Interrupt pin for IGT signal from ECU (pin3) [datarange 0-1]
const byte crankshaftReferencePin = 2;   //Interrupt pin for crankshaft reference pin (pin2) [datarange 0-255]
volatile boolean syncAchieved = 0;         //Set this to true if sync has been achieved [datarange 0-255] 
volatile byte cylinderCounter = 0;           //Sequence which cylinder should fire (0-1-2-3) 
const byte fireOrder[] = {                     //Table containing the fireorder (1-3-4-2) [datarange 0-255]
B00000001, // cylinder 1-4
B00000010, // cylinder 2-3 
B00000001, // cylinder 1-4
B00000010}; // cylinder 2-3   


void setup() {
Serial.begin(19200);
pinMode(crankshaftReferencePin, INPUT_PULLUP);   
pinMode(IGTsignalPin, INPUT_PULLUP);
DDRB = 0b00000011;                                               //Set the first 2 pins on the B register to outputs. 

attachInterrupt(digitalPinToInterrupt(crankshaftReferencePin), ISR0, CHANGE);
Serial.println("Startup");
}

void loop() {
// put your main code here, to run repeatedly:
 while(syncAchieved == 1){                         //Start sequencing ignition outputs when sync has occured. 
 PORTB = fireOrder[cylinderCounter];}
}

void ISR1()
{
if (syncAchieved == 1) {                         
     if(digitalRead(IGTsignalPin) == HIGH){ 
       cylinderCounter++;                                             //we sequence the next cylinder that should fire
       Serial.println(cylinderCounter);
       if (cylinderCounter > 3){cylinderCounter = 0;}     //This a reset for the  4 cylinders
       }
       }
       else
      {
       Serial.println("No IGT SYNK");
      }
}

void ISR0()
{
if (digitalPinToInterrupt(crankshaftReferencePin), CHANGE)
   {
      detachInterrupt(digitalPinToInterrupt(crankshaftReferencePin));
      syncAchieved = 1;
      Serial.print("Sync Achieved");
      attachInterrupt(digitalPinToInterrupt(IGTsignalPin), ISR1, HIGH);    
   } 
 else{
  Serial.print("trying to sync");
 } 
}

SO i get it to sync but i never goes into the IGT interupten? why? :S It also take quite a while for it to sync, which it would do on the first pulse from the engine? :o

To make it easy for people to help you please modify your post and use the code button </>
codeButton.png

so your code 
looks like this

and is easy to copy to a text editor. See How to use the Forum

Also, don't write long comments that wrap to the next line as they make it vary hard to see the actual code. If you need a long comment put it on its own line (or lines) indented clear of the code - like this, for example

          // this is a comment
          // this is more
digitalWrite(pin, HIGH);

It looks as if you have print statements in your ISR - don't ever do that. Printing is slow and needs interrupts to be enabled. The code in an ISR should be designed to complete in as few microseconds as possible.

Thanks for the input, removed as much comment i could to make it clearer.

Im not a good coder so the write commets in interrupts are some good info even though i mostly use it now to debug my code and se were i get stuck.

But good to know that the slowness migth be the commets.

i still cant figure out why i cant get into the second interrupt (ISR1), any clue? :o

ceasarn:
But good to know that the slowness migth be the commets.

No. comments do not affect the actual code. Serial.print() statements in the ISR do affect the code and need to be avoided.

@ceasarn, for the future please don't make big changes to existing Posts - correcting typos if fine. But put new material in a new Reply so we can compare the old and the new if necessary.

Also, if you use the AutoFormat tool it will indent your code consistently and make it much easier to see where the different code blocks begin and end.

This does not look like valid (or at least sensible) code

if (digitalPinToInterrupt(crankshaftReferencePin), CHANGE)

What have you in mind? Maybe you intended attachInterrupt()

I suspect it would make more sense to trigger your interrupts with RISING or FALLING so each pulse only produces a single interrupt

If you just want to temporarily disable or enable an interrupt it will be quicker to change the EIMSK register. It is also good idea to clear the interrupt flag immediately before re-enabling an interrupt in case something had been detected while the interrupt was disabled. The EIFR register is used for that. The details are in the Atmega 328 datasheet.

...R

Oh ok, sorry @Robin2 will not do.
Yeah @blh64 i ment that i understod that the Serial.print lines takes time, not the comment. just badly formulated from me. :slight_smile:

And yes, dont really see what i intended with this line. it quite weird..

if (digitalPinToInterrupt(crankshaftReferencePin), CHANGE)

Went through the code again with a rubberduck, Notic i also connected one led-circuit wrong.
Got the reading side to work like intended with RISING like you said.

const byte IGTPin = 2;   //Interrupt pin for IGT signal from ECU (pin3)
const byte crankPin = 3;  //Interrupt pin for crankshaft reference pin (pin2)
volatile boolean syncAchieved = 0;    //Set this to true if sync has been achieved
volatile byte cylinderCounter = 0;    //Sequence which cylinder should fire (0-1-2-3)
const byte fireOrder[] = {            //Table containing the fireorder (1-3-4-2)
  B00000001,                          // cylinder 1-4
  B00000010,                          // cylinder 2-3
  B00000001,                          // cylinder 1-4
  B00000010                           // cylinder 2-3
};                         


void setup() {
  Serial.begin(19200);               //for debug
  pinMode(crankPin, INPUT_PULLUP);   //Interrupt pin for crankshaft position Use pullup to get rid of dangerous wire break situation
  pinMode(IGTPin, INPUT_PULLUP);
  DDRB = 0b00000011;                 //Set the first 2 pins on the B register to outputs.
  attachInterrupt(digitalPinToInterrupt(crankPin), ISR0, RISING);
  Serial.println("Startup");
}

void loop() {
  // put your main code here, to run repeatedly:
  while (syncAchieved == 1) { //Start sequencing ignition outputs when sync has occured. Otherwise just wait until engine starts rotating.
    PORTB = fireOrder[cylinderCounter];
  }
}

void ISR0()
{
  detachInterrupt(digitalPinToInterrupt(crankPin));              //If sync is achieved, we immedeatly disable keeping track of the position pin permanently
  syncAchieved = 1;                                              //Set variable used to start ignition and disable unnecessary measuring of position pin
  Serial.println("Sync Achieved");                               //Add when troubleshooting
  attachInterrupt(digitalPinToInterrupt(IGTPin), ISR1, RISING);    //We no longer keep track of change state once synced. Now we locate rising change on the ref pin.
}

void ISR1()
{
  if (syncAchieved == 1) {                                        //If we have achieved sync, do only this part of the interrupt
    if (digitalRead(IGTPin) == HIGH) {                        //This is an "unneeded if". It filters out spark EMI, incorrect pulses will be counted otherwise.
      cylinderCounter++;                                      //we sequence the next cylinder that should fire
      Serial.println(cylinderCounter);                        //debug line to see that the right cylinder are shooting
      if (cylinderCounter > 3) {
        cylinderCounter = 0; //This a reset for the cylinder firing sequencer. We have 4 cylinders, so we reset after we reached the final one.
      }
    }
  }
}

For the detach line my intention is to use the syncing pin for the crank once to get it to fire in the right order, i dont think i need to check it again if the rest works correctly. But since a faulty spark can blow my engine up i might be good to check it every revolution?

Now the big question for me is the outputs, that i have set to port B?
I want them to send out a high signal. So when sync is achived i want cylinderCounter for 1 to be high, and after the IGT signal i want it to be low and cylinderCounter for 2 high.

How do i do that? since i got it to rotate correctly for the cylinder, the outputs dont become high.

The high signal of the output will go to a mosfet that awaits the IGT signal and then do the real switching between cylinders.

So from a risk analytic standpoint, do you guys se something in the code or am i missing something that would prevent blowing the engine?
All i have done is INPUT_PULLUP to get rid of a broken/loose connection from the sensors.

//Thanks

ceasarn:
So from a risk analytic standpoint, do you guys se something in the code or am i missing something that would prevent blowing the engine?

I am not prepared to answer that question. The cost of me being wrong would be too high.

The usual thing that damages an engine is running too fast or igniting the fuel too early so that the high cylinder pressure acts to try to reverse the crankshaft.

...R

i understand your reasoning, but i think its all on me for taking this risk of fiddeling with the engine management system.If pre-ignition occurs the engine is easy to find cheap.

I wonder though, is there anyway to stresstest this code? i have calculated that the IGT signal will it occur about 450-500 times per secound at max RPM. Can i calulate/or see if my code can manage that?

Also about the output i ask about earlier, i cant manage to get the output on Port B choosen to become high when engineCounter choose that output. Any advice how to do it smoothly?

//thanks

ceasarn:
i understand your reasoning, but i think its all on me for taking this risk of fiddeling with the engine management system.If pre-ignition occurs the engine is easy to find cheap.

So what if there is a problem in the code ("Im not a good coder ") and a problem occurs when the car is out on the road ?

And as with all car modifications, do remember to inform your insurance company of the modification.

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom... :slight_smile:

ceasarn:
but i think its all on me for taking this risk of fiddeling with the engine management system

Who else would you expect to carry the risk?

If you want someone to take the risk you have to pay him / her an appropriate professional fee. (And by the way, I am not offering to do work for money)

...R

Sorry im not native in english so migth be abit unclear what i mean.

srnet:
So what if there is a problem in the code ("Im not a good coder ") and a problem occurs when the car is out on the road ?

And as with all car modifications, do remember to inform your insurance company of the modification.

That's why i asked about the risk analytic standpoint and i then ment codewise, im a very bad coder so i asked for a viewpoint what migth go wrong with it? The car is a "stubbracer" so i will only be a danger to myself since i drive it on my own dirtroad.

Robin2:
Who else would you expect to carry the risk?

If you want someone to take the risk you have to pay him / her an appropriate professional fee. (And by the way, I am not offering to do work for money)

i was trying to answer your

Robin2:
The cost of me being wrong would be too high.

by implementing that I choose to take the risk by doing this project and wanted to encurage you to speak your mind of what could go wrong without feeling gilty about "cost".

Im not trying to be rude or anything like that i just wanted some help with the code from you guys that probebly are superior coderd.

TomGeorge:
Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom... :slight_smile:

Sure Tom i will try to draw it up correctly! :smiley:

//thanks

ceasarn:
by implementing that I choose to take the risk by doing this project

My mistake - I thought you were complaining about having to carry the risk.

However, even if you are prepared to carry the risk, I'm still not prepared to review your code and say whether it will work and won't cause engine damage.

...R

So @Tom, i was thinking something like this for circuit. Couldn't find at2560 mega but the code posted is adapted to the megas port's.

Couldn't find a hallsensor either so the N is the hall. :roll_eyes:

So the IGT signal will give a 5v pulse, 4 times each revolution of the engine.
The hall sensor will have a tooth and give one signal right before TDC of engine.

So when IGT signal comes, the arduino should have one output high for the mosfet, which will bypass the signal to two cylinders (ex 1-4), the incoming IGT signal in the arduino will then switch output for (1-4) to low and put output (2-3) to high for the next IGT signal. :o

And questionmarks on it? :smiley:

Robin2:
However, even if you are prepared to carry the risk, I'm still not prepared to review your code and say whether it will work and won't cause engine damage.

Understandable! :slight_smile:

I think the risk i quite small for engine damage anyway :slight_smile: , since people have done this COP's swap the engine and fire all 4 coils every time the IGT signal goes. :fearful:

So despite the engine part, how is a good way to make the output high in the squence of fireOrder thats active and after that low?

I just thought that some closure might be good if anyone else who are trying to do this and stumble upon this thread.

Got the engine running with this method and code which is fun.

So the code looks like this:

//Running on a Arduino Nano with TC4468 mosfetchip.

const byte IGTPin = 2;   //Interrupt pin for IGT signal from ECU (pin3) 
const byte crankPin = 3;  //Interrupt pin for crankshaft reference pin (pin2) 
volatile boolean syncAchieved = 0;    //Set this to true if sync has been achieved 
volatile byte cylinderCounter = 0;    //Sequence which cylinder should fire (0-1-2-3) 

const byte fireOrder[] = {            //Table containing the fireorder (1-3-4-2) but for batchfiring.
  B00010010,                          // cylinder 1-4
  B00001100,                          // cylinder 2-3 
  B00010010,                          // cylinder 1-4
  B00001100};                         // cylinder 2-3   

 
void setup() {
  PORTB = PORTB & 0b00000000;        //Clear port's
  //Serial.begin(19200);               //for debug
  pinMode(crankPin, INPUT_PULLUP);   //Interrupt pin for crankshaft position Use pullup to get rid of dangerous wire break situation
  pinMode(IGTPin, INPUT);            // Set IGT as input, goes high when spark occure
  DDRB = 0b00011110;                 //Set the 12-8 pins on the B register to outputs.
  attachInterrupt(digitalPinToInterrupt(crankPin), ISR0, RISING); //Setup so the code waits for crankpin sync.
  //Serial.println("Startup");
}

void loop() {
  // put your main code here, to run repeatedly:
    while(syncAchieved == 1){  //Start sequencing ignition outputs when sync has occured. Otherwise just wait until engine starts rotating.
        PORTB = fireOrder[cylinderCounter];} //Keep the nexy cylinder port's high until IGT signal then switches.
}
}

void ISR0()
{
   detachInterrupt(digitalPinToInterrupt(crankPin));              //If sync is achieved, we immedeatly disable keeping track of the position pin permanently
   syncAchieved = 1;                                              // Set that sync has achived for mainloop.
   cylinderCounter = 0;                                           //Prime the first 1 and 4 cylinder to fire for the next IGT signal.
   //Serial.println("Sync Achieved");   
   //Serial.println(cylinderCounter);
   attachInterrupt(digitalPinToInterrupt(IGTPin), ISR1, HIGH);    //We no longer keep track of this since it have sync with cylinder 1 and will count. (be good to implement a check to see if sync is correct though)
 }

void ISR1()
{
  if (syncAchieved == 1) {                                       //If we have achieved sync, do only this part of the interrupt
        if(digitalRead(IGTPin) == HIGH){                          //This is an "unneeded if". It filters out spark EMI, incorrect pulses will be counted otherwise.
          PORTB = 0x00;                                           // Set output's to low before switching.
          cylinderCounter++;                                      //we sequence the next cylinder that should fire
          //Serial.println(cylinderCounter);                       //debug line to see that the right cylinder are shooting
          if (cylinderCounter > 3){cylinderCounter = 0;}          //This a reset for the cylinder firing sequencer. We have 4 cylinders, so we reset after we reached the final one.
   }
  }
 }

note

Still have some minor issues:
Coil's are all able to spark during startup on Arduino (prob not a problem.)
Seems to not be changing the output fast enough at high rpm(simulated high rpm), get a bleed through of the the mosfet's that are suppose to be low. (can be hareware problem aswell) Orderd a PCB so might solve it.

IF you are doing this with a Toyota the IGF signal can be solved with a diode transistor circuit.

And finally thanks for those who helped me.

:smiley:

Hi,
You have shown the code, now the final circuit diagram would be great.

Thanks.. Tom.. :slight_smile: