Page 10 of 19
Re: Coding my own aftermarket ECU
Posted: Wed Jun 11, 2025 11:51 pm
by AngelMarc
Looking at this, it might be more accurate to say the range of interpolation "noise" is Frac = 0 to Frac = what the code calculation says it should be.
https://www.youtube.com/watch?v=A4_zRVw8nag
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 2:52 am
by AngelMarc
My best guess is, code throws the math at floating point unit, which takes multiple clock cycles to complete the math, but after just one clock cycle, grabs the value before the multiple cycle float math finishes... a race condition. Something like that. Not trying to fix that today. I'll test it later with a short delay (a few microseconds) after lines with float math. See if it get's more consistent. Go for optimizing after that.
EDIT: Didn't work.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 5:05 pm
by AngelMarc
Blindly stabbing at it by replacing variables with constants make it seem like its signal generator instability... but I only see a measurable 5 RPM variation.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 6:08 pm
by AngelMarc
It's not the interpolation code itself.
Code: Select all
// --- Calculate RPM timing (µs per event) ---
unsigned long RPMTime = pulseHighTime + pulseLowTime;
RPMTime = constrain(RPMTime, 134, 125000); // 18600 RPM to 20 RPM
IndexFull = (2500000/(RPMTime*600));
IndexWhole = (int)IndexFull;
IndexPlusOne = IndexWhole + 1;
IndexPlusOne = constrain(IndexPlusOne, 0, 31);
TerpA = Iend[9][adcIndex];//
TerpB = Iend[10][adcIndex];//
Diff = TerpB - TerpA;
Frac = .5; //IndexFull - IndexWhole;
TerpC = Diff * Frac;
TerpD = TerpA + TerpC;
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 6:11 pm
by AngelMarc
No interpolation, just involving a truncated float. Horrible results
Code: Select all
unsigned long RPMTime = pulseHighTime + pulseLowTime;
RPMTime = constrain(RPMTime, 134, 125000); // 18600 RPM to 20 RPM
IndexFull = (2500000/(RPMTime*600));
IndexWhole = (int)IndexFull;
//IndexPlusOne = IndexWhole + 1;
//IndexPlusOne = constrain(IndexPlusOne, 0, 31);
//TerpA = Iend[IndexWhole][adcIndex];//
//TerpB = Iend[IndexPlusOne][adcIndex];//
//Diff = TerpB - TerpA;
//Frac = .5; //IndexFull - IndexWhole;
//TerpC = Diff * Frac;
//TerpD = TerpA + TerpC;
// --- Update delay values from tables ---
currentOnDelay11 = Dstart[IndexWhole][adcIndex];
currentOffDelay11 = Dend[IndexWhole][adcIndex];
currentOnDelay4 = Istart[IndexWhole][adcIndex];
currentOnDelay4 = Iend[IndexWhole][adcIndex];
//currentOffDelay4 = TerpD;
https://www.youtube.com/watch?v=Z99Jf7TEtJo
Replacing
Code: Select all
IndexFull = (2500000/(RPMTime*600));
IndexWhole = (int)IndexFull;
with
Code: Select all
IndexWhole = (int)(2500000/(RPMTime*600));
Get's rid of the weird double spikes... somehow.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 6:15 pm
by antus
It can only be a race condition if you have things running in parallel, eg one in the main thread on the main CPU and code in an interrupt handler that can interrupt the main loop and run something else. Or an MCU with 2 cores and you have code running in both. Since its bare metal there is no operating system to provide threads in software that could create a race condition.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 6:45 pm
by AngelMarc
ChatGPT suggested fixed point code that works better, but still seems awefuly sloppy.
Code: Select all
unsigned long RPMTime = pulseHighTime + pulseLowTime;
RPMTime = constrain(RPMTime, 134, 125000); // Clamp RPMTime for your RPM range
// Calculate IndexFull in fixed-point 16.16 format
uint32_t IndexFull_fixed = (uint32_t)((2500000ULL << 16) / (RPMTime * 600UL)); // <<16 for fractional bits
uint16_t Frac_fixed = IndexFull_fixed & 0xFFFF; // Fractional part (0 to 65535)
uint8_t IndexWhole = (IndexFull_fixed >> 16); // Whole part
IndexWhole = constrain(IndexWhole, 0, 31);
uint8_t IndexPlusOne = constrain(IndexWhole + 1, 0, 31);
// Get lookup values from your table
uint16_t TerpA = Iend[IndexWhole][adcIndex];
uint16_t TerpB = Iend[IndexPlusOne][adcIndex];
// Integer linear interpolation: TerpD = TerpA + ( (TerpB - TerpA) * Frac_fixed ) >> 16;
int16_t Diff = (int16_t)TerpB - (int16_t)TerpA;
uint16_t TerpD = TerpA + ((int32_t)Diff * Frac_fixed >> 16);
// TerpD is your interpolated result, integer, .00 precision (whole number)
I sweep the analog input and see a range that looks just as bad as float.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 6:46 pm
by AngelMarc
antus wrote: ↑Thu Jun 12, 2025 6:15 pm
It can only be a race condition if you have things running in parallel, eg one in the main thread on the main CPU and code in an interrupt handler that can interrupt the main loop and run something else. Or an MCU with 2 cores and you have code running in both. Since its bare metal there is no operating system to provide threads in software that could create a race condition.
It's my understanding Arduino uses MBed OS as firmware for ARM.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 6:54 pm
by antus
Hmm thats interesting. I thought arduino was all C on bare metal. A quick google found me this
https://forum.arduino.cc/t/is-it-possib ... d/1162356/ and also a few notes that say mbed goes end of life mid 2026. So I think you may have 3 opions. mbed, arduino core or bare metal. Ill have to read some more.
Re: Coding my own aftermarket ECU
Posted: Thu Jun 12, 2025 7:03 pm
by AngelMarc
I'm not crazy about the abstraction layers, but I'm certainly not ready to do this in assembly. Extra windows with "live" updates of some of the compilation steps would be cool. Arduino specific library interporated away, then idk plain C, then assembly. Not sure how much it would help me right now; but I'm sure it'd be wonderful for some. Something like Ghidra's function graph, scroll one and it shows you where it is in the other.