I was wondering too.AngelMarc wrote: Mon Jul 14, 2025 3:51 pm That why I kept getting
"The forum is currently unavailable. Try again in a few minutes."
Coding my own open source 24x ECU [beta available]
-
Denny
- Posts: 71
- Joined: Sun Nov 10, 2024 8:04 pm
- cars: 2007 Chevrolet Silverado 4.8
Re: Coding my own open source 24x ECU [beta available]
-
pman92
- Posts: 667
- Joined: Thu May 03, 2012 12:50 pm
- Location: Castlemaine, Vic
Re: Coding my own open source 24x ECU [beta available]
I'm still getting the try again later warning and getting logged out occasionally.antus wrote: Sun Jul 13, 2025 6:19 am BTW the site is behind cloudflare now. We got broken hard over the last 2 weeks.
Bloody AI is going to kill what good things are left of the internet
-
antus
- Site Admin
- Posts: 10012
- Joined: Sat Feb 28, 2009 10:34 am
- cars: TX Gemini 2L Twincam 8psi
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Subaru WRX 2007
Re: Coding my own open source 24x ECU [beta available]
Lets let this thread be for the 24 times open source ECU. But yes load problems are ongoing. Cloudflare helped, significantly, but we are still too popular and overloading the server. I'm not sure what I can do yet. I think i'm out of low cost options and need to scale up. Any further comments about load, start a new thread (or post to one, once it exists) and we can talk about it there.
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396
-
AngelMarc
- Posts: 612
- Joined: Sat Apr 08, 2023 11:23 am
- cars: A CB450 running to 8,000RPM with a P59.
Re: Coding my own open source 24x ECU [beta available]
Tell us all about it
viewtopic.php?t=8973&sid=cc70fac4583fa2 ... 99ad73c925
viewtopic.php?t=8973&sid=cc70fac4583fa2 ... 99ad73c925
Don't stress specific units.
-
AngelMarc
- Posts: 612
- Joined: Sat Apr 08, 2023 11:23 am
- cars: A CB450 running to 8,000RPM with a P59.
Re: Coding my own open source 24x ECU [beta available]
Not liking ChatGPT's suggestions for pulse gen changes that don't change things outside those functions, so I'm trying to slowly type something out manually. Really need something that doesn't cause chaos when bouncing off the rev limiter.
Don't stress specific units.
-
AngelMarc
- Posts: 612
- Joined: Sat Apr 08, 2023 11:23 am
- cars: A CB450 running to 8,000RPM with a P59.
Re: Coding my own open source 24x ECU [beta available]
Didn't test yet. Surprised myself with only 1 typo and no Ai help with this change.
Separated pulse handlers into 2 halves. Basically borrowed a little from how I sorted my crank signal generator. A little difference, 1st function/loop doesn't de-assert itself, so second loop can use that flag to lock in its pulse width, then de-assert the flag. Should be able to bounce off the rev limiter all day and not see partial pulses. Same with transient conditions.
Separated pulse handlers into 2 halves. Basically borrowed a little from how I sorted my crank signal generator. A little difference, 1st function/loop doesn't de-assert itself, so second loop can use that flag to lock in its pulse width, then de-assert the flag. Should be able to bounce off the rev limiter all day and not see partial pulses. Same with transient conditions.
Code: Select all
#include "TuneArrays.h"
const uint8_t pattern0 = 0b01111101;//0 degrees / TDC #1 and paired cylinder
const uint8_t pattern1 = 0b01110011;//90 degrees
const uint8_t pattern2 = 0b11000101;//180 degrees
const uint8_t pattern3 = 0b01000001;//270 degrees
uint8_t RPMIndex = 0;
uint8_t adcIndex = 0;
unsigned long currentOnDelaySpark = 0;
unsigned long currentOffDelaySpark = 0;
unsigned long currentOnDelayFuel = 0;
unsigned long currentOffDelayFuel = 0;
bool pulseHighSpark0 = false;
bool pulseActiveSpark0 = false;
bool triggerPulseSpark0 = false;
unsigned long pulseStartTimeSpark0 = 0;
unsigned long pulseWidthSpark0 = 0;
bool pulseHighSpark1 = false;
bool pulseActiveSpark1 = false;
bool triggerPulseSpark1 = false;
unsigned long pulseStartTimeSpark1 = 0;
unsigned long pulseWidthSpark1 = 0;
bool pulseHighSpark2 = false;
bool pulseActiveSpark2 = false;
bool triggerPulseSpark2 = false;
unsigned long pulseStartTimeSpark2 = 0;
unsigned long pulseWidthSpark2 = 0;
bool pulseHighSpark3 = false;
bool pulseActiveSpark3 = false;
bool triggerPulseSpark3 = false;
unsigned long pulseStartTimeSpark3 = 0;
unsigned long pulseWidthSpark3 = 0;
bool pulseHighSpark4 = false;
bool pulseActiveSpark4 = false;
bool triggerPulseSpark4 = false;
unsigned long pulseStartTimeSpark4 = 0;
unsigned long pulseWidthSpark4 = 0;
bool pulseHighSpark5 = false;
bool pulseActiveSpark5 = false;
bool triggerPulseSpark5 = false;
unsigned long pulseStartTimeSpark5 = 0;
unsigned long pulseWidthSpark5 = 0;
bool pulseHighSpark6 = false;
bool pulseActiveSpark6 = false;
bool triggerPulseSpark6 = false;
unsigned long pulseStartTimeSpark6 = 0;
unsigned long pulseWidthSpark6 = 0;
bool pulseHighSpark7 = false;
bool pulseActiveSpark7 = false;
bool triggerPulseSpark7 = false;
unsigned long pulseStartTimeSpark7 = 0;
unsigned long pulseWidthSpark7 = 0;
bool pulseHighFuel0 = false;
bool pulseActiveFuel0 = false;
bool triggerPulseFuel0 = false;
unsigned long pulseStartTimeFuel0 = 0;
unsigned long pulseWidthFuel0 = 0;
bool pulseHighFuel1 = false;
bool pulseActiveFuel1 = false;
bool triggerPulseFuel1 = false;
unsigned long pulseStartTimeFuel1 = 0;
unsigned long pulseWidthFuel1 = 0;
bool pulseHighFuel2 = false;
bool pulseActiveFuel2 = false;
bool triggerPulseFuel2 = false;
unsigned long pulseStartTimeFuel2 = 0;
unsigned long pulseWidthFuel2 = 0;
bool pulseHighFuel3 = false;
bool pulseActiveFuel3 = false;
bool triggerPulseFuel3 = false;
unsigned long pulseStartTimeFuel3 = 0;
unsigned long pulseWidthFuel3 = 0;
bool pulseHighFuel4 = false;
bool pulseActiveFuel4 = false;
bool triggerPulseFuel4 = false;
unsigned long pulseStartTimeFuel4 = 0;
unsigned long pulseWidthFuel4 = 0;
bool pulseHighFuel5 = false;
bool pulseActiveFuel5 = false;
bool triggerPulseFuel5 = false;
unsigned long pulseStartTimeFuel5 = 0;
unsigned long pulseWidthFuel5 = 0;
bool pulseHighFuel6 = false;
bool pulseActiveFuel6 = false;
bool triggerPulseFuel6 = false;
unsigned long pulseStartTimeFuel6 = 0;
unsigned long pulseWidthFuel6 = 0;
bool pulseHighFuel7 = false;
bool pulseActiveFuel7 = false;
bool triggerPulseFuel7 = false;
unsigned long pulseStartTimeFuel7 = 0;
unsigned long pulseWidthFuel7 = 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 = 0b00000000;
bool newSample = false;
void handleCrankSignal() {
unsigned long currentTime = micros();
if (digitalRead(22) == HIGH) {
pulseLowTime = currentTime - lastTime;
} else {
pulseHighTime = currentTime - lastTime;
uint8_t bit = (pulseHighTime > pulseLowTime) ? 1 : 0;
signalHistory = ((signalHistory << 1) | bit) & 0xFF;
newSample = true; // flag to loop()
}
lastTime = currentTime;
}
void handleSparkPulse(uint8_t pin, unsigned long startTime, bool &highFlag) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (elapsed < currentOnDelaySpark) {
digitalWrite(pin, LOW);
} else {
highFlag = true;
}
}
void handleSparkPulse2(uint8_t pin, unsigned long startTime, bool &activeFlag, bool &highFlag, unsigned long OnTime) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (activeFlag){
OnTime = currentOnDelaySpark + currentOffDelaySpark;
activeFlag = false;
} else if (elapsed < OnTime) {
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
highFlag = false;
}
}
void handleFuelPulse(uint8_t pin, unsigned long startTime, bool &highFlag) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (elapsed < currentOnDelaySpark) {
digitalWrite(pin, LOW);
} else {
highFlag = true;
}
}
void handleFuelPulse2(uint8_t pin, unsigned long startTime, bool &activeFlag, bool &highFlag, unsigned long OnTime) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (activeFlag){
OnTime = currentOnDelaySpark + currentOffDelaySpark;
activeFlag = false;
} else if (elapsed < OnTime) {
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
highFlag = 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 == 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;}
}
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 / 24UL;
uint Predicted360Time = RPMTimeavg * 48;//48 for full sequential, 720 degrees. 25 for waste spark, 360 degrees.
// 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, 278UL, 3000000UL); // 9600 RPM to 0 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);
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){ //if RPM below minimum = 20RPM
Scaled3 = 0UL; //Fuel off
signalHistory = 0b00000000;//Sync reset
}
// --- 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 (pulseHighSpark0) handleSparkPulse2(0, pulseStartTimeSpark0, pulseActiveSpark0, pulseHighSpark0, pulseWidthSpark0);
if (pulseHighSpark1) handleSparkPulse2(1, pulseStartTimeSpark1, pulseActiveSpark1, pulseHighSpark1, pulseWidthSpark1);
if (pulseHighSpark2) handleSparkPulse2(2, pulseStartTimeSpark2, pulseActiveSpark2, pulseHighSpark2, pulseWidthSpark2);
if (pulseHighSpark3) handleSparkPulse2(3, pulseStartTimeSpark3, pulseActiveSpark3, pulseHighSpark3, pulseWidthSpark3);
if (pulseHighSpark4) handleSparkPulse2(4, pulseStartTimeSpark4, pulseActiveSpark4, pulseHighSpark4, pulseWidthSpark4);
if (pulseHighSpark5) handleSparkPulse2(5, pulseStartTimeSpark5, pulseActiveSpark5, pulseHighSpark5, pulseWidthSpark5);
if (pulseHighSpark6) handleSparkPulse2(6, pulseStartTimeSpark6, pulseActiveSpark6, pulseHighSpark6, pulseWidthSpark6);
if (pulseHighSpark7) handleSparkPulse2(7, pulseStartTimeSpark7, pulseActiveSpark7, pulseHighSpark7, pulseWidthSpark7);
if (pulseActiveSpark0) handleSparkPulse(0, pulseStartTimeSpark0, pulseHighSpark0);
if (pulseActiveSpark1) handleSparkPulse(1, pulseStartTimeSpark1, pulseHighSpark1);
if (pulseActiveSpark2) handleSparkPulse(2, pulseStartTimeSpark2, pulseHighSpark2);
if (pulseActiveSpark3) handleSparkPulse(3, pulseStartTimeSpark3, pulseHighSpark3);
if (pulseActiveSpark4) handleSparkPulse(4, pulseStartTimeSpark4, pulseHighSpark4);
if (pulseActiveSpark5) handleSparkPulse(5, pulseStartTimeSpark5, pulseHighSpark5);
if (pulseActiveSpark6) handleSparkPulse(6, pulseStartTimeSpark6, pulseHighSpark6);
if (pulseActiveSpark7) handleSparkPulse(7, pulseStartTimeSpark7, pulseHighSpark7);
// --- Fuel pulse timing (Pins 8 to 15) ---
if (pulseHighFuel0) handleFuelPulse2(8, pulseStartTimeFuel0, pulseActiveFuel0, pulseHighFuel0, pulseWidthFuel0);
if (pulseHighFuel1) handleFuelPulse2(9, pulseStartTimeFuel1, pulseActiveFuel1, pulseHighFuel1, pulseWidthFuel1);
if (pulseHighFuel2) handleFuelPulse2(10, pulseStartTimeFuel2, pulseActiveFuel2, pulseHighFuel2, pulseWidthFuel2);
if (pulseHighFuel3) handleFuelPulse2(11, pulseStartTimeFuel3, pulseActiveFuel3, pulseHighFuel3, pulseWidthFuel3);
if (pulseHighFuel4) handleFuelPulse2(12, pulseStartTimeFuel4, pulseActiveFuel4, pulseHighFuel4, pulseWidthFuel4);
if (pulseHighFuel5) handleFuelPulse2(13, pulseStartTimeFuel5, pulseActiveFuel5, pulseHighFuel5, pulseWidthFuel5);
if (pulseHighFuel6) handleFuelPulse2(14, pulseStartTimeFuel6, pulseActiveFuel6, pulseHighFuel6, pulseWidthFuel6);
if (pulseHighFuel7) handleFuelPulse2(15, pulseStartTimeFuel7, pulseActiveFuel7, pulseHighFuel7, pulseWidthFuel7);
if (pulseActiveFuel0) handleFuelPulse(8, pulseStartTimeFuel0, pulseHighFuel0);
if (pulseActiveFuel1) handleFuelPulse(9, pulseStartTimeFuel1, pulseHighFuel1);
if (pulseActiveFuel2) handleFuelPulse(10, pulseStartTimeFuel2, pulseHighFuel2);
if (pulseActiveFuel3) handleFuelPulse(11, pulseStartTimeFuel3, pulseHighFuel3);
if (pulseActiveFuel4) handleFuelPulse(12, pulseStartTimeFuel4, pulseHighFuel4);
if (pulseActiveFuel5) handleFuelPulse(13, pulseStartTimeFuel5, pulseHighFuel5);
if (pulseActiveFuel6) handleFuelPulse(14, pulseStartTimeFuel6, pulseHighFuel6);
if (pulseActiveFuel7) handleFuelPulse(15, pulseStartTimeFuel7, pulseHighFuel7);
}
Don't stress specific units.
-
AngelMarc
- Posts: 612
- Joined: Sat Apr 08, 2023 11:23 am
- cars: A CB450 running to 8,000RPM with a P59.
Re: Coding my own open source 24x ECU [beta available]
Apparently I messed this up.
So much for what was commented here.
So much for what was commented here.
Last edited by AngelMarc on Sun Sep 28, 2025 3:57 am, edited 1 time in total.
Don't stress specific units.
-
AngelMarc
- Posts: 612
- Joined: Sat Apr 08, 2023 11:23 am
- cars: A CB450 running to 8,000RPM with a P59.
Re: Coding my own open source 24x ECU [beta available]
When I split the pulse handlers, I sorted spark (thought I did anyway, god damn ampersand), then copy pasted that for fuel. Changed the function name but forgot to change some variable in the handlers. And apparently the "&" for passing variables for whatever the fuck reason. Going to replace that in original post.
Code: Select all
#include "TuneArrays.h"
const uint8_t pattern0 = 0b01111101;//0 degrees / TDC #1 and paired cylinder
const uint8_t pattern1 = 0b01110011;//90 degrees
const uint8_t pattern2 = 0b11000101;//180 degrees
const uint8_t pattern3 = 0b01000001;//270 degrees
uint8_t RPMIndex = 0;
uint8_t adcIndex = 0;
unsigned long currentOnDelaySpark = 0;
unsigned long currentOffDelaySpark = 0;
unsigned long currentOnDelayFuel = 0;
unsigned long currentOffDelayFuel = 0;
bool pulseHighSpark0 = false;
bool pulseActiveSpark0 = false;
bool triggerPulseSpark0 = false;
unsigned long pulseStartTimeSpark0 = 0;
unsigned long pulseWidthSpark0 = 0;
bool pulseHighSpark1 = false;
bool pulseActiveSpark1 = false;
bool triggerPulseSpark1 = false;
unsigned long pulseStartTimeSpark1 = 0;
unsigned long pulseWidthSpark1 = 0;
bool pulseHighSpark2 = false;
bool pulseActiveSpark2 = false;
bool triggerPulseSpark2 = false;
unsigned long pulseStartTimeSpark2 = 0;
unsigned long pulseWidthSpark2 = 0;
bool pulseHighSpark3 = false;
bool pulseActiveSpark3 = false;
bool triggerPulseSpark3 = false;
unsigned long pulseStartTimeSpark3 = 0;
unsigned long pulseWidthSpark3 = 0;
bool pulseHighSpark4 = false;
bool pulseActiveSpark4 = false;
bool triggerPulseSpark4 = false;
unsigned long pulseStartTimeSpark4 = 0;
unsigned long pulseWidthSpark4 = 0;
bool pulseHighSpark5 = false;
bool pulseActiveSpark5 = false;
bool triggerPulseSpark5 = false;
unsigned long pulseStartTimeSpark5 = 0;
unsigned long pulseWidthSpark5 = 0;
bool pulseHighSpark6 = false;
bool pulseActiveSpark6 = false;
bool triggerPulseSpark6 = false;
unsigned long pulseStartTimeSpark6 = 0;
unsigned long pulseWidthSpark6 = 0;
bool pulseHighSpark7 = false;
bool pulseActiveSpark7 = false;
bool triggerPulseSpark7 = false;
unsigned long pulseStartTimeSpark7 = 0;
unsigned long pulseWidthSpark7 = 0;
bool pulseHighFuel0 = false;
bool pulseActiveFuel0 = false;
bool triggerPulseFuel0 = false;
unsigned long pulseStartTimeFuel0 = 0;
unsigned long pulseWidthFuel0 = 0;
bool pulseHighFuel1 = false;
bool pulseActiveFuel1 = false;
bool triggerPulseFuel1 = false;
unsigned long pulseStartTimeFuel1 = 0;
unsigned long pulseWidthFuel1 = 0;
bool pulseHighFuel2 = false;
bool pulseActiveFuel2 = false;
bool triggerPulseFuel2 = false;
unsigned long pulseStartTimeFuel2 = 0;
unsigned long pulseWidthFuel2 = 0;
bool pulseHighFuel3 = false;
bool pulseActiveFuel3 = false;
bool triggerPulseFuel3 = false;
unsigned long pulseStartTimeFuel3 = 0;
unsigned long pulseWidthFuel3 = 0;
bool pulseHighFuel4 = false;
bool pulseActiveFuel4 = false;
bool triggerPulseFuel4 = false;
unsigned long pulseStartTimeFuel4 = 0;
unsigned long pulseWidthFuel4 = 0;
bool pulseHighFuel5 = false;
bool pulseActiveFuel5 = false;
bool triggerPulseFuel5 = false;
unsigned long pulseStartTimeFuel5 = 0;
unsigned long pulseWidthFuel5 = 0;
bool pulseHighFuel6 = false;
bool pulseActiveFuel6 = false;
bool triggerPulseFuel6 = false;
unsigned long pulseStartTimeFuel6 = 0;
unsigned long pulseWidthFuel6 = 0;
bool pulseHighFuel7 = false;
bool pulseActiveFuel7 = false;
bool triggerPulseFuel7 = false;
unsigned long pulseStartTimeFuel7 = 0;
unsigned long pulseWidthFuel7 = 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 = 0b00000000;
bool newSample = false;
void handleCrankSignal() {
unsigned long currentTime = micros();
if (digitalRead(22) == HIGH) {
pulseLowTime = currentTime - lastTime;
} else {
pulseHighTime = currentTime - lastTime;
uint8_t bit = (pulseHighTime > pulseLowTime) ? 1 : 0;
signalHistory = ((signalHistory << 1) | bit) & 0xFF;
newSample = true; // flag to loop()
}
lastTime = currentTime;
}
void handleSparkPulse(uint8_t pin, unsigned long startTime, bool &highFlag) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (elapsed < currentOnDelaySpark) {
digitalWrite(pin, LOW);
} else {
highFlag = true;
}
}
void handleSparkPulse2(uint8_t pin, unsigned long startTime, bool &activeFlag, bool &highFlag, unsigned long &OnTime) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (activeFlag){
OnTime = currentOnDelaySpark + currentOffDelaySpark;
activeFlag = false;
digitalWrite(pin, HIGH);
}
if (elapsed > OnTime) {
digitalWrite(pin, LOW);
highFlag = false;
}
}
void handleFuelPulse(uint8_t pin, unsigned long startTime, bool &highFlag) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (elapsed < currentOnDelayFuel) {
digitalWrite(pin, LOW);
} else {
highFlag = true;
}
}
void handleFuelPulse2(uint8_t pin, unsigned long startTime, bool &activeFlag, bool &highFlag, unsigned long &OnTime) {
unsigned long now = micros();
unsigned long elapsed = now - startTime;
if (activeFlag){
OnTime = currentOnDelayFuel + currentOffDelayFuel;
activeFlag = false;
digitalWrite(pin, HIGH);
}
if (elapsed > OnTime) {
digitalWrite(pin, LOW);
highFlag = 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 == 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;}
}
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 / 24UL;
uint Predicted360Time = RPMTimeavg * 48;//48 for full sequential, 720 degrees. 25 for waste spark, 360 degrees.
// 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, 278UL, 3000000UL); // 9600 RPM to 0 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);
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){ //if RPM below minimum = 20RPM
Scaled3 = 0UL; //Fuel off
signalHistory = 0b00000000;//Sync reset
}
// --- 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 (pulseHighSpark0) handleSparkPulse2(0, pulseStartTimeSpark0, pulseActiveSpark0, pulseHighSpark0, pulseWidthSpark0);
if (pulseHighSpark1) handleSparkPulse2(1, pulseStartTimeSpark1, pulseActiveSpark1, pulseHighSpark1, pulseWidthSpark1);
if (pulseHighSpark2) handleSparkPulse2(2, pulseStartTimeSpark2, pulseActiveSpark2, pulseHighSpark2, pulseWidthSpark2);
if (pulseHighSpark3) handleSparkPulse2(3, pulseStartTimeSpark3, pulseActiveSpark3, pulseHighSpark3, pulseWidthSpark3);
if (pulseHighSpark4) handleSparkPulse2(4, pulseStartTimeSpark4, pulseActiveSpark4, pulseHighSpark4, pulseWidthSpark4);
if (pulseHighSpark5) handleSparkPulse2(5, pulseStartTimeSpark5, pulseActiveSpark5, pulseHighSpark5, pulseWidthSpark5);
if (pulseHighSpark6) handleSparkPulse2(6, pulseStartTimeSpark6, pulseActiveSpark6, pulseHighSpark6, pulseWidthSpark6);
if (pulseHighSpark7) handleSparkPulse2(7, pulseStartTimeSpark7, pulseActiveSpark7, pulseHighSpark7, pulseWidthSpark7);
if (pulseActiveSpark0) handleSparkPulse(0, pulseStartTimeSpark0, pulseHighSpark0);
if (pulseActiveSpark1) handleSparkPulse(1, pulseStartTimeSpark1, pulseHighSpark1);
if (pulseActiveSpark2) handleSparkPulse(2, pulseStartTimeSpark2, pulseHighSpark2);
if (pulseActiveSpark3) handleSparkPulse(3, pulseStartTimeSpark3, pulseHighSpark3);
if (pulseActiveSpark4) handleSparkPulse(4, pulseStartTimeSpark4, pulseHighSpark4);
if (pulseActiveSpark5) handleSparkPulse(5, pulseStartTimeSpark5, pulseHighSpark5);
if (pulseActiveSpark6) handleSparkPulse(6, pulseStartTimeSpark6, pulseHighSpark6);
if (pulseActiveSpark7) handleSparkPulse(7, pulseStartTimeSpark7, pulseHighSpark7);
// --- Fuel pulse timing (Pins 8 to 15) ---
if (pulseHighFuel0) handleFuelPulse2(8, pulseStartTimeFuel0, pulseActiveFuel0, pulseHighFuel0, pulseWidthFuel0);
if (pulseHighFuel1) handleFuelPulse2(9, pulseStartTimeFuel1, pulseActiveFuel1, pulseHighFuel1, pulseWidthFuel1);
if (pulseHighFuel2) handleFuelPulse2(10, pulseStartTimeFuel2, pulseActiveFuel2, pulseHighFuel2, pulseWidthFuel2);
if (pulseHighFuel3) handleFuelPulse2(11, pulseStartTimeFuel3, pulseActiveFuel3, pulseHighFuel3, pulseWidthFuel3);
if (pulseHighFuel4) handleFuelPulse2(12, pulseStartTimeFuel4, pulseActiveFuel4, pulseHighFuel4, pulseWidthFuel4);
if (pulseHighFuel5) handleFuelPulse2(13, pulseStartTimeFuel5, pulseActiveFuel5, pulseHighFuel5, pulseWidthFuel5);
if (pulseHighFuel6) handleFuelPulse2(14, pulseStartTimeFuel6, pulseActiveFuel6, pulseHighFuel6, pulseWidthFuel6);
if (pulseHighFuel7) handleFuelPulse2(15, pulseStartTimeFuel7, pulseActiveFuel7, pulseHighFuel7, pulseWidthFuel7);
if (pulseActiveFuel0) handleFuelPulse(8, pulseStartTimeFuel0, pulseHighFuel0);
if (pulseActiveFuel1) handleFuelPulse(9, pulseStartTimeFuel1, pulseHighFuel1);
if (pulseActiveFuel2) handleFuelPulse(10, pulseStartTimeFuel2, pulseHighFuel2);
if (pulseActiveFuel3) handleFuelPulse(11, pulseStartTimeFuel3, pulseHighFuel3);
if (pulseActiveFuel4) handleFuelPulse(12, pulseStartTimeFuel4, pulseHighFuel4);
if (pulseActiveFuel5) handleFuelPulse(13, pulseStartTimeFuel5, pulseHighFuel5);
if (pulseActiveFuel6) handleFuelPulse(14, pulseStartTimeFuel6, pulseHighFuel6);
if (pulseActiveFuel7) handleFuelPulse(15, pulseStartTimeFuel7, pulseHighFuel7);
}
Don't stress specific units.
-
antus
- Site Admin
- Posts: 10012
- Joined: Sat Feb 28, 2009 10:34 am
- cars: TX Gemini 2L Twincam 8psi
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Subaru WRX 2007
Re: Coding my own open source 24x ECU [beta available]
Sure is. Now you are in the land of pointers. That is often considered advanced C in tutorial.Apparetly the "&" on variables passed to the pulse handler functions is pretty damn important.
When you put the & in front of the variable or array element the compiler will use the address of the data, not the data itself. A very different thing. This is sometimes done as an optimisation, depending on the context. Sometimes when you want to modify data in place for speed instead of copying it, modifying it and writing it back. Absolutely if the compiler treats a pointer (a variable with an * in front of the name of it, which makes it store an address, not data) as data it'll corrupt the memory address, and if you treat data as a pointer you'll probably read or write invalid memory. What happens then depends on the platform. On a PC it'll crash, on an pi pico it might crash mbed, or hardware, or might keep running. But these sorts of bugs are exactly why C has a bad reputation for security, and a good reputation for being able to write fast code when used correctly. Bugs can be hard to find, because the crash may come much later after its been triggered depending on what happened.
In your case its passing the address of those bools so that you can update the original data, instead of a local copy of the variable that you'd then need to return and save back to the original location if you didn't.
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396
-
AngelMarc
- Posts: 612
- Joined: Sat Apr 08, 2023 11:23 am
- cars: A CB450 running to 8,000RPM with a P59.
Re: Coding my own open source 24x ECU [beta available]
OK, then that's how it's effectively making multiple copies for overlapping channel pulses without... "cross talk". Function call and not some compile level thing to just make writing repetative code unneeded. Also, seemed no "&" just used the initialized value of zero, without updating, didn't verify that, because whatever it was doing was wrong and just needed changed.
I've left it running overnight before with pointers (before splitting the handlers), woke up to it doing the same thing it's suppose to do.
not going to pretend I understand all of what you said. Just like I'm not going to get use to what programmers consider a "3D array".
I've left it running overnight before with pointers (before splitting the handlers), woke up to it doing the same thing it's suppose to do.
not going to pretend I understand all of what you said. Just like I'm not going to get use to what programmers consider a "3D array".
Don't stress specific units.