Can I use analogwrite inside an ISR()?

You say that the injection pulse must start within +/- 500µsecs of the ideal time (or +/- 250µsecs if I have misunderstood Reply #27).

In either case that is a wide margin that will be easily achieved by an Arduino.

As @MorganS has said in Reply #32 the trick is to organize your code so that the other tasks take place during the non-critical time. For example if the ISR is triggered at PMS/TDC and the injection pulse must start 200 degrees (of crankshaft angle) later then the period of time between TDC and TDC + 180 degrees can be used for other things.

Another option that I have used (my project was nothing to do with an engine) is to use the ISR at TDC to start a HardwareTimer that will generate a different ISR at the time that the injection pulse must start.

That brings to mind something that I don't think has been touched on - you should think of your actions always happening one revolution in arrears. In other words all the measurements and calculations you do during Revolution X will be for the purpose of the actions (injection timing and injection duration) in Revolution X + 1. When TDC is reached at the end of Revolution X you will already know the values needed for when the injection should start and how long it should be.

...R

TDC is the most compressed. Short of a spark it is the high heat, the full heat content of the air-fuel charge is in the smallest volume it will be. The temperature probe will get the temperature of what it's mounted in and/or the fuel-air mix?

Another option that I have used (my project was nothing to do with an engine) is to use the ISR at TDC to start a HardwareTimer that will generate a different ISR at the time that the injection pulse must start.

I'm still uncertain if the timing pulse begins before, after, or the same time as the TDC interrupt. It is certainly possible to use the two output compare interrupts of a timer to start and stop a pulse during a cycle.

It maybe a little late in this process for Fabious_rex to switch gears from a software to a hardware timer approach. Since accuracy/precision does not appear to be the central issue, the change might bring more complexity than its worth.

If the task is just to turn on an output for an amount of time beginning when a TDC pulse is received, the TimerOne library might be useful, but again its not clear to me if the resolution of using micros() in a software timer is the key issue here.

GoForSmoke:
TDC is the most compressed. Short of a spark it is the high heat, the full heat content of the air-fuel charge is in the smallest volume it will be. The temperature probe will get the temperature of what it's mounted in and/or the fuel-air mix?

The temperature meassured is the one of the admitted air. With that using ideal gas law I calculate how many grams of fuel do I need.

MorganS:
I would try to push as much as possible out of the parts that are timing-critical.

Temperature, for example, should be measured after all the timing is done, so that the new value is available to the next cycle.

So I just put the function calculating temperature at the end of the loop (easy as that?)

GoForSmoke:
Can't you pre-calculate for each of those possible read values, 0 to 1023. the number of microseconds that results? Then table them in flash memory, 16 bit unsigned int would work using only 2K flash taking 6 cycles per value to fetch. The read value x 2 is the offset into the table where the answer is pre-stored. Or would you rather spend many 100's of cycles calculating with floats on an 8 bit cpu with no fpu to get the same thing?

Tabling was a fact of life if you wanted fast code before computers got really big and fast.

YES table lookup for known RPM and density stage will be my next step. But as said before I have lije 3 months of arduino experience and my first project was to make arduino "sing" the super mario bros and the Imperial March with a PC buzzer, then jumped right to a E.F.I
"Jarvis, sometimes you gotta run, before you can walk. Tony Stark"

Since a child I´ve always loved electronics and tinkering, tearing apart my toys, and I have diplomas at car mechanic and E.F.I inyections (the best part of the course) and object oriented programming. That is why some things I get the knack pretty fast, others I don´t

Being considering saving in the eeprom the lookup table in the future, that´s right, but first I need to understand and reason through experiencie simpler tasks.

Robin2:
You say that the injection pulse must start within +/- 500µsecs of the ideal time (or +/- 250µsecs if I have misunderstood Reply #27).

In either case that is a wide margin that will be easily achieved by an Arduino.

As @MorganS has said in Reply #32 the trick is to organize your code so that the other tasks take place during the non-critical time. For example if the ISR is triggered at PMS/TDC and the injection pulse must start 200 degrees (of crankshaft angle) later then the period of time between TDC and TDC + 180 degrees can be used for other things.

Another option that I have used (my project was nothing to do with an engine) is to use the ISR at TDC to start a HardwareTimer that will generate a different ISR at the time that the injection pulse must start.

That brings to mind something that I don't think has been touched on - you should think of your actions always happening one revolution in arrears. In other words all the measurements and calculations you do during Revolution X will be for the purpose of the actions (injection timing and injection duration) in Revolution X + 1. When TDC is reached at the end of Revolution X you will already know the values needed for when the injection should start and how long it should be.

...R

Yes I´m always one revolution behind schedule. But since this is a single inyector fuel, the mixture is really being "flooded" inside the admission collector until the next available cylinder enters in the admission state. Once I have everything operational and understood I can start making upgrades

cattledog:
If the task is just to turn on an output for an amount of time beginning when a TDC pulse is received, the TimerOne library might be useful, but again its not clear to me if the resolution of using micros() in a software timer is the key issue here.

That´s exactly it. I shall see the timer library. Thanks!

GoForSmoke:
TDC is the most compressed. Short of a spark it is the high heat,

The spark will have happened a considerable time before TDC.

...R

Here is the wiring diagram of the Injection System

and this is currently my rig

Can you please provide a drawing of a timing diagram which shows the relationship between the TDC signal and the output turning on and off? How will this then change at different RPM?

Thanks.

cattledog:
If the task is just to turn on an output for an amount of time beginning when a TDC pulse is received, the TimerOne library might be useful, but again its not clear to me if the resolution of using micros() in a software timer is the key issue here.

For a 500 usec wide time tolerance? Micros() granulatity is 4. The window is 125x as wide.

Robin2:
The spark will have happened a considerable time before TDC.

...R

And from another view the spark happens after "a" TDC. You want to fire after the piston starts moving down or you get knock.

It's fire every other TDC with a 4-stroke engine and all times are relative. How long since the last TDC matters because you can know when the shaft is at TDC. That's a known absolute place and time to measure varying events against, as what else have you got?

Fabius_rex:
Yes I´m always one revolution behind schedule. But since this is a single inyector fuel, the mixture is really being "flooded" inside the admission collector until the next available cylinder enters in the admission state. Once I have everything operational and understood I can start making upgrades

The injector runs constant when the engine runs constant? It is not timed to the piston?

GoForSmoke:
And from another view the spark happens after "a" TDC. You want to fire after the piston starts moving down or you get knock.

Sorry, but that is not correct. The spark fires some time before TDC on the firing stroke so that the fuel has time to ignite and build up pressure. The faster the engine runs the earlier (in terms of angle before TDC) the spark must fire because the flame propagation works at approximately the same speed.

If the spark ignites the fuel too soon then you will, of course, get knock. But if it were not to happen until TDC them much of the fuel would still be unburned when the exhaust valve opens.

And, of course, the ignition before TDC is after TDC-1, for example 35deg before TDC is 325deg after TDC-1. Which is why I referred in Reply #33 to things happening one revolution in arrears.

...R

I was under a wrong impression.... spark advance.. right from back when... it's been just a while. Do new engines knock?

The spark is going to be after the last reference measure, so unless there's a way to advance the sensor it is "a" TDC event.

If you only exactly know when it's noon, then one day to the next, morning follows noon. It's just a clock reference for cyclic activity.

Added:
I'd want more reads per rev. I'd want enough to follow changes in rpm during a turn of the wheel if timing means positioning. 1 sensor picking up holes/slots/teeth turning by can add greatly to the outcome simply by shortening the time between a sensed reference and when the spark fires there is less time to change.

Fabius_rex:
Being considering saving in the eeprom the lookup table in the future, that´s right, but first I need to understand and reason through experiencie simpler tasks.

The table gets put in the flash along with the program. Uno has 32K flash and typical programs are 2K to 8K.
Search Arduino for PROGMEM. You can put all your messages, help text, labels and prompts in flash and print directly from there and save RAM using the print F() macro.

Serial.println( F( "This text does not use RAM, it's stored in flash." ));

Constant data and tables are better done with PROGMEM.

Arduino is GCC (C++) at heart. Just avoid dynamic allocation, String and Containers that copy themselves to grow. It's best to make your own that behave in C fashion. The difference is which fits small RAM better, that's C.

GoForSmoke:
Added:
I'd want more reads per rev. I'd want enough to follow changes in rpm during a turn of the wheel if timing means positioning. 1 sensor picking up holes/slots/teeth turning by can add greatly to the outcome simply by shortening the time between a sensed reference and when the spark fires there is less time to change.

I'm not convinced that more reads per rev would offer any significant improvement - injection timing (as opposed to quantity/duration) is probably a lot less critical than ignition timing.

...R

When accelerating or braking, timing changes. The longer the timed period the more a simple calculation can be off, this is a matter of reducing sensor lag to directly improve output precision, get that +/- window put closer to the right place to begin with. How many RPM can a wheel change in 1 full revolution? How good are your brakes and power to weight?
With a short enough arc, possible error from unaccounted acceleration becomes small.

You could watch the change between TDC reads and the change in the change as digital derivatives to better predict spark timing during RPM change but it's still a bit blind.

GoForSmoke:
When accelerating or braking, timing changes. The longer the timed period the more a simple calculation can be off, this is a matter of reducing sensor lag to directly improve output precision, get that +/- window put closer to the right place to begin with.

IMHO the response of a big heavy thing like an engine with a flywheel and (if it is powering a vehicle) the mass of a vehicle is many many times slower than the the precision that can be achieved with a microprocessor.

Taking account of changes in speed from one revolution to the next should be more than sufficient.

...R

From driving cars and bikes, acceleration from 3000 to 4000 RPM can happen in a very short time. That's 50 turns per second to 67, 20000 us down to 15000 us to place a certain 500 us wide spark window. The margin of change is much bigger than the tolerance when you have to time spark from last TDC.

A task that watches the changes to keep 1st to 3rd order change effects wouldn't take many cycles.

1st order as the difference between the current TDC-TDC time and the last time.
2nd order being the difference of 1st order current and last
3rd order to track 2nd order difference.

Here I can't be sure but you might just be able to add them up without factoring anything to get a predictive timing offset.

Think of it as really cheap digital calculus.

What I should have said in Reply #48 is that the project will work very well with a single pulse per revolution and when that is working the OP could experiment with additional pulses to see if it improves the performance. Keep things simple to start with.

...R

Hi had a busy Monday so couldn´t read the post.

First, I´m very happy that you guys took the discussing thread furthermore and are taking new and your own conclusions.

Since last discussed I think I´ve got a little problem with the inyector pulse variable.

But first let me clear a question.

The original TDC pulse (4 per rev, as 4 cylinders and SINGLE injector) uses not a HALL effect (as my CPU FAN for tests) but it uses magnetic inductance. And the sensor is inside the distributor. Hence if you give the distributor 10° BTDC (before Top Dead End) you have some fixed advance to spark and injection to start.

However, the H.E.I module below 450 R.P.M (cranking) uses the induction pulses from the pickup coil to fire the spark (and sends a RPM pulse to the E.C.U to start the injection)

After the engine surpasses the 450 R.P.M, the E.C.U sends a HIGH signal through pin B of the H.E.I in order to command it to stop controling spark timing (hardware fixed by 10° BTDC) and then, it will be the E.C.U that through pin E of the H.E.I will send the pulses to control the NPN transistor inside the H.E.I module to cut the coil.

The TDC signal is a ramp up ramp down with max positive and min negative.
In the positive part, is when the piston starts getting close to TDC. the maximum positive amplitude is whe it has reached that.
Then the signal drops to the negative part, wich means that it´s leaving TDC and the piston is getting lower.

Original in the E.C.U and H.E.I documentation it´s said that the spark timing happends sometime after TDC (when the signal changes from MAX to MIN and after it crosses 0). (remember that it will never be less than 10° BTDC because of fixed distribuitor position.

Returning to my doubt.

If have a function that calculates how long the pulse for the injector needs to be HIGH.

unsingned long int PULSE_INY; // Time in micros that the injector needs to be opened, calculated through constant polling of 3 sensors

then
unsigned long PULSE_INY //Calculated in micros through polling sensor data
unsigned long lastInj;

if (micros() - lastInj >= PULSE_INY)
{
//Inyector pulse goes HIGH
micros() = lastInj;
}
else
{
//injector pulse goes LOW
}

But, for each loop when if, checks elapsed time >= TI, if TI is contantly being calculated through polling, wouldn´t this mean that in each pass it can change several micros, thus making innaccurate the time the pulse goes high?

I think that to circumvent this issue I will poll the sensor data, but only calculate PULSE_INY inside a function that will be trigger from a flag set in the ISR()

So
//Variables
bool PMS = false;
unsigned long INY_PULSE; // used in funcionCalculate.... The amount of time the Injector needs to be HIGH
unsigned long lastINY; //Comparative time variable
//Variables

ISR pulse_rpm()
{
bool TDC = true;
}

void loop
{
if (PMS == true;)
functionCalculate_Injector_Pulse; //Returns injector pulse var

if (micros() - lastINY >= INY_PULSE)
{
//Inyector HIGH
micros() = lastINY;
}
else
{
//INYECTOR LOW
TDC = false;
}

Don´t ,mix TDC variable with top dead cylinder. the TDC = true, does mean that the piston is 10° before TDC, but the window in the coding in wich TDC var goes from high to low is just figurative

What do you guys think?

Thanks in advance

Quick update

I need to calculate the time the inyector goes HIGH only once between PULSES (from 33ms to 6ms)

I don´t need to calculate the time in the loop, because for example

For example:

If the arduino micro processor took 1us to complete a loop pass.

And my function calculated that the Inyector pulse needs to be from 800 to 1500 uS

if the funcion is

INY_PULSE = 1000 //uS, last store calculation from CalculateINY()

if (TDC = true)
{
if (micros() - lastIny >= INY_PULSE).
CalculateINY();
digitalWrite(INYPIN, HIGH);
micros() lastIny;
}
else
{
digitalWrite(INYPIN, LOW);
TDC = false;
}
}
So, what happends when the last stored time in loop 1 (one pass = 1us) was 1000us

But in the loop 750 (750 passes = 750us) now the value is 600? Wouldn´t this break the function´s conditional?

That´s my doubt

That´s why I think that instead of IF the function controlling the inyector pulse needs to be a while, So I calculate the time outside the trigger of the inyector, then set a while condition that until that time is not up don´t do anything else.

Again, my windows are from 33ms to 5ms
And my inyector pulse will be no longer than 1500 microseconds

In the worst case scenario, that leaves me with 3500 microseconds for polling data at 7200 rpm (speed at wich the engine will never be used but it´s its tops)

Any suggestions?