//Once the configs have been loaded, a number of one time calculations can be completed
req_fuel_uS=configPage1.reqFuel*1000;//Convert to uS and an int. This is the only variable to be used in calculations
triggerToothAngle=360/configPage2.triggerTeeth;//The number of degrees that passes from tooth to tooth
triggerActualTeeth=configPage2.triggerTeeth-configPage2.triggerMissingTeeth;//The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
req_fuel_uS=req_fuel_uS/engineSquirtsPerCycle;//The req_fuel calculation above gives the total required fuel (At VE 100%) in the full cycle. If we're doing more than 1 squirt per cycle then we need to split the amount accordingly. (Note that in a non-sequential 4-stroke setup you cannot have less than 2 squirts as you cannot determine the stroke to make the single squirt on)
//This sets the ADC (Analog to Digitial Converter) to run at 1Mhz, greatly reducing analog read times (MAP/TPS)
//1Mhz is the fastest speed permitted by the CPU without affecting accuracy
//Please see chapter 11 of 'Practical Arduino' (http://books.google.com.au/books?id=HsTxON1L6D4C&printsec=frontcover#v=onepage&q&f=false) for more details
//Can be disabled by removing the #include "fastAnalog.h" above
if((mainLoopCount&63)==1)//Only check the serial buffer (And hence process serial commands) once every 64 loops (64 Is more than fast enough for TunerStudio). This function is equivalent to ((loopCount % 64) == 1) but is considerably faster due to not using the mod or division operations
if((currentLoopTime-toothLastToothTime)<500000L)//Check how long ago the last tooth was seen compared to now. If it was more than half a second ago then the engine is probably stopped
unsignedlongrevolutionTime=(toothOneTime-toothOneMinusOneTime);//The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
currentStatus.tpsADC=map(analogRead(pinTPS),0,1023,0,255);//Get the current raw TPS ADC value and map it into a byte
currentStatus.TPS=map(currentStatus.tpsADC,configPage1.tpsMin,configPage1.tpsMax,0,100);//Take the raw TPS ADC value and convert it into a TPS% based on the calibrated values
currentStatus.O2=map(analogRead(pinO2),0,1023,117,358);//Get the current O2 value. Calibration is from AFR values 7.35 to 22.4, then multiplied by 16 (<< 4). This is the correct calibration for an Innovate Wideband 0v - 5V unit
currentStatus.VE=get3DTableValue(fuelTable,currentStatus.TPS,currentStatus.RPM);//Perform lookup into fuel map for RPM vs TPS value
currentStatus.PW=PW_AN(req_fuel_uS,currentStatus.VE,currentStatus.TPS,corrections,engineInjectorDeadTime);//The 100 here is just a placeholder for any enrichment factors (Cold start, acceleration etc). To add 10% extra fuel, this would be 110
currentStatus.advance=get3DTableValue(ignitionTable,currentStatus.TPS,currentStatus.RPM);//As above, but for ignition advance
//This is the current angle ATDC the engine is at. This is the last known position based on what tooth was last 'seen'. It is only accurate to the resolution of the trigger wheel (Eg 36-1 is 10 degrees)
intcrankAngle=(toothCurrentCount-1)*triggerToothAngle+configPage2.triggerAngle;//Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth
//How fast are we going? Need to know how long (uS) it will take to get from one tooth to the next. We then use that to estimate how far we are between the last tooth and the next one
unsignedlongtimePerDegree=fastDivide32((toothOneTime-toothOneMinusOneTime),(triggerToothAngle*configPage2.triggerTeeth));//The time (uS) it is currently taking to move 1 degree (fastDivide version)
crankAngle+=fastDivide32((micros()-toothLastToothTime),timePerDegree);//Estimate the number of degrees travelled since the last tooth (fastDivide version)
intinjector1StartAngle=355-(fastDivide32(currentStatus.PW,timePerDegree));//This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. I am using 355 as the point at which the injector MUST be closed by. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
if(currentStatus.RPM>((int)(configPage2.SoftRevLim*100))){currentStatus.advance-=configPage2.SoftLimRetard;}//Softcut RPM limit (If we're above softcut limit, delay timing by configured number of degrees)
intignition1StartAngle=360-currentStatus.advance-(fastDivide32((configPage2.dwellRun*100),timePerDegree));// 360 - desired advance angle - number of degrees the dwell will take
if(currentStatus.RPM<((int)(configPage2.HardRevLim)*100))//Check for hard cut rev limit (If we're above the hardcut limit, we simply don't set a spark schedule)
{
setIgnitionSchedule1(beginCoil1Charge,
(ignition1StartAngle-crankAngle)*timePerDegree,
(configPage2.dwellRun*100),//Dwell is stored as ms * 10. ie Dwell of 4.3ms would be 43 in configPage2. This number therefore needs to be multiplied by 100 to get dwell in uS
voidopenInjector2(){digitalWrite(pinInjector2,HIGH);BIT_SET(currentStatus.squirt,1);}//Sets the relevant pin HIGH and changes the current status bit for injector 2 (2nd bit of currentStatus.squirt)
voidopenInjector3(){digitalWrite(pinInjector3,HIGH);BIT_SET(currentStatus.squirt,1);}//Sets the relevant pin HIGH and changes the current status bit for injector 2 (2nd bit of currentStatus.squirt)
voidopenInjector4(){digitalWrite(pinInjector4,HIGH);BIT_SET(currentStatus.squirt,1);}//Sets the relevant pin HIGH and changes the current status bit for injector 2 (2nd bit of currentStatus.squirt)
if((curTime-toothLastToothTime)<triggerFilterTime){interrupts();return;}//Debounce check. Pulses should never be less than triggerFilterTime, so if they are it means a false trigger. (A 36-1 wheel at 8000pm will have triggers approx. every 200uS)
//If the time between the current tooth and the last is greater than 1.5x the time between the last tooth and the tooth before that, we make the assertion that we must be at the first tooth after the gap
if((curTime-toothLastToothTime)>((3*(toothLastToothTime-toothLastMinusOneToothTime))>>1))//Same as above, but uses bitshift instead of multiplying by 1.5