Coding my own aftermarket ECU [beta available]

Post Reply
User avatar
antus
Site Admin
Posts: 9002
Joined: Sat Feb 28, 2009 8:34 pm
cars: TX Gemini 2L Twincam
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Contact:

Re: Coding my own aftermarket ECU

Post by antus »

Why dont you put something in your build system to make an xdf for tunerpro? you can make the xdf in tunerpro but put some magic numbers in for addreses and in your build system setup something to read the address after compilation and search and replace the magic numbers with real numbers in the xdf.
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
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 »

This will be easier and just as capable.
Unless it shits itself when I tell it to combine all the values into a single string with appropriate punctuation/syntax.
Last edited by AngelMarc on Tue Jun 10, 2025 8:25 pm, edited 2 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 »

Also, I know enough about computers and engines to go back and forth with AI until it spits out chunks of code that actually do what I expect, then Integrate those chunks as I go, manually making small edits here and there. This stuff is 99% AI written. I'm more.... CEO than coder on this one.
The crank signal generator code was all me; not the ECU.
Don't stress specific units.
User avatar
antus
Site Admin
Posts: 9002
Joined: Sat Feb 28, 2009 8:34 pm
cars: TX Gemini 2L Twincam
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Contact:

Re: Coding my own aftermarket ECU

Post by antus »

Yeah all good. It's not how I would approach the problem, and I think I know what you are up against, but I am not closed minded and watching with interest to see how you go. It's not every day someone tries to write their own ECU, especially someone without the programmer background using AI tools.
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
hjtrbo
Posts: 227
Joined: Tue Jul 06, 2021 6:57 pm
cars: VF2 R8 LSA
FG XR6T
HJ Ute w/RB25DET

Re: Coding my own aftermarket ECU

Post by hjtrbo »

Excel has python
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 »

Any math wiz know how to get the row RPMtime to = the row index, with 1 formula?
The goal is even RPM spacing for VE table. Don't need those exact RPM values in the end. close is good enough.
EDIT: Had index in reverse order. Fixed attachment.
Attachments
f71bdd2fa105d5fae564a7165db8947896d1373e.png
f71bdd2fa105d5fae564a7165db8947896d1373e.png (95.85 KiB) Viewed 166 times
Last edited by AngelMarc on Wed Jun 11, 2025 9:20 am, edited 1 time in total.
Don't stress specific units.
User avatar
antus
Site Admin
Posts: 9002
Joined: Sat Feb 28, 2009 8:34 pm
cars: TX Gemini 2L Twincam
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Contact:

Re: Coding my own aftermarket ECU

Post by antus »

Normally you'd use a 3d lookup function that averages the cells proportionately to the actual value. Once you have the function you'd use that for all your 3d lookups. GM optimised the hell out of it in the VPW computers, and made it complex at the same time, but thats not required. You probably only need x and y resolution to bounds check, x and y values to lookup, and possibly a data type unless you are always using the same data format or have a different lookup per type.
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
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 »

Ah, found the no decimal number format option.
Getting closer, but dropping more resolution than I want at the stupid high RPM values.
Attachments
Capture.PNG
Capture.PNG (48.2 KiB) Viewed 160 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 »

antus wrote: Wed Jun 11, 2025 9:11 am GM optimised the hell out of it in the VPW computers, and made it complex at the same time, but thats not required.
just hope whatever I end up with doesn't add so much to the loop that it can't handle high RPM by the time it's all done, with IAT added and what not... and external correction inputs. That's been in the back of my mind for a while; a way to add wideband, torque reduction for transmission shift etc. That's all end of the list though.
I suppose interpolation between all cells might be enough to solve nearly all of it.
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 »

That is a perfect question for AI:

RPMtime = (2,500,000 / ( index - 1 )) * 600
Index = 1 + (2,500,000 * (RPMtime * 600))

https://chatgpt.com/share/6848bfe0-99f0 ... 51d98a254c


Regarding lookup tables, here are some functions I've used before:

Code: Select all

  uint16_t lookup_2d_linear(uint16_t reference, uint16_t *table, uint8_t tableSize, uint16_t tableMin, uint16_t tableMax){ //16 bit
    uint8_t index = 0; //Index of the first of 2 interpolated table entries
    uint16_t cellSize = (tableMax - tableMin) / ( tableSize - 1); // => "range of table" / "number of entries in table"
    if(reference < tableMin){
        index = 0; //use the first 2 entries
    } else if(reference > tableMax){
        index = tableSize - 2; //use the last 2 entries
    } else {
        index = (reference - tableMin) / cellSize; 
    }
    uint16_t x0 = tableMin + (index * cellSize);
    uint16_t x1 = tableMin + ((index + 1) * cellSize);
    uint16_t y0 = pgm_read_word(&(table[index]));
    uint16_t y1 = pgm_read_word(&(table[index + 1]));
    return (((uint32_t)y0 * (x1 - reference)) + ((uint32_t)y1 * (reference - x0))) / (x1 - x0); //linear interpolation
}

uint8_t lookup_2d_linear(uint16_t reference, uint8_t *table, uint8_t tableSize, uint16_t tableMin, uint16_t tableMax){ // 8 bit
    uint8_t index = 0; //Index of the first of 2 interpolated table entries
    uint16_t cellSize = (tableMax - tableMin) / ( tableSize - 1); // => "range of table" / "number of entries in table"
    if(reference < tableMin){
        index = 0; //use the first 2 entries
    } else if(reference > tableMax){
        index = tableSize - 2; //use the last 2 entries
    } else {
        index = (reference - tableMin) / cellSize; 
    }
    uint16_t x0 = tableMin + (index * cellSize);
    uint16_t x1 = tableMin + ((index + 1) * cellSize);
    uint16_t y0 = pgm_read_byte(&(table[index]));
    uint16_t y1 = pgm_read_byte(&(table[index + 1]));
    return (((uint32_t)y0 * (x1 - reference)) + ((uint32_t)y1 * (reference - x0))) / (x1 - x0); //linear interpolation
}

uint16_t lookup_3d_linear(uint16_t xRef, uint16_t yRef, uint16_t **table, uint8_t xSize, uint16_t xMin, uint16_t xMax, uint8_t ySize, uint16_t yMin, uint16_t yMax){
    /*  xRef / yRef = column (x) and row (y) values that we want to lookup 
        xSize / ySize = number of columns + rows in this table
        xMin / xMax / yMin / yMax = minimum/maximum values of each axis of this table (first and last row/columns value)
    */
    uint8_t colIndex = 0; //X value
    uint8_t rowIndex = 0; //Y value
    uint16_t xCellSize = (xMax - xMin) / (xSize - 1);
    uint16_t yCellSize = (yMax - yMin) / (ySize - 1);
    if(xRef < xMin){
        colIndex = 0; //use first 2 entries along x axis
    } else if(xRef > xMax){
        colIndex = xSize - 2; //use last 2 entries along x axis
    } else {
        colIndex = xRef / xCellSize;
    }
    if(yRef < yMin){
        rowIndex = 0; //use first 2 entries along y axis
    } else if(yRef > yMax){
        rowIndex = ySize - 2; //use last 2 entries along y axis
    } else {
        rowIndex = yRef / yCellSize;
    }
    uint16_t x1 = xMin + (colIndex * xCellSize); //Column axis value preceding
    uint16_t x2 = xMin + ((colIndex + 1) * xCellSize); //column axis value following
    uint16_t y1 = yMin + (rowIndex * yCellSize); //Row axis value preceding
    uint16_t y2 = yMin + ((rowIndex + 1) * yCellSize); //Row axis value following
    //Multiply index's by 2 as reading a 16 bit value:
    uint16_t q11 = pgm_read_word((uint16_t)table + ((rowIndex * 2) * xSize) + (colIndex * 2)); //Get value at: row preceding, column preceding
    uint16_t q12 = pgm_read_word((uint16_t)table + (((rowIndex + 1) * 2) * xSize) + (colIndex * 2)); //Get value at: row following, column preceding
    uint16_t q21 = pgm_read_word((uint16_t)table + ((rowIndex * 2) * xSize) + ((colIndex + 1) * 2)); //Get value at: row preceding, column following
    uint16_t q22 = pgm_read_word((uint16_t)table + (((rowIndex + 1) * 2) * xSize) + ((colIndex + 1) * 2)); //Get value at: row following, column following
    uint16_t r1 = (q11*((float)(x2 - xRef)/(x2 - x1))) + (q21*((float)(xRef - x1)/(x2 - x1))); //Linear interpolate along X axis, row preceding 
    uint16_t r2 = (q12*((float)(x2 - xRef)/(x2 - x1))) + (q22*((float)(xRef - x1)/(x2 - x1))); //Linear interpolate along X axis, row following
    return (uint16_t)((r1*((float)(y2 - yRef)/(y2 - y1))) + (r2*((float)(yRef - y1)/(y2 - y1)))); //Linear interpolate Y axis down column between 2 interpolated row values
}
 

These can be used with arrays (which I initialise with defines in a header file specifically for calibration data, keeping code and data in seperate files. These defines are used inside a struct to hold the data in my source file):

Code: Select all

   #define TABLE_EGT2_INPUT_CONVERSION_SIZE 26
#define TABLE_EGT2_INPUT_CONVERSION_MIN 0
#define TABLE_EGT2_INPUT_CONVERSION_MAX 5000
#define TABLE_EGT2_INPUT_CONVERSION_3K3  { \
    /*3.3K pullup - used to lookup EGT2 temperature from an input voltage*/ \
    850,    /* 0 - 0  V */ \
    688,    /* 1 - 0.2V */ \
    532,    /* 2 - 0.4V */ \
    455,    /* 3 - 0.6V */ \
    404,    /* 4 - 0.8V */ \
    367,    /* 5 - 1.0V */ \
    337,    /* 6 - 1.2V */ \
    312,    /* 7 - 1.4V */ \
    290,    /* 8 - 1.6V */ \
    271,    /* 9 - 1.8V */ \
    254,    /* 10 - 2.0V */ \
    238,    /* 11 - 2.2V */ \
    223,    /* 12 - 2.4V */ \
    208,    /* 13 - 2.6V */ \
    194,    /* 14 - 2.8V */ \
    180,    /* 15 - 3.0V */ \
    167,    /* 16 - 3.2V */ \
    153,    /* 17 - 3.4V */ \
    139,    /* 18 - 3.6V */ \
    124,    /* 19 - 3.8V */ \
    109,    /* 20 - 4.0V */ \
    92,     /* 21 - 4.2V */ \
    72,     /* 22 - 4.4V */ \
    47,     /* 23 - 4.6V */ \
    12,     /* 24 - 4.8V */ \
    0       /* 25 - 5.0V */ \
}

It's been interesting watching you try and nut this out. But I would encourage trying to use the AI to help you understand whats happening, rather than writing it all for you. Especially if the goal is to actually learn how to do what you're doing.
Questions like "what could a formula for this be" are great for AI, when theres a highly specific set of data or objective. Open ended questions sometimes not so much.

That being said I do the same. I've never used python much, but recently Ive been working on a project and using python (mainly AI generated) as a tool to do what I need to do (collect data, format it, etc. etc.). After a month or so I feel like I've learnt nothing about python, im still asking it very basic questions (like how do I loop through this, or getting confused betweena list tuple or dictionary). But I've got some absolutely brilliant python scripts to do very useful things and make my life super easy. But my objective isn't to learn python, it's to learn about what I'm working on so I can implement the final project in C / C++
Post Reply