Abstract

A cammed idle is marginal by nature — high overlap means a heavily diluted, residual- rich charge that burns slowly and unevenly. Stability comes from getting the architecture right: airflow owns RPM, ignition is a fast trim, feed-forward is deliberately conservative, and every common stall maps to one specific, diagnosable cause. Tune the cause, not the symptom.

The architecture (EMU Black v3)

The single biggest mental shift: airflow PID is the primary RPM controller; ignition timing is fast-path fine-tuning only (the opposite of older setups). On a 264° cam the engine barely responds to timing at idle anyway — so timing is run flat (~16°) and the airflow target does the work. Layered on top:

  • An active-state airflow table (the feed-forward base the PID rides on, above 400 RPM).
  • A separate cranking airflow table below 400 RPM, pre-positioned so the handoff at 400 RPM has no step — a step would take multiple ~740 ms manifold time constants to settle and disturb RPM.
  • An armed-state table for the overrun window before idle PID engages.

Why cammed engines stall — and the fix

The notes catalog the stall patterns; nearly every one is a specific, logged cause:

  • Overrun-to-idle (the most common): armed-state airflow resolves too low at the decel RPM bins, the DBW motor fights its return spring at −80% DC with no useful air, and fuel returns into a near-zero air column → rich stumble → stall. Fix: populate armed-state airflow at 60–80% at 1800–2200 RPM, tapering seamlessly into the idle value — no step. The rich spike is a symptom; it disappears when the air is there.
  • Tip-in stall: a gap between idle airflow control and the DBW blend values. Fix: set the actuator floor just below steady hot-idle TPS, and the blend point just above idle PPS.
  • Cold-start slam: throttle snaps from ~14% cranking TPS to ~3% idle TPS faster than ASE can cover. Fix: hold an elevated post-start RPM target for 5–10 s — don’t cut ASE.
  • Warm stall with no trigger: usually base VE lean at idle while ASE masks it until it decays, or the idle PID never engaging (a stuck brake switch pins idle state at 0).
  • Hunt-then-stall: noisy VVT-i or CLT — three feedback loops fighting. Lock those down before touching calibration.

Conservative feed-forward

Feed-forward should be conservative; the PID does the rest. Bias open-loop corrections toward under-correction — apply roughly half the airflow change the engine needs and let closed-loop ease in the remainder. The asymmetry is the whole point:

FailureResult
Feed-forward under-correctsbrief high idle, PID trims it down — safe
Feed-forward over-correctscommands too little air, hits the actuator floor before the PID can recover — stall

This matters most for corrections keyed on sensor proxies (CAT for throttle-body temp), step loads (fan, A/C, alternator), and anything that crosses stall margin — exactly where a cammed idle already lives near the floor. Keep integrator limits below proportional limits so the slow integrator can’t trap the engine in a low-air state.

Removing every source of variation

A cammed idle has almost no margin, so the real work is making the operating point boring — eliminating the scheduled disturbances that jolt it. In principle a disturbance can be handled two ways: smooth it into a PWM/airflow ramp slow enough that it never outruns the idle PID, or move it outside the idle region entirely so the step never lands while you’re holding a controlled idle.

Relocate, don't smooth

On this build I moved all three of the usual offenders — VSS up-idle, A/C compressor, and the coolant fan — well outside the idle region, rather than asking the idle controller to absorb them. The most robust way to keep a transient from upsetting idle is to make sure it doesn’t happen at idle in the first place.

What that looks like for the three offenders:

  • VSS up-idle (raising the idle target with road speed). Rather than scheduling a target step at a speed threshold — which itself injects variation into a heat-soak idle every time you cross it — the speed-dependent behavior is kept out of the held-idle window, and the low-speed return-to-idle dip is owned by airflow-PID authority (PID output / integral ceilings) and a faster PID update interval (e.g. 200 ms → ~50 ms). The idle you actually sit at sees no scheduled target jump.
  • A/C compressor. The simplest possible fix: raise the minimum A/C activation RPM above the idle band so the clutch physically cannot engage while you’re sitting at idle. The ~900 ms torque step never lands on a minimum-airflow idle because the compressor only comes on once the engine is already off idle and breathing. No idle-up schedule, no feed-forward to time — the disturbance is simply gated out of the window. Works just fine.
  • Coolant fan. The fan is gated on CLT and road speed so it engages while the car is still moving (e.g. at ~70 °C below a speed threshold) instead of snapping on while you sit at a light. The steady-state airflow compensation for fan load (a fixed airflow adder) stays; what’s removed is the transient of it engaging at idle.

The throughline: don’t make the idle controller discover a disturbance the moment it happens. Schedule each load to arrive somewhere other than a held idle — and where a transient is unavoidable, ramp it slowly enough that the PID can ride it. Anything you take off the idle controller’s plate is variation it no longer has to chase.

Notes

Repo: github.com/4AM365/emu-black-tuning-notes