ESP32 as engine ECU

Hello everyone,

I am new on this forum so I hope to do everything right. I have a Tomos A55 2 stroke moped with a stock CDI. This is an ignition module that charges a capacitor and releases the spark whenever a magnet passes the hall effect sensor on the flywheel.

Stock the ignition timing has a curve so at low rpm the timing advance is larger than at high rpm. I could not really get good info about this CDI but I think it starts at 1.5mm btdc and lowers to around 0.6mm.

I would like to use an ESP32 to trick the cdi by modifying the hall effect signal. I did this by connecting the hall effect sensor with a NPN 2n222 transistor to the ESP32 GPIO 34. This way I could get great rpm data. Because the hall effect sensor usually emits around 1 to 5v AC, I just connected GPIO 33 with the CDI directly so the CDI gets a 3.3v spike.

I managed to get the engine running and it idles fine, it also starts up quiet quickly. But if I give it some throttle the engine beginnes to act like some sort of rev limiter. It is really quiet strange.

Maybe someone has already done this and knows about what I should do differently? I will upload my code as well. I should also mention that I have very little experience with ESP and coding, so I mostly use chatgpt to help.

Thanks a lot!

Wouter


const int pickupPin = 34;
const int cdiPin    = 33;

volatile bool pulseFlag = false;
volatile unsigned long lastPickupMicros = 0;

float currentRPM = 0;
unsigned long pulseCount = 0;

// Pulslengte instellingen (µs)
const int minPulseWidth = 80;
const int maxPulseWidth = 350;

// Extra vertraging in microseconden (kan negatief zijn)
long extraDelay = 0; // start bij 0 µs

void IRAM_ATTR pickupISR() {
  pulseFlag = true;
  lastPickupMicros = micros();
  pulseCount++;
}

float mapPulseLength(float rpm) {
  if(rpm > 8000) rpm = 8000;
  return maxPulseWidth - ((rpm * (maxPulseWidth - minPulseWidth) / 8000.0));
}

void sendCDIPulse(float pulseLength) {
  digitalWrite(cdiPin, HIGH);
  delayMicroseconds((int)pulseLength);
  digitalWrite(cdiPin, LOW);
}

unsigned long lastTime = 0;

void setup() {
  Serial.begin(115200);
  pinMode(pickupPin, INPUT);
  pinMode(cdiPin, OUTPUT);
  digitalWrite(cdiPin, HIGH); // idle HIGH
  attachInterrupt(digitalPinToInterrupt(pickupPin), pickupISR, RISING);

  Serial.println("Type een vertraging in µs (bv 200 of -100) om de vonk te finetunen.");
}

void loop() {
  unsigned long now = millis();

  // RPM berekenen elke 500ms
  if(now - lastTime >= 500){
    noInterrupts();
    unsigned long pulses = pulseCount;
    pulseCount = 0;
    interrupts();

    currentRPM = pulses * 1.2; // 500ms interval -> *2*60
    lastTime = now;
  }

  // Pickup-flank afgehandeld
  if(pulseFlag){
    pulseFlag = false;

    float pulseLength = mapPulseLength(currentRPM);

    // Bereken geplande tijd voor vonk
    long plannedMicros = lastPickupMicros + extraDelay;

    // Wacht tot geplande tijd bereikt is
    while((long)(micros() - plannedMicros) < 0){
      // even niets doen, wachten
    }

    sendCDIPulse(pulseLength);
  }

  // Serial input voor dynamische vertraging
  if(Serial.available()){
    String input = Serial.readStringUntil('\n');
    input.trim();
    if(input.length() > 0){
      long newDelay = input.toInt();
      if(newDelay >= -5000 && newDelay <= 5000){ // limiet -5ms tot 5ms
        extraDelay = newDelay;
        Serial.print("Nieuwe extra delay: ");
        Serial.println(extraDelay);
      }
    }
  }

  // Debug
  static unsigned long lastPrint = 0;
  if(millis() - lastPrint > 500){
    lastPrint = millis();
    Serial.print("RPM: ");
    Serial.print(currentRPM);
    Serial.print(" | Extra delay: ");
    Serial.println(extraDelay);
  }
}

Hi, @woetner
Welcome to the forum.
Are you building an ECU or replacement CDI?

Have you Googled;

arduino ecu cdi

Tom.... :smiley: :+1: :coffee: :australia:

Hi Tom,

Thank you for your quick response.

I am trying to build a kind of ECU. I hope to quickly change the ignition timing based on engine temp, load and drive modes that I can choose from. I think this is possible using the stock cdi but modifying the pickup signal.

Wouter

How are you protecting the electronics for electrical noise and surges?

My newest version is as follows:

Pickup signal white wire -> 470r resistor -> OPTO PC817 anode (I measured the pickup output and it was around 1v per 1000rpm AC)
Pickup signal black wire -> OPTO PC817 cathode
Betwoon the anode and cathode a 1N4148 diode

OPTO PC817 emitter -> ESP and moped GND
OPTO PC817 -> 4.7k 3.3v pull-up -> ESP D34

ESP D33 -> 220R resistor -> CDI in (White wire)
ESP and moped GND -> CDI GND (black wire)

Yesterday I managed to get a full on rpm reading that worked and up to 9000 rpm reliable firing. The bike ran great! I could not yet test it under load while riding because of all the loose wiring.

I also have a MAX6675 temp sensor, and GM6 gps, a SPI 2.4 inch lcd, an electronic throttle, a servo for the throttle, some buttons, etc.

Are there things that can be optimised in my system? Once again 90% of this is ChatGPT and me prototyping.

Thanks a lot,

Wouter

I suggest you use an opto-coupler as a way to drive the CDI as well, and even more important to protect the ESP32 from the voltage spikes from the Bike & reverse voltages from the GND.

What happens when it gets a 60V spike on the battery line or if the battery gets connected backwards. Here is some good reading for you:
Valuable Resources for Automotive Electronics:

  1. STMicroelectronics Application Note AN2689:
    This application note provides guidelines on protecting automotive electronics from electrical hazards, focusing on design and component selection. Reading this will greatly enhance your understanding of automotive circuit protection.
    Read AN2689

  2. Analog Devices: Automotive Electronics Design:
    This article distills key insights into designing automotive electronics, offering practical advice for engineers.
    Read the article

  3. Diodes Incorporated: Transient Voltage Suppression in Automotive:
    Learn about techniques to protect automotive circuits from transient voltage, which is critical for ensuring reliable operation in harsh conditions.
    Read the article

  4. AEC-100 Standards Webinar:
    This webinar from Monolithic Power Systems provides a detailed overview of AEC standards, essential for understanding automotive electronics requirements.
    Watch the webinar

  5. Understanding Automotive Electronics, An Engineering Perspective by William B. Ribbens:
    This comprehensive book offers an in-depth look into automotive electronics from an engineering perspective, making it an invaluable resource.
    Access the book

  6. Check this for OBD ISO9141 Code Meaning & How To Fix OBD negotation initialization procedure https://cdn.standards.iteh.ai/samples/16738/20ff360c25c6462b811ebc0c9256eee0/ISO-9141-2-1994.pdf Then there is https://github.com/muki01/OBD2_K-line_Reader PID codes: OBD-II PIDs - Wikipedia

  7. Load Dump and Cranking Protection for Automotiv Backlight LED Power Suppl https://www.ti.com/lit/an/snva681a/snva681a.pd

  8. Quality requirements:

These resources should provide a strong foundation for anyone involved in automotive electronics design.

Is the engine running normal when you remove your stuff? Please show us a schematic of your circuit and how it is attached to the rest of the moped circuit.

Thanks for your input,

I will soon add a opto to try this. I do like the peace of mind of isolating the ESP from the CDI.

Thanks a lot!

This is a lot of useful stuff. I will sure check it out.

The engine runs fine without my additions. I do however got the engine to run great using my additions since yesterday. I will add a schematic soon.

Great to see you are making progress with the project!