Skip to content

Latest commit

 

History

History
218 lines (163 loc) · 8.15 KB

File metadata and controls

218 lines (163 loc) · 8.15 KB

Ignition System Architecture

zigEFI supports multiple ignition control strategies, from fully mechanical to full ECU control. The mode is selected in EngineConfig.ignition.mode at compile time.


Mode 1: Disabled (distributor handles everything)

config: .mode = .disabled

The distributor's mechanical and vacuum advance mechanisms control timing. The ECU reads the VR pickup signal for RPM measurement only. No ignition outputs are used.

Use this when:

  • Running a stock distributor with functional advance mechanisms
  • Developing and testing fuel-only control before adding ignition
  • You don't trust the ECU yet (smart)

Wiring:

Distributor VR pickup ──→ uaEFI VR2 input (PE1)   [RPM only]
Ignition module ──→ Coil ──→ Distributor cap        [stock wiring]

Mode 2: Distributor (ECU-controlled timing)

config: .mode = .distributor

The ECU replaces the factory ignition module (e.g. Ford Duraspark II, TFI, GM HEI module). The distributor cap still routes spark to the correct cylinder — the ECU controls when the spark fires using a programmable advance table.

Requirements:

  • Lock out mechanical advance (weld centrifugal weights or use a locked distributor)
  • Block vacuum advance (cap the vacuum port)
  • Remove the factory ignition module
  • Wire the VR pickup directly to the ECU
  • Wire the ECU ignition output to a coil driver or directly to the coil

Wiring:

Distributor VR pickup ──→ uaEFI VR2 input (PE1)    [position + RPM]
uaEFI IGN1 output (PC13) ──→ Coil driver ──→ Coil  [timing control]
Coil high voltage ──→ Distributor cap ──→ Plugs     [spark distribution]

How it works:

  1. VR pickup generates a pulse as each reluctor tooth passes (V8 = 4 pulses/crank rev)
  2. Timer input capture ISR records the pulse timestamp
  3. Period between pulses gives RPM
  4. Look up advance from the 2D table (RPM x MAP)
  5. Calculate fire delay relative to the VR pulse:
degrees_between_pulses = 360 / distributor_pulses_per_rev   (V8 = 90 degrees)
time_per_degree = pulse_period_us / degrees_between_pulses
fire_delay = (ref_angle - desired_advance) * time_per_degree

Where ref_angle is the mechanical angle of the VR pickup with advance locked out (typically 10 degrees BTDC on a Ford).

  1. Schedule dwell start: dwell_start = fire_time - dwell_us
  2. At dwell_start: set IGN1 HIGH (coil charging)
  3. At fire_time: set IGN1 LOW (coil releases, spark fires)

Timing diagram:

VR pulse         next VR pulse
    │                 │
    ▼                 ▼
────┤                 ├────
    │                 │
    │   ┌─────────┐   │
IGN1│   │  DWELL  │   │
────┘   └─────────┘───┘
        ↑         ↑
    dwell start  SPARK

Advance table:

The advance table is 16x16, RPM x MAP, with values in degrees BTDC. More advance at light load (high vacuum / low MAP), less at heavy load (high MAP / low vacuum). This replaces both the mechanical weights (RPM-based advance) and vacuum canister (load-based advance).

.advance_table = .{
    //  vacuum ◄──────────────────────────────► full load
    //  15   20   25   30   35   40   50   60   70   80   85   90   95  100  kPa
    .{ 34, 33, 32, 31, 29, 28, 26, 24, 22, 20, 18, 17, 16, 15 }, // 2000 RPM
    .{ 38, 37, 36, 34, 33, 31, 29, 27, 25, 23, 21, 19, 18, 17 }, // 3000 RPM
    // more advance at high RPM + light load
    // less advance at high RPM + heavy load (knock prevention)
};

Dwell compensation:

Coil charge time (dwell) must increase as battery voltage drops to maintain spark energy. The dwell_voltage_comp table maps voltage to dwell time:

14V = 3000 us (base)
12V = 3600 us
10V = 4200 us
 8V = 5000 us

Ford-specific notes (1982 SBF 302):

  • Duraspark II distributor: 8-tooth reluctor, ~10 degrees BTDC mechanical reference
  • Remove the blue Duraspark II ignition module (on the fender or firewall)
  • VR pickup has 2 wires (orange + purple on Ford) — connect to uaEFI VR2 input
  • Use a coil driver module between uaEFI IGN1 and the coil, or a logic-level coil (e.g. LS2 truck coil)
  • The uaEFI IGN outputs have on-board smart coil drivers rated for most modern coils
  • Stock Duraspark coil is fine but draws more current — verify against uaEFI driver ratings

Mode 3: Coil-on-Plug / Wasted Spark (future)

config: .mode = .coil_on_plug

NOT YET IMPLEMENTED — this section documents the architecture for future development.

Full ECU-controlled ignition with individual coil outputs. No distributor — the ECU fires each coil directly. Requires crank and cam position sensors for cylinder identification.

Crank/Cam Position Decoding

Modern engines use a toothed wheel on the crankshaft (typically 36-1 or 60-2 pattern) and a cam sensor for cylinder identification.

Trigger wheel patterns:

Pattern Description Common on
36-1 36 teeth, 1 missing (10 degrees/tooth) Ford, GM, many aftermarket
60-2 60 teeth, 2 missing (6 degrees/tooth) GM LS, many modern engines
36-1-1 36 teeth, 2 singles missing Some Bosch applications

Cam sync patterns:

Pattern Description Purpose
Single tooth 1 pulse per cam revolution Identifies cylinder #1 for sequential
Multi-tooth Multiple pulses at known positions Faster sync, VVT position feedback

Decoding Algorithm

1. Crank ISR fires on every tooth edge
2. Measure tooth-to-tooth period
3. Detect missing tooth: period > 1.5x average → gap found
4. Count teeth from gap → precise crank angle (within 6-10 degrees)
5. Interpolate between teeth for sub-tooth-degree precision
6. Cam sync pulse identifies which revolution (1 of 2 in 4-stroke cycle)
7. After sync: schedule each coil output at its cylinder's advance angle

Hardware Requirements

Inputs:

  • Crank VR/Hall sensor → uaEFI VR2 (PE1) or VR1 (PE0)
  • Cam Hall sensor → uaEFI HALL1 (PE12)

Outputs (wasted spark, V8 = 4 coils):

  • IGN1 (PC13) → Coil pack 1 (cyl 1+6)
  • IGN2 (PE5) → Coil pack 2 (cyl 5+8)
  • IGN3 (PE4) → Coil pack 3 (cyl 4+3)
  • IGN4 (PE3) → Coil pack 4 (cyl 2+7)

Outputs (coil-on-plug, V8 = 8 coils):

  • IGN1-IGN6 → 6 individual coils
  • Plus 2 additional coil outputs via INJ7/INJ8 or other GPIO

New Modules Needed

src/engine/
    crank_decoder.zig    Tooth counting, gap detection, angle tracking
    cam_sync.zig         Cylinder identification from cam sensor
    scheduler.zig        Angle-based event scheduling (replaces simple timer delay)

Key Differences from Distributor Mode

Aspect Distributor Coil-on-Plug
Position resolution ~90 degrees (V8) 6-10 degrees (per tooth)
Outputs 1 (IGN1) 4-8 (one per coil)
Cam sensor needed No Yes
Sync time Immediate (1 pulse) 1-2 crank revolutions
Cylinder ID Distributor cap handles it Cam sensor + software
Code complexity Low High

Why This Is Harder

Distributor mode has one input, one output, and simple delay math. Coil-on-plug needs:

  • Real-time tooth counting at up to 400+ teeth/second (7500 RPM * 60 teeth / 60 sec)
  • Sub-degree interpolation between teeth for precise timing
  • Synchronization state machine (unsync → crank sync → full sync)
  • Per-cylinder dwell and fire scheduling
  • Loss-of-sync detection and recovery
  • VVT angle feedback (if variable valve timing is used)

This is the hardest part of ECU firmware — it's where rusEFI and Speeduino invest most of their complexity. zigEFI will tackle it after the distributor mode is proven.


Implementation Priority

  1. .disabled — fuel-only, distributor handles timing (current)
  2. .distributor — ECU-controlled timing, single output (next)
  3. .coil_on_plug — full crank/cam decoding, individual coils (future)

Each mode is a superset of the previous. The VR input capture and advance table lookup from distributor mode are reused in coil-on-plug mode — just with higher resolution position tracking and multiple outputs.