advice needed for arduino as diesel injection brain...

cyclegadget:
It is easier for me to write a sketch to show how a return works

Given that the sketch was written to demonstrate the use of return, it's ironic that your sketch ignores the return value.

PeterH is correct, I did not write the sketch properly. I need a signature under my avatar that says "Warning Novice on board!" .

I rewrote the return sketch, I think it is correct this time. Sorry for the mistake I made earlier.

const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int DonesAnswer = 0;           // variable to pass "done" to         

long previousMillis = 0;        // will store last time LED was updated

long interval = 1200;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);   
  Serial.begin(9600);  
}

void loop()
{

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval)
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

   DonesAnswer = whatdonedoes();   // transfer "done" to DonesAnswer using the function

    Serial.print("done = ");
    Serial.println(DonesAnswer);

    digitalWrite(ledPin, DonesAnswer);
  }
}

////////////////////////////////function with a return called done//////////
int whatdonedoes()
{
  static int done = 0;  //set done to static int

  // if the LED is off turn it on and vice-versa:
  if (done == 1)
    done = 0;
  else
    done = 1;

  return done;
}

Nice signature :wink:

However I got the point about the done in this case. (in bash I use it to halt or continue script so this case was new to me)

I did some test with the program, added several "timestamps" and at the end of the loop printed them all. (to prevent serial prints to slow down things)
Very disturbing is the fact that reading analog and writing to pwm takes over 200uS, if this delay happens at the wrong point my injection timing will be 5-10 degree to late or even worse if that happens while injecting it can mean 20-30% more diesel which melts my pistons.
400HP+ with a 4 cylinder 2.0l diesel is a bit on the edge, with 200cc diesel per 1000 injections it will run around 1000 degree Celsius and the pistons will melt at 1100... (with 160cc 800 degree)

To wrap it all together; running a loop and take action based on interrupt created flags inside that loop isn't gonna work since injection moment and duration are both time critical give or take 10uS. (20 total)

So back to my first plan (disapproved by every coder around the world :wink:

A loop that checks and set stuff, throttle, pump pressure, idle, rpm limiter etc.
Interrupts that open injector, wait injection time and close it. (during that time the loop is stalled but who cares)
connect timer to throttle so advance is manually controlled. (0 at idle, -45 at full load)
Main thing is that the time critical functions (opening and closing injectors) are interrupt driven, all other stuff can have some delay the only result of that can be that throttle feels a bit sloppy at high rpm (when times between interrupts get shorter) but in that case I was all ready holding on to my wheel and praying...

japie:
Interrupts that open injector, wait injection time and close it. (during that time the loop is stalled but who cares)

As well as being ugly, I'm not at all convinced that you will get it to work. What would IMO be far better would be to use the timer interrupt to start the injection and at that time configure a timer to trigger another interrupt when the injection needs to end. This way the real time part of your code runs with minimal latency and does not lock the processor up for the duration of the injection, and the background processing in loop() can run and do whatever it needs to. Just ensure that you don't do anything that disables interrupts.

I have been searching for some solution to replace the delay and found Arduino Playground - Timer1

Was thinking about the interrupt opening the injector and starting a timer, the timer does the closing so I suppose you where thinking the same.

shot in the dark:

attachInterrupt(18, Inject1, RISING);

void Inject1()
{
  // calculate how many uS 180 degrees last
  TimeFrame = (micros() - TimeOld);
  TimeOld = TimeFrame;
  // open injector1
  digitalWrite(inj1,HIGH);
  // start timer1
  Timer1.initialize(ThrottleDuration);
  Timer1.attachInterrupt(Close1);
}

void Close1()
{
  // close injector1
  digitalWrite(inj1, LOW);
}

Only I don't think I can share the timer between all 4 injectors but since I use the mega it seems I have 3 extra ones so 1,3,4 and 5 are all 16 bit.
From the docs timer0 is used for millis, micros, delay and PWM pin13 (my pump pressure output) so I won't touch it.

Does something like above work or am I ready for mental care? :wink:

japie:
Only I don't think I can share the timer between all 4 injectors

If you have an even firing engine then you could just generate the interrupt at the total injection frequency rather than the per-cylinder frequency, and cycle through the cylinders in the appropriate order.

I've missed/forgotten how you're going to synchronise the injection with the engine physical position. Do you already have the crank position and engine phase sensing sorted out? Presumably you'll have some sort of phase locked loop tracking where (you think) the engine is.

@japie

Could you post the code that you used to find this

Very disturbing is the fact that reading analog and writing to pwm takes over 200uS,

I am not saying your wrong but, I can bench mark the Uno, Teensy 3.0, and the Due for comparison. I also have a Maple clone but, it is not as easy for me to put it to good use.

With some clever coding and dividing those 2 actions the times can probably be brought down but the main issue is that the time critical stuff is done in the loop, it should be real time...

The injection moment is in sync with the engine trough an alternator, I have a pcb with 4 IR transmitters on it and one with 4 receivers, between those there is a rotating plate with a little hole so at every TBP one of the receivers gets a pulse.
The casing with the PCB's in it can be attached to the throttle to create more advance when giving more throttle. (the above system has been used in the past by me and works flawless)
Nothing fancy, if receiver1 gets a pulse injector1 has to spray.

japie:
The injection moment is in sync with the engine trough an alternator, I have a pcb with 4 IR transmitters on it and one with 4 receivers, between those there is a rotating plate with a little hole so at every TBP one of the receivers gets a pulse.

I don't know what a TBP is. When you say alternator, do you mean the alternator that provides electrical power for the vehicle? How is that connected to the crank?

CrossRoads:
For sure there are only 2 External Interrupts.
But almost every pin also supports PCINT, whichNick Gammon has a great page on and even shows them as being a little faster:
Gammon Forum : Electronics : Microprocessors : Interrupts

Nice link, thanks. Just nit-picking, but I believe that Timer1 Capture is also an external interrupt pin, making for a total of 3.

@cyclegadget

I did timings by adding stuff between lines like:

int readthrottle = micros();

and at the end of the loop print all of them in one line, substracting manually gave me the readings...

@PeterH

Sorry 4 misleading you, I am pretty busy with labour so most of the time I do computer stuff early in the morning before going to work.
I meant TDP or TDC: Top Dead Center, when the piston is in it's most uprising/compression point.
Also I don't mean alternator but distributor.
So I can give an electronical pulse at exactly the moment I want to inject, in the past I used almost the same setup with an NE555 as timer for injection duration but since I got involved with the arduino while building a data logger I thought it was a nice idea to use it for injecting.
In my old setup the distributor :wink: was connected to the throttle so when giving more throttle the timing would advance from -10 to -50 degree TDP.

Actually there is nothing wrong with that, in my current conventional plunger Bosch A-pump I modified the plungers by grinding the top in an angle and the helix flat so when giving more throttle injection moment will advance. (normally the top of the plunger is flat, halfway down there is a groove in an angle (the helix) that is connected via another groove to the top, when the plunger moves upwards the helix will pass a hole and bleeds fuel from the top so at that point the injection stops. Since that helix is under an angle you can turn the plunger so the effective stroke of the plunger is extended and therefore delivering more fuel. http://transportation.centennialcollege.ca/oduffy/fuels/HD%20fuels%203/inline.pdf)

@afremont

The other timers also all connect to a pin so that would mean they are not useable.
When looking at the example code it looks like the timers can be used without using the pin attached to it, no clue.
Also no clue how to use the other 3...

If I can't find out I will use a microsecond delay, bad coding leaving the arduino doing a lot of nothing but see no reason why it should not work.

Hello there, got the basic timer code working:

#include "TimerOne.h"
#include "TimerThree.h"

int ledPin = 13;
volatile int state = LOW;
volatile int InjectionCycle1  = false;

void setup() 
{
  pinMode(ledPin, OUTPUT);
  attachInterrupt(0, Inject1, RISING); // interrupt 0 = pin 2
  Timer1.initialize(1000000);
  Timer1.stop(); //stop the counter
  Timer1.disablePwm(9); // disables PWM on pin 9
  Timer1.disablePwm(10); // disables PWM on pin 10
  Serial.begin(9600);
}
 
void loop()
{
}

void Inject1()
{
  if (InjectionCycle1 == false)
  {
    Serial.print("start injection cycle: ");
    Serial.println (millis());
    InjectionCycle1 = true;
    Timer1.setPeriod(1000000);
    Timer1.attachInterrupt(OpenInjector1);
  }
}

void OpenInjector1()
{
  if (InjectionCycle1 == true)
  {
    Serial.print("open injector: ");
    Serial.println (millis());
    digitalWrite(ledPin, HIGH);
    Timer1.stop();
    Timer1.detachInterrupt();
    Timer1.setPeriod(2000000);
    Timer1.attachInterrupt(CloseInjector1);
  }
}

void CloseInjector1()
{
  if (InjectionCycle1 == true)
  {
    Serial.print("close injector: ");
    Serial.println (millis());
    Serial.println ("");
    digitalWrite(ledPin, LOW);
    InjectionCycle1 = false;
    Timer1.stop();
    Timer1.detachInterrupt();
  }
}

Tested this and it works as expected, next step integrate all other stuff, will port when I have it complete.
In this setup the timer replace delay. (and is not stalling the loop like delay)

edited since in first instance I used Timer1 and Timer3 both for both delays:
Using one timer for the cycle works also good so I can use Timer1 for cylinders 1 and 4 and Timer3 for cylinders 2 and 3.
Since the firing order is 1-3-4-2 there is 180 crank degree extra time between interrupt firing cycles, better would be a per cylinder dedicated timer but rewriting the Timer1 code for the extra timers on the mega is out off my league...

Finished the total code for the injection system based on 2 timers.
Included idle revving, soft rpm limit for over-revving and hard rpm limit in case of driveline breakage.

cuprumV2.ino (10.7 KB)

Japie, where did you download the timerone and timerthree libraries?

I was wanting to do some testing with your code but, I think maybe I am missing the correct library.

I am glad you have been sticking with your project and making it work!

Also, I want to say that you should speed up your serial baud rate to 115,200, which is the maximum that the IDE can use. If you have a terminal program, you maybe able to choose a much higher rate. Serial communication can really hurt the performance of your sketch. I will make a sketch to show you the difference. I will post it here soon.

Test code using 9600 baud:

int ledPin = 13;

//variables to keep track of time of injection code////
unsigned long time1 = 0;
unsigned long time2 = 0;


void setup() 
{
  pinMode(ledPin, OUTPUT); 
  digitalWrite(ledPin, LOW);
  Serial.begin(9600);
}

void loop()
{

  digitalWrite(ledPin, HIGH);
  time1 = micros();
  Serial.print("light the LED for all to see! ");
  Serial.println(time1);

  Serial.print("Turn off the LED it does not need to be ");
  digitalWrite(ledPin, LOW);
  time2 = micros();
  Serial.println(time2);

  Serial.print("total time = ");
  Serial.print(time2 - time1);
  Serial.println("micros");
  delay(5000);  
}

Typical output in micros():

light the LED for all to see! 35358256
Turn off the LED it does not need to be 35373908
total time = 15652micros

Using 115200 baud:

light the LED for all to see! 35029036
Turn off the LED it does not need to be 35030356
total time = 1320micros

Removing all but total time print, code:

int ledPin = 13;

//variables to keep track of time of injection code////
unsigned long time1 = 0;
unsigned long time2 = 0;

void setup() 
{
  pinMode(ledPin, OUTPUT); 
  digitalWrite(ledPin, LOW);
  Serial.begin(115200);
}

void loop()
{
  digitalWrite(ledPin, HIGH);
  time1 = micros();

  digitalWrite(ledPin, LOW);
  time2 = micros();

  Serial.print("micros = ");
  Serial.println(time2 - time1);

  delay(5000);  
}

results:

micros = 12
micros = 12
micros = 8
micros = 8
micros = 8

Hi cyclegadget,

The timer libs came from the playground: Arduino Playground - HomePage

I know about the serial port speed but I have an arduino data logger spitting out it's reading true the serial port to my FriendlyARM dashboard.
The arm reads the serial port with a bash script (simple cat) and writes the data on the screen, when using 115200 I ran into problems on that so I stepped back in speed and somehow kept that for other projects...

If all works out well I remove the serial stuff completely...

japie:
Hello there, got the basic timer code working:

#include "TimerOne.h"

#include "TimerThree.h"

int ledPin = 13;
volatile int state = LOW;
volatile int InjectionCycle1  = false;

void setup()
{
  pinMode(ledPin, OUTPUT);
  attachInterrupt(0, Inject1, RISING); // interrupt 0 = pin 2
  Timer1.initialize(1000000);
  Timer1.stop(); //stop the counter
  Timer1.disablePwm(9); // disables PWM on pin 9
  Timer1.disablePwm(10); // disables PWM on pin 10
  Serial.begin(9600);
}

void loop()
{
}

void Inject1()
{
  if (InjectionCycle1 == false)
  {
    Serial.print("start injection cycle: ");
    Serial.println (millis());
    InjectionCycle1 = true;
    Timer1.setPeriod(1000000);
    Timer1.attachInterrupt(OpenInjector1);
  }
}

void OpenInjector1()
{
  if (InjectionCycle1 == true)
  {
    Serial.print("open injector: ");
    Serial.println (millis());
    digitalWrite(ledPin, HIGH);
    Timer1.stop();
    Timer1.detachInterrupt();
    Timer1.setPeriod(2000000);
    Timer1.attachInterrupt(CloseInjector1);
  }
}

void CloseInjector1()
{
  if (InjectionCycle1 == true)
  {
    Serial.print("close injector: ");
    Serial.println (millis());
    Serial.println ("");
    digitalWrite(ledPin, LOW);
    InjectionCycle1 = false;
    Timer1.stop();
    Timer1.detachInterrupt();
  }
}




Tested this and it works as expected, next step integrate all other stuff, will port when I have it complete.
In this setup the timer replace delay. (and is not stalling the loop like delay)

edited since in first instance I used Timer1 and Timer3 both for both delays:
Using one timer for the cycle works also good so I can use Timer1 for cylinders 1 and 4 and Timer3 for cylinders 2 and 3.
Since the firing order is 1-3-4-2 there is 180 crank degree extra time between interrupt firing cycles, better would be a per cylinder dedicated timer but rewriting the Timer1 code for the extra timers on the mega is out off my league...

When I want to run this, I get: Timer1 was not declared in this scope.
I'm very new to arduino and elektronics, sorry.

And Japie I found more stuf injectors and pump. I even have a pump and four of the six injectors, aextra Uno an a Mega to start with.

Panther95

Hello Panther, did you install the timer libs?

For this project you need a mega and lucky you it seem to have 6 hardware interrupts so you should be good.
Must say that I am not sure at all it will work, currently I finished my output dirver board (the 4 injector drivers and 1 PWM output for the pump pressure) but the PWM doesn't work. (the arduino does drive PWM but I made an error on the PCB)

Got my tiny automotive pump connected to an 0,75Kw motor but when making pressure it stalls (so the pump will ask for over 2HP I think) I will set it up in my lathe which should be powerfull enough.
Since the PWM doesn't work I use a car battery and some big fat resistors to control pump pressure, from the past I know that with 3V it delivers about 600bar and with the full battery load (13.8V) over 2300bar.

Also have some trouble with the injectors, they have been laying in stock for 2 years and they are jammed despite being filled with diesel. (hardware troubles it is, got one going now, will open them this weekend I suspect the diesel has turned into grease :wink:

The arduino addon hardware I am making in Fritzing, one output board and one input board, when both finished and working I will post the files here to, OK?

@Panther
@anybody_else, sorry for being off-topic in an arduino forum...

Found some documentation about the parts I use for the PSA 2.0Hdi engine (RHY type) with Bosch CR system:

Pump CR/CP1S3/R65/10-16S
According to a benchmark from a pump testing/overhauling company this pump delivers; 1350bar@2000rpm - 1200cc/min. In conventional pumps we speak off cc. injection amount per 1000 injections so assume we run 1000 rotations so the pump delivers 600cc.
Since we have a four stroke four cylinder that means that one pump rotation we have to feed 4 cylinders, 600/4=150cc per injector at 1000rpm but that means we have to inject 90 pump degrees/180 crank degrees to get it all in.

A bigger one is: CR/CP3S3/L110/30-789S: 1350bar@2000rpm - 2000cc/min. (AUDI 4.x/Iveco/Mitsubishi/MAN/Sisu)

Also found scope readings from the injectors:
@idle 200uS pre-inject, 2.2mS wait and 400uS main injection.
@3000rpm one injection 400uS
So it seems in automotive use we don't use injection duration for power...

And scope readings from the pump PWM (1khz):
@2000rpm 25% duty cycle
@3000rpm 35% duty cycle
Accelerating 45% duty cycle
Which is also strange, one would expect 100% when power is needed.

It seems all knowledge gathered with conventional injection is off, I know I inject 160cc. currently over 35 degree crank duration. (45btdc till 10btdc)

Wrote a test program with timer pulses relative to pump rpm (must see first how strong/fast my lathe is with the pump attached) that injects 1000 times 500uS with PWM@50% and will collect the amount of fuel while monitoring pump pressure sensor..

If someone takes offense about me posting arduino-irrelevant information please let me know... (but from my point of view it belongs to the "package" and maybe someone not familiar to diesel injections creates a new and fresh point of view)