Coding my own aftermarket ECU [beta available]
Re: Coding my own aftermarket ECU [beta available]
Think I'll just do TDC for pattern match. Allows more error in timing with rapid RPM change, but seriously simplifies setup instructions, and the later planned cam sensor logic.
Also allows the most max RPM potential with dwell timing without stopping 0 degree advance from working.
If anybody wants to share their 2 cents on that, I'll consider it.
I'll look into loop code that can dynamicly adjust timing outside after it's initial set time to account for rapid change. Since it's 'if >' it should be tollerant to dynamic updates every 15 degrees.
That's a priority over all previously mentioned features.
Also allows the most max RPM potential with dwell timing without stopping 0 degree advance from working.
If anybody wants to share their 2 cents on that, I'll consider it.
I'll look into loop code that can dynamicly adjust timing outside after it's initial set time to account for rapid change. Since it's 'if >' it should be tollerant to dynamic updates every 15 degrees.
That's a priority over all previously mentioned features.
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Shit, I think the AI generated
already dynamically updates as I described. Can't remember if that's part of what I described, or a happy coincidence.
I definitely emphasized 'dynamic' a bit. Took 3 or 4 tries to get results that weren't shit.
Code: Select all
currentOnDelay11 = Scaled;
currentOffDelay11 = Dwell;
currentOnDelay4 = ScaledOffset;
currentOffDelay4 = Scaled3;
}
// --- Check for new pulse triggers from crank handler ---
if (triggerPulse11) {
triggerPulse11 = false;
pulseStartTime11 = micros();
pulseActive11 = true;
}
if (triggerPulse4) {
triggerPulse4 = false;
pulseStartTime4 = micros();
pulseActive4 = true;
}
// --- Pulse timing for pin 11 (pattern1) ---
if (pulseActive11) {
unsigned long now = micros();
unsigned long elapsed = now - pulseStartTime11;
if (elapsed < currentOnDelay11) {
digitalWrite(11, LOW);
} else if (elapsed < currentOnDelay11 + currentOffDelay11) {
digitalWrite(11, HIGH);
} else {
digitalWrite(11, LOW);
pulseActive11 = false;
}
}
// --- Pulse timing for pin 4 (pattern0) ---
if (pulseActive4) {
unsigned long now = micros();
unsigned long elapsed = now - pulseStartTime4;
if (elapsed < currentOnDelay4) {
digitalWrite(4, LOW);
} else if (elapsed < currentOnDelay4 + currentOffDelay4) {
digitalWrite(4, HIGH);
} else {
digitalWrite(4, LOW);
pulseActive4 = false;
}
}
}
I definitely emphasized 'dynamic' a bit. Took 3 or 4 tries to get results that weren't shit.
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
For 8 cylinder support, going to use pins 0-15. Since that's one entire side of the Pico.
So crank sensor is moving to pin 22. Closest digital-only pin to analog pins.
One side of board for outputs, one side for inputs.
Makes board prototyping easier. Make 2 halves. Turns out it's 1 pin short of doing 12 cylinder fuel and spark, and that's before even doing external correction inputs.
Could use 2 and do a little reconfiguring though.
Found and removed some unused variables left from previous prototyping iterations.
Will post an update when I add cylinder count and think I have the corresponding TDCs for pattern matches.
So crank sensor is moving to pin 22. Closest digital-only pin to analog pins.
One side of board for outputs, one side for inputs.
Makes board prototyping easier. Make 2 halves. Turns out it's 1 pin short of doing 12 cylinder fuel and spark, and that's before even doing external correction inputs.
Could use 2 and do a little reconfiguring though.
Found and removed some unused variables left from previous prototyping iterations.
Will post an update when I add cylinder count and think I have the corresponding TDCs for pattern matches.
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Guess AI is making me learn a little about "helper functions" today.
It did offer to spell them all out individually. But this is smarter. I break all of them or break none.
Seems to work.
It did offer to spell them all out individually. But this is smarter. I break all of them or break none.
Code: Select all
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;
}
}
Code: Select all
// --- 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);
}
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Well, extra noise on the fuel output, but psted in 16 channels of outputs now.
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Full sequential (but still sorting bugs).
Noise zoom
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Minimal bug testing.
Full sequential V8.
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.
Full sequential V8.
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);
}
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.
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Changing inputs, you'll see different amounts of steady state noise. Just so we're clear it various a bit.
Don't stress specific units.
Re: Coding my own aftermarket ECU [beta available]
Parsing some of that down a bit.
Just like a distributor V8 only needs the 4x crank signal, this full sequential only needs 4 pattern matches 90 degrees out of phase from each other.
That spreads it all out as needed. Now less to change for V6 support, and less compares happening in code. Unneeded optimization.
Just like a distributor V8 only needs the 4x crank signal, this full sequential only needs 4 pattern matches 90 degrees out of phase from each other.
That spreads it all out as needed. Now less to change for V6 support, and less compares happening in code. Unneeded optimization.
Code: Select all
const uint8_t pattern0 = 0b01111101;
const uint8_t pattern1 = 0b01110011;
const uint8_t pattern2 = 0b11000101;
const uint8_t pattern3 = 0b01000001;
Code: Select all
if (digitalRead(21) == HIGH){
// Spark patterns
if (signalHistory == pattern0) {triggerPulseSpark0 = true; triggerPulseFuel0 = true;}
if (signalHistory == pattern1) {triggerPulseSpark2 = true; triggerPulseFuel2 = true;}
if (signalHistory == pattern2) {triggerPulseSpark4 = true; triggerPulseFuel4 = true;}
if (signalHistory == pattern3) {triggerPulseSpark6 = true; triggerPulseFuel6 = true;}
}
if (digitalRead(21) == LOW) {
if (signalHistory == pattern0) {triggerPulseSpark1 = true; triggerPulseFuel1 = true;}
if (signalHistory == pattern1) {triggerPulseSpark3 = true; triggerPulseFuel3 = true;}
if (signalHistory == pattern2) {triggerPulseSpark5 = true; triggerPulseFuel5 = true;}
if (signalHistory == pattern3) {triggerPulseSpark7 = true; triggerPulseFuel7 = true;}
}
Don't stress specific units.