while() and micros() and Freaking out

I need help. I get this weird thing happening. Whenever I divide by 2 or smaller, the Arduino freaks out, but when I use 2.25 and bigger, program works like a charm. (Highlighted field) And here is the funny thing. If I use a know value for dt, like 120000, it will work perfectly, but when I find dt using the code bellow, it will freak out. both dt would be same, cause I set my other arduino to produce 120ms pulse, 4ms high, 116ms low, similar to my engine running ~1000RPM and my cam sensor going off.

I use While instead of delayMicroseconds to increase my precision. with While, it keeps timing on the dot, with delayMicroseconds it jumps around too much.

This program is meant to keep up timing on my project. It has 3 identical parts. The period of the window is ~200ms to max 30ms. I cannot really use millis since I need to have high precision on my spark.
Spark happens almost at the same time interput happens.
My fuel injection happens about half way point.
My air injection happens about 3/4 of whole period.

I have to have high precision on spark.

Oh yes, it is ECU that I am working on for my project. Its a Air Assisted Direct Injection ECU for a single cylinder engine, max 4000 RPM. More info on the project: polysae.poly.edu/

Program, this is only 1/3 of the code. Rest of the code is copy and paste with the highlighted field below number 2:

volatile int rpmcount = 0;
unsigned long timecycle = 0, timecycle2 = 0;
long dt,temp;

const byte SparkPlugPin = 13;
const byte AirValvePin = 4;
const byte FuelValvePin = 5;

void setup()
{
Serial.begin(19200);

attachInterrupt(1, contactbreaker_fun, RISING); //pin 3

pinMode(SparkPlugPin, OUTPUT);
pinMode(AirValvePin, OUTPUT);
pinMode(FuelValvePin, OUTPUT);

digitalWrite(FuelValvePin, LOW);
digitalWrite(AirValvePin, LOW);
}

void loop()
{
if ((rpmcount >3) && ((micros()-timecycle)>30000))
{
timecycle2 = micros();
dt=(timecycle2 - timecycle);
temp=timecycle2+dt/2.5;
timecycle = timecycle2;

do{ }
while (temp>micros());

digitalWrite(SparkPlugPin, HIGH);
delayMicroseconds(2000);
digitalWrite(SparkPlugPin, LOW);

rpmcount = 3;
}

}
void contactbreaker_fun()
{
rpmcount = rpmcount+1;
//Each two rotation, this interrupt function is run once
}

If it's safe to say dt will always computer a positive number, I would define dt and temp as unsigned long.

I didn't work out how all of your timing is done, or what means what... but this line:
temp=timecycle2+dt/2.5;

will divide dt by 2.5 or 2.0 or whatever first. That result will be stored in temp, and then timecycle2 will be added to it. All I can say is just think about that and how it might break something. I have no idea if that's it or not.

I am going to try assigning both unsigned long again, there where before.

if I devide by 2.0 or just 2 it freaks out.

dt would be 120000 under my testing, If I sub dt with 120 000 it works perfectly and problem is gone. Something in units.

BrettW was on the right track, but not close enough.

All the variables in the problem line are integer. The constant is not. Since the result is an int, integer arithmetic is performed. You will need to add some casts in that line to get floating point arithmetic performed. But, that will slow things down.

Alternatively, you could multiply by 2 and divide by 5, instead.

Paul, in his orginal problem he stated the problem was occuring when he divided by 2, not 2.5.

So I read this at 1:00 AM. Not quite awake, then.

Yeah, I think the overflow is a likely cause of the problem. I’m still concerned about the integer arithmetic, though. I’d want to cast stuff to assure floating point arithmetic was used, or eliminate the need for it.

Wish I could test this right now, but I've tried casting to float before and haven't had much luck with that. Would it be better to declare dt as float?

I'd say your idea of multiplying by multiplying by 2 and dividing by 5 is a great alternative to div by 2.5, however it seems like he wants this number to be variable?

kakarot, can you please explain what this code is for, i.e. how often is rpmcount > 3, what's timecycle 1 and 2 used for, what's the 2.5 supposed to be (just 2 or variable?) and what the timing in general is supposed to be as it relates to these variables?

 if ((rpmcount >3) && ((micros()-timecycle)>30000))
 {
   timecycle2 = micros();
   dt=(timecycle2 - timecycle);
   temp=timecycle2+dt/2.5;
   timecycle = timecycle2;

   do{ }
   while (temp>micros());

I can see that you are waiting (half of the period between the previous time cycle and the current one from now) to pulse the SparkPlugPin, but I don't see why.

Also, could there be an issue with rpmcount not reaching > 3 in 30ms or no?

There is 4 things happening:

  1. Cam sensors triggered causing rpmcount to advance by 1. Cam sensor is triggered every 2 revolutions of the engine. Based on cam sensor I can get my period of the engine. The cam trigger is about 20deg BTDC .

  2. Ignition system discharges at 20 to 3 deg BTDC.

  3. Fuel injector is priming the injector chamber, 50 to 270deg ATDC

  4. Air Injector is fired, forcing mix of air and fuel into the combustion chamber. 540 deg from original TDC or 180 from new TDC. This happens in between my cam sensor going off.

  5. is a sensors
    2,3,4 is Arduino events.

dt/2 should put the spark at 360deg,
and dt/1.333 or dt*720/540
30ms limit is set to prevent the Arduino from reving the engine beyond its redline of 4000rpm.

The most odd thing is. say my period is 120ms, then dt is 120 000, if I substitute dt with 120 000 it works no problem.

if I substitute dt with 120 000 it works no problem.

This, I think, confirms my suspicion that some overflow is occurring, because of integer arithmetic being performed. When you substitute a value, the value doesn't have a predefined type. So, the compiler chooses a type based on the other variables or values involved in the operation.

unsigned long dt = 120000UL;
unsigned long result1 = dt/2.5;
unsigned long result2 = 120000/2.5;

The result1 and result2 variables will not necessarily contain the same value.

The problem actually ended up to be in
do{ }
while (temp>micros());
Same code also freaks out if I substitute While loop with delayMicroseconds.

Not sure what happens, but when it loops in their, temp gets screwed up. I rewrote the code to have no more secondary loops. Now it keeps up the timing very well.