Minimal bug testing.
Code: Select all
#include "TuneArrays.h"
uint8_t RPMIndex = 0;
uint8_t adcIndex = 0;
unsigned long currentOnDelaySpark = 0;
unsigned long currentOffDelaySpark = 0;
unsigned long currentOnDelayFuel = 0;
unsigned long currentOffDelayFuel = 0;
// Spark patterns (Pin 0 to 7)
const uint8_t patternSpark0 = 0b01111101;
bool pulseActiveSpark0 = false;
bool triggerPulseSpark0 = false;
unsigned long pulseStartTimeSpark0 = 0;
const uint8_t patternSpark1 = 0b01111101;
bool pulseActiveSpark1 = false;
bool triggerPulseSpark1 = false;
unsigned long pulseStartTimeSpark1 = 0;
const uint8_t patternSpark2 = 0b01110011;
bool pulseActiveSpark2 = false;
bool triggerPulseSpark2 = false;
unsigned long pulseStartTimeSpark2 = 0;
const uint8_t patternSpark3 = 0b01110011;
bool pulseActiveSpark3 = false;
bool triggerPulseSpark3 = false;
unsigned long pulseStartTimeSpark3 = 0;
const uint8_t patternSpark4 = 0b11000101;
bool pulseActiveSpark4 = false;
bool triggerPulseSpark4 = false;
unsigned long pulseStartTimeSpark4 = 0;
const uint8_t patternSpark5 = 0b11000101;
bool pulseActiveSpark5 = false;
bool triggerPulseSpark5 = false;
unsigned long pulseStartTimeSpark5 = 0;
const uint8_t patternSpark6 = 0b01000001;
bool pulseActiveSpark6 = false;
bool triggerPulseSpark6 = false;
unsigned long pulseStartTimeSpark6 = 0;
const uint8_t patternSpark7 = 0b01000001;
bool pulseActiveSpark7 = false;
bool triggerPulseSpark7 = false;
unsigned long pulseStartTimeSpark7 = 0;
// Fuel patterns (Pin 8 to 15)
const uint8_t patternFuel0 = 0b01111101;
bool pulseActiveFuel0 = false;
bool triggerPulseFuel0 = false;
unsigned long pulseStartTimeFuel0 = 0;
const uint8_t patternFuel1 = 0b01111101;
bool pulseActiveFuel1 = false;
bool triggerPulseFuel1 = false;
unsigned long pulseStartTimeFuel1 = 0;
const uint8_t patternFuel2 = 0b01110011;
bool pulseActiveFuel2 = false;
bool triggerPulseFuel2 = false;
unsigned long pulseStartTimeFuel2 = 0;
const uint8_t patternFuel3 = 0b01110011;
bool pulseActiveFuel3 = false;
bool triggerPulseFuel3 = false;
unsigned long pulseStartTimeFuel3 = 0;
const uint8_t patternFuel4 = 0b11000101;
bool pulseActiveFuel4 = false;
bool triggerPulseFuel4 = false;
unsigned long pulseStartTimeFuel4 = 0;
const uint8_t patternFuel5 = 0b11000101;
bool pulseActiveFuel5 = false;
bool triggerPulseFuel5 = false;
unsigned long pulseStartTimeFuel5 = 0;
const uint8_t patternFuel6 = 0b01000001;
bool pulseActiveFuel6 = false;
bool triggerPulseFuel6 = false;
unsigned long pulseStartTimeFuel6 = 0;
const uint8_t patternFuel7 = 0b01000001;
bool pulseActiveFuel7 = false;
bool triggerPulseFuel7 = false;
unsigned long pulseStartTimeFuel7 = 0;
int readings[24] {4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095}; // Circular buffer
int bufIndex = 0; // Buffer index
long total = 4095L * 24; // Set this to the initial sum
int readings2[24]; // Circular buffer
int bufIndex2 = 0; // Buffer index
long total2 = 0L * 24; // Set this to the initial sum
int readings3[24]; // Circular buffer
int bufIndex3 = 0; // Buffer index
unsigned long total3 = 0UL * 24; // Set this to the initial sum
unsigned long lastTime = 0;
unsigned long pulseHighTime = 0;
unsigned long pulseLowTime = 0;
uint8_t signalHistory = 0;
bool newSample = false;
void handleCrankSignal() {
unsigned long currentTime = micros();
if (digitalRead(22) == HIGH) {
pulseHighTime = currentTime - lastTime;
} else {
pulseLowTime = currentTime - lastTime;
uint8_t bit = (pulseHighTime > pulseLowTime) ? 0 : 1;
signalHistory = ((signalHistory << 1) | bit) & 0xFF;
newSample = true; // flag to loop()
}
lastTime = currentTime;
}
void handleSparkPulse(uint8_t pin, unsigned long startTime, bool &activeFlag) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (elapsed < currentOnDelaySpark) {
digitalWrite(pin, LOW);
} else if (elapsed < currentOnDelaySpark + currentOffDelaySpark) {
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
activeFlag = false;
}
}
void handleFuelPulse(uint8_t pin, unsigned long startTime, bool &activeFlag) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (elapsed < currentOnDelayFuel) {
digitalWrite(pin, LOW);
} else if (elapsed < currentOnDelayFuel + currentOffDelayFuel) {
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
activeFlag = false;
}
}
void setup() {
analogReadResolution(12);
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(22, INPUT);
pinMode(21, INPUT);
attachInterrupt(digitalPinToInterrupt(22), handleCrankSignal, CHANGE);
}
void loop() {
if (newSample) {
newSample = false;
if (digitalRead(21) == HIGH){
// Spark patterns
if (signalHistory == patternSpark0) triggerPulseSpark0 = true;
if (signalHistory == patternFuel0) triggerPulseFuel0 = true;
if (signalHistory == patternSpark2) triggerPulseSpark2 = true;
if (signalHistory == patternFuel2) triggerPulseFuel2 = true;
if (signalHistory == patternSpark4) triggerPulseSpark4 = true;
if (signalHistory == patternFuel4) triggerPulseFuel4 = true;
if (signalHistory == patternSpark6) triggerPulseSpark6 = true;
if (signalHistory == patternFuel6) triggerPulseFuel6 = true;
}
if (digitalRead(21) == LOW) {
if (signalHistory == patternSpark1) triggerPulseSpark1 = true;
if (signalHistory == patternFuel1) triggerPulseFuel1 = true;
if (signalHistory == patternSpark3) triggerPulseSpark3 = true;
if (signalHistory == patternFuel3) triggerPulseFuel3 = true;
if (signalHistory == patternSpark5) triggerPulseSpark5 = true;
if (signalHistory == patternFuel5) triggerPulseFuel5 = true;
if (signalHistory == patternSpark7) triggerPulseSpark7 = true;
if (signalHistory == patternFuel7) triggerPulseFuel7 = true;
}
unsigned long RPMTime = pulseHighTime + pulseLowTime;//Calculate RPMtime (µs per 15 degrees)
total2 -= readings2[bufIndex2];
unsigned long newVal2 = RPMTime;
readings2[bufIndex2] = newVal2;
total2 += newVal2;
bufIndex2 = (bufIndex2 + 1) % 24;
unsigned long RPMTimeavg = total2 / 24;
// FIXED: Rev limiter + low-RPM cutoff
unsigned long Dwell = 4000UL;
if (RPMTimeavg < Limiter) {
Dwell = 0UL; // spark cut when RPM too high
} else if (RPMTimeavg > 125000UL) {
Dwell = 0UL; // below 20 RPM, also cut spark
}
RPMTimeavg = constrain(RPMTimeavg, 261UL, 3000000UL); // 9600 RPM to 20 RPM. Always round the decimal up, even if it's 0.0001. Not overflowing arrays is important
// --- ADC rolling average (12-bit to 7-bit scale) ---
total -= readings[bufIndex];
int newVal = analogRead(A0);
readings[bufIndex] = newVal;
total += newVal;
bufIndex = (bufIndex + 1) % 24;
int avg12bit = total / 24;
adcIndex = avg12bit >> 8; //Discarding LSBs to match array resolution
uint32_t IndexFull = ((uint64_t)2500000 << 8) / ((uint32_t)RPMTimeavg * 600);
uint Predicted360Time = RPMTimeavg * 48;//48 for full sequential, 720 degrees
uint16_t IndexWhole = IndexFull >> 8;
uint8_t Frac = IndexFull & 0xFF;
int Frac2 = avg12bit & 0x1F;
int TerpA = Dstart[IndexWhole][adcIndex];
int TerpB = Dstart[IndexWhole +1][adcIndex];
int TerpD = TerpA + (((TerpB - TerpA) * Frac) >> 8);
int TerpA2 = Dstart[IndexWhole][adcIndex +1];
int TerpB2 = Dstart[IndexWhole +1][adcIndex +1];
int TerpD2 = TerpA2 + (((TerpB2 - TerpA2) * Frac) >> 8);
int TerpD5 = TerpD + (((TerpD2 - TerpD) * Frac2) >> 8);
int TerpA3 = Iend[IndexWhole][adcIndex+1];
int TerpB3 = Iend[IndexWhole +1][adcIndex +1];
int TerpD3 = TerpA3 + (((TerpB3 - TerpA3) * Frac) >> 8);
int TerpA4 = Iend[IndexWhole][adcIndex];
int TerpB4 = Iend[IndexWhole +1][adcIndex];
int TerpD4 = TerpA4 + (((TerpB4 - TerpA4) * Frac) >> 8);
int TerpD6 = TerpD4 + (((TerpD3 - TerpD4) * Frac2) >> 8);
total3 -= readings3[bufIndex3];
int newVal3 = analogRead(A1);
readings3[bufIndex3] = newVal3;
total3 += newVal3;
bufIndex3 = (bufIndex3 + 1) % 24;
int IATavg = total3 / 24;
int IAT7bit = IATavg >> 5;
int Temp = IATSpark [IAT7bit];
int Scaled = ((TerpD5 * Temp) >>8);
int TrimA = EOIT [IndexWhole];
int TrimB = EOIT [IndexWhole +1];
int TrimTerp = TrimA + (((TrimB - TrimA) * Frac) >> 8);
int Temp2 = IATFuel [IAT7bit];
int Scaled3 = ((TerpD6 * Temp2) >>8);
int ScaledOffset = Predicted360Time - (Scaled3 + TrimTerp);
if (ScaledOffset < 0) ScaledOffset = 0;
if (RPMTimeavg > 125000UL){ //Fuel off if RPM below minimum = 20RPM
Scaled3 = 0UL;
}
// --- Update delay values from tables ---
currentOnDelaySpark = Scaled;
currentOffDelaySpark = Dwell;
currentOnDelayFuel = ScaledOffset;
currentOffDelayFuel = Scaled3;
}
// --- Check for new pulse triggers from crank handler ---
// --- Spark pulse triggers ---
if (triggerPulseSpark0) { triggerPulseSpark0 = false; pulseStartTimeSpark0 = micros(); pulseActiveSpark0 = true; }
if (triggerPulseSpark1) { triggerPulseSpark1 = false; pulseStartTimeSpark1 = micros(); pulseActiveSpark1 = true; }
if (triggerPulseSpark2) { triggerPulseSpark2 = false; pulseStartTimeSpark2 = micros(); pulseActiveSpark2 = true; }
if (triggerPulseSpark3) { triggerPulseSpark3 = false; pulseStartTimeSpark3 = micros(); pulseActiveSpark3 = true; }
if (triggerPulseSpark4) { triggerPulseSpark4 = false; pulseStartTimeSpark4 = micros(); pulseActiveSpark4 = true; }
if (triggerPulseSpark5) { triggerPulseSpark5 = false; pulseStartTimeSpark5 = micros(); pulseActiveSpark5 = true; }
if (triggerPulseSpark6) { triggerPulseSpark6 = false; pulseStartTimeSpark6 = micros(); pulseActiveSpark6 = true; }
if (triggerPulseSpark7) { triggerPulseSpark7 = false; pulseStartTimeSpark7 = micros(); pulseActiveSpark7 = true; }
// --- Fuel pulse triggers ---
if (triggerPulseFuel0) { triggerPulseFuel0 = false; pulseStartTimeFuel0 = micros(); pulseActiveFuel0 = true; }
if (triggerPulseFuel1) { triggerPulseFuel1 = false; pulseStartTimeFuel1 = micros(); pulseActiveFuel1 = true; }
if (triggerPulseFuel2) { triggerPulseFuel2 = false; pulseStartTimeFuel2 = micros(); pulseActiveFuel2 = true; }
if (triggerPulseFuel3) { triggerPulseFuel3 = false; pulseStartTimeFuel3 = micros(); pulseActiveFuel3 = true; }
if (triggerPulseFuel4) { triggerPulseFuel4 = false; pulseStartTimeFuel4 = micros(); pulseActiveFuel4 = true; }
if (triggerPulseFuel5) { triggerPulseFuel5 = false; pulseStartTimeFuel5 = micros(); pulseActiveFuel5 = true; }
if (triggerPulseFuel6) { triggerPulseFuel6 = false; pulseStartTimeFuel6 = micros(); pulseActiveFuel6 = true; }
if (triggerPulseFuel7) { triggerPulseFuel7 = false; pulseStartTimeFuel7 = micros(); pulseActiveFuel7 = true; }
// --- Spark pulse timing (Pins 0 to 7) ---
if (pulseActiveSpark0) handleSparkPulse(0, pulseStartTimeSpark0, pulseActiveSpark0);
if (pulseActiveSpark1) handleSparkPulse(1, pulseStartTimeSpark1, pulseActiveSpark1);
if (pulseActiveSpark2) handleSparkPulse(2, pulseStartTimeSpark2, pulseActiveSpark2);
if (pulseActiveSpark3) handleSparkPulse(3, pulseStartTimeSpark3, pulseActiveSpark3);
if (pulseActiveSpark4) handleSparkPulse(4, pulseStartTimeSpark4, pulseActiveSpark4);
if (pulseActiveSpark5) handleSparkPulse(5, pulseStartTimeSpark5, pulseActiveSpark5);
if (pulseActiveSpark6) handleSparkPulse(6, pulseStartTimeSpark6, pulseActiveSpark6);
if (pulseActiveSpark7) handleSparkPulse(7, pulseStartTimeSpark7, pulseActiveSpark7);
// --- Fuel pulse timing (Pins 8 to 15) ---
if (pulseActiveFuel0) handleFuelPulse(8, pulseStartTimeFuel0, pulseActiveFuel0);
if (pulseActiveFuel1) handleFuelPulse(9, pulseStartTimeFuel1, pulseActiveFuel1);
if (pulseActiveFuel2) handleFuelPulse(10, pulseStartTimeFuel2, pulseActiveFuel2);
if (pulseActiveFuel3) handleFuelPulse(11, pulseStartTimeFuel3, pulseActiveFuel3);
if (pulseActiveFuel4) handleFuelPulse(12, pulseStartTimeFuel4, pulseActiveFuel4);
if (pulseActiveFuel5) handleFuelPulse(13, pulseStartTimeFuel5, pulseActiveFuel5);
if (pulseActiveFuel6) handleFuelPulse(14, pulseStartTimeFuel6, pulseActiveFuel6);
if (pulseActiveFuel7) handleFuelPulse(15, pulseStartTimeFuel7, pulseActiveFuel7);
}
TuneArrays.h did not change.
Moving all the pattern matching outside the interrupt seemed to help with noise.
That picture may not convince, but it looks different viewing real-time.
Notice the even spread vs discrete steps in previous pictures. I think most of the noise is a shift vs a pulse width change.
Actaully, I can measure that by triggering oscilloscope off the pulse instead of cam signal.
Well, make of that what you will. Looks like exactly 50uS and only 50uS.