Coding my own aftermarket ECU [beta available]

Post Reply
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Coding my own aftermarket ECU [beta available]

Post by AngelMarc »

EDIT: Most recent progress
A simple beta is ready if anybody is willing to VE edit in the arduino source code tables.
https://www.youtube.com/watch?v=bqC3ijvPBOU
Capture.PNG
Capture.PNG (37.92 KiB) Viewed 2 times
Currently only targeting Pi Pico. Timer strategy requires it.
If you have a different Arduino compatible 32bit board with a 64 bit timer and 2 analog inputs, feel free to try.
All code is generic for easy porting of the entire project or just snippets, like crank decode logic.
Maybe Alpha is more appropriate.
DM if interested/require instructions.
GM 24x crank signal only.
17x17 tables using bilinear interpolation.
Only setup for a single cylinder, or even-fire twin, or single cylinder 2 stroke.
Can be expanded to 4, 6, 8, or 12 cylinder fuel and spark later.
Current max RPM for tables is about 9,600. Start out more reasonable.
Whatever BAR MAP sensor you want.
IAT scaling for spark and fuel.
Added EOIT that get's disregarded when required to hit high injector duty cycle and has it's own interpolation.
If you want, you can turn off temp scaling pretty easy, or leave it on just for fuel and use a potentiometer as a manual choke.
Waste spark only, injector is same, once per revolution. I plan to test on a small 2 stroke first.
There's 50 microseconds of "noise"/inaccuracy on output pulse timing, and there seems to be a minimum on time before it just stays zero, I think that number was 100-150 microseconds.
Added a spark-cut rev limiter.
Added minimum of 20 RPM to shut off fuel and spark.

ECU.ino

Code: Select all

#define CRANK_SENSOR_PIN 2  
#include "TuneArrays.h" 
//#include <mbed/platform/bare_metal/

enum PinState { WAITING_FOR_ON, WAITING_FOR_OFF };
PinState pinState = WAITING_FOR_ON;
unsigned long previousToggleTime = 0;
uint8_t RPMIndex = 0;
uint8_t adcIndex = 0;
bool pulseActive = false;
bool triggerPulse = false;
// Pin 11 (pattern1)
bool pulseActive11 = false;
bool triggerPulse11 = false;
unsigned long pulseStartTime11 = 0;
unsigned long currentOnDelay11 = 1000;
unsigned long currentOffDelay11 = 1000;
// Pin 4 (pattern0)
bool pulseActive4 = false;
bool triggerPulse4 = false;
unsigned long pulseStartTime4 = 0;
unsigned long currentOnDelay4 = 1000;
unsigned long currentOffDelay4 = 1000;

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;
const uint8_t pattern0 = 0b00001111; //Fuel cycle strat/end point
const uint8_t pattern1 = 0b01111101; //Spark max advance point. +/- 15 degrees, round up to more advance
uint8_t avg8bit = 0;

void handleCrankSignal() {
  unsigned long currentTime = micros();
  if (digitalRead(CRANK_SENSOR_PIN) == HIGH) {
    pulseHighTime = currentTime - lastTime;
  } else {
    pulseLowTime = currentTime - lastTime;
    uint8_t bit = (pulseHighTime > pulseLowTime) ? 0 : 1;
    signalHistory = ((signalHistory << 1) | bit) & 0xFF;
    if (signalHistory == pattern1) triggerPulse11 = true;
    if (signalHistory == pattern0) triggerPulse4 = true;
    newSample = true; // flag to loop()
  }
  lastTime = currentTime;
}

void setup() {
  analogReadResolution(12);
  pinMode(4, OUTPUT);
  pinMode(11, OUTPUT);
  digitalWrite(11, LOW);
  previousToggleTime = micros();
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(CRANK_SENSOR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(CRANK_SENSOR_PIN), handleCrankSignal, CHANGE);
}

void loop() {
  if (newSample) {
    newSample = false;

    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_fixed = ((uint64_t)2500000 << 8) / ((uint32_t)RPMTimeavg * 600);
    uint Predicted360Time = RPMTimeavg * 24;
    uint16_t IndexWhole = IndexFull_fixed >> 8;
    uint8_t Frac = IndexFull_fixed & 0xFF;                                         
    int Frac2 = avg12bit & 0xFF;



    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){
      Scaled3 = 0UL; //Fuel off if RPM below minimum = 20RPM
    }

    // --- Update delay values from tables ---
    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;
    }
  }
}
TuneArrays.h

Code: Select all

volatile int IATFuel[129] = {128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272,274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344,346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380,382,384};
//Comment above and uncomment below for no temp scaling, 256 = 100% or no change
//volatile int IATFuel[129] = {256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256};
volatile int IATSpark [129] = {128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272,274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344,346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380,382,384};
//Comment above and uncomment below for no temp scaling, 256 = 100% or no change
//volatile int IATSpark [129] = {256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256};

volatile unsigned long Limiter = 277; //Spark cut rev limiter, microseconds per 15 degrees. divide 2,500,000 by this number to get RPM. Limiter is set after rolling average and before being constrained for table access, can be set beyond table limits

volatile unsigned long EOIT [17] = {500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500};// these were test values, also in microseconds, change as needed
 //                                             0 RPM -------------------------------------------------------------------------9600 RPM same 600 spacing
volatile unsigned long Dstart [17] [17] = { //lower numbers = more advance, numbers are in microseconds
{10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000},//"0" RPM
{9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500, 9500},// 600
{9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000},// 1200
{8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500, 8500},// 1800
{8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000},// 2400
{7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500},// 3000
{7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000, 7000},// 3600
{6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500, 6500},// 4200
{6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000},// 4800
{5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500},// 5400
{5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000},// 6000
{4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500},// 6600
{4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000},// 7200
{3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500},// 7800
{3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000},// 8400
{2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500},// 9000
{2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000} // 9600
};//low KPA --------------------------------------------------------------------------------- high KPA

volatile unsigned long Iend [17] [17] = { //injector on time, in microseconds
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},//"0" RPM
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 600
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 1200
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 1800
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 2400
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 3000
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 3600
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 4200
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 4800
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 5400
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 6000
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 6600
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 7200
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 7800
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 8400
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 9000
{1000, 2200, 3400, 4600, 5800, 7000, 8200, 9400, 10600, 11800, 13000, 14200, 15400, 16600, 17800, 19000, 20000},// 9600
};//low KPA --------------------------------------------------------------------------------- high KPA
For convenience if somebody tries. Also updated array comments with these labels and KPA direction.
Index.PNG
Index.PNG (14.99 KiB) Viewed 95 times
Original post-
Just going to dump progress and ideas of logic flow.
Updates will be sparse and slow. Largely from hunting for right syntax references.
I think spark timing/dwell will be handled by multiple arrays. One for start of dwell, one for end.
Same for fuel.
Will use 24x wheel. No cam, waste spark/batch fire.
Similar decode logic to what GM used.
AngelMarc wrote: Wed Apr 30, 2025 2:44 pm Ok, signed (+/-) start at zero, count down when low, up when high, move MSB of counter (for the +/-) each time signal goes low, into a shift register.
I knew it had to be a list of 1s and 0s, but I love this simple thing that can likely be done with common arduinos.
A little validation on a theory is nice every now and then. Great read.
With an array for the pattern to point at correct cylinder

Hopefully I don't run out of RAM.
If I can offset array values by a set amount for each cylinder, that'd be how timing is changed for V6, V8, V2 etc. As long as 15 degree increments work for the engine.
Sensor calibration will be done by the same array tables, deal with it.
Sensor count will be minimal.
No idle management routines.
Cylinder count limit currently unknown.
How to get it all going without overlap restrictions and racing-code conditions... I don't know yet.
Last edited by AngelMarc on Mon Jun 16, 2025 11:45 pm, edited 36 times in total.
Don't stress specific units.
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Re: Coding my own aftermarket ECU

Post by AngelMarc »

Nearly an hour just trying to get some formatting/syntax right so I can even see what space could be taken up by tune/cal.
It also didn't like me specifying "long" instead of "unsigned long"... "narrowing conversion from long long int, to long" ... um, no.
Attachments
Capture.PNG
Last edited by AngelMarc on Fri May 02, 2025 8:13 am, edited 1 time in total.
Don't stress specific units.
User avatar
pman92
Posts: 577
Joined: Thu May 03, 2012 10:50 pm
Location: Castlemaine, Vic
Contact:

Re: Coding my own aftermarket ECU

Post by pman92 »

You're missing a set of { } to cover the whole lot, and your array is backwards.
You've specified an array of 12 arrays with length 20. But then shown 20 arrays with length 12.

As for working out how much space, you dont actually need to define all the data. " = { }" is enough to allocate memory.
But even easier, 12 x 20 items of type unsigned long (4 bytes each) = 12 x 20 x 4 = 960 bytes of memory.
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Re: Coding my own aftermarket ECU

Post by AngelMarc »

Thank you. Need a quick reference manual as helpful as you. I'm not an encyclopedia that can remember all this arbitrary syntax.
Attachments
Capture.PNG
Don't stress specific units.
User avatar
pman92
Posts: 577
Joined: Thu May 03, 2012 10:50 pm
Location: Castlemaine, Vic
Contact:

Re: Coding my own aftermarket ECU

Post by pman92 »

Try chatGPT. It's excellent for stuff like that.
Just tell it you want short answers and you dont want it to try and take over.
If you let it start writing code for you, you'll generally get it working in the end, but you'll learn nothing in the process.
Just keep it for when you get stuck on stuff like that. The show it your code, show it the error you're getting, and it will point out the problem for you
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Re: Coding my own aftermarket ECU

Post by AngelMarc »

I forgot. My approach requires this insanity.
And compiler doesn't just tell me what that consumes.
Attachments
Capture.PNG
Capture.PNG (29.69 KiB) Viewed 1826 times
Don't stress specific units.
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Re: Coding my own aftermarket ECU

Post by AngelMarc »

EDIT: think I did my math wrong.
65,536 bytes, so before it was 131,072 bytes.
1 good thing about that circuit python nonsense, the units meant for it have excess resources.
Messed up the edit and deleted original. Don't know how I originally got 20kB.
Attachments
Capture.PNG
Capture.PNG (19.21 KiB) Viewed 1823 times
Last edited by AngelMarc on Wed May 28, 2025 2:03 am, edited 4 times in total.
Don't stress specific units.
User avatar
pman92
Posts: 577
Joined: Thu May 03, 2012 10:50 pm
Location: Castlemaine, Vic
Contact:

Re: Coding my own aftermarket ECU

Post by pman92 »

The [20][256] table is over 20kb by itself

20 x 256 x 4
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Re: Coding my own aftermarket ECU

Post by AngelMarc »

Oh, yes, I forgot to x4 that.
Don't stress specific units.
User avatar
AngelMarc
Posts: 243
Joined: Sat Apr 08, 2023 9:23 pm
cars: A CB450 running to 8,000RPM with a P59.

Re: Coding my own aftermarket ECU

Post by AngelMarc »

To keep code more generic, I think I'll just compare 2 counters. Each counter will increment with the high and low of crank signal, then those numbers get compared with an if < or if > for the 24X decode.
Don't stress specific units.
Post Reply