Some time ago I had a rebuilt 2.0 Fiat Twin Cam (Fiat 131 block, Lancia Beta head, Fiat Croma FI intake manifold) ready for installation. I thought it was fun to get it in a slow looking car but didn't want too much custom fabrication. This leads you to one option: a Lada.
To add another challenge I wanted to get it running on LPG only, so no start-on-petrol-and-switchover-when-engine-is-hot, but a 100% cold start LPG.
I had some experience with the Megasquirt system, but always had the impression it is quite out-dated. When I got news of rusefi I decided to bite the bullet and design a custom ECU to build a clean platform which allowed me to do the above.
(I know, the engine bay is ready for tidy-up)
ECU: hellen-one ECU for low-z (low impedance) injectors
The ECU is based on the hellen-one platform and uses the modules mcu144-0.7, ign8-0.2, input-0.1, wbo-0.3 and can-0.1 (2x). The 12V supply, 5V supply and discrete knock input is basically a copy of the hellen-one modules' BOM and schematics, but with a different layout since I couldn't fit the hellen-one modules. The 5V analog output is done by TPS7B4253 and the electronic throttle body is controlled by a DRV8873. There are 4 low-side AO3400 outputs.
The low-z injectors are controlled through 4x LM1949 configured with a 8A/2A ratio. The LM1949's timer functionality is used to limit the time 8A current is allowed. This timer setup should basically match the opening time of the LPG injectors. The range of opening times of LPG injectors varies from 1.7ms (KME W3 Fenix) to 3.3ms (Valtek type 30), so an internal PWM output allows you to control the timer from 1.65ms to 3.3ms.
In practice you will never see 8A current through a single injector (even at charging voltages) and the timer circuit will transfer the injector to hold mode.
A small Lua script sets up the internal PWM output to the LM1949 timer circuitry:
Code: Select all
-- Opening time LPG injections
-- Note: range: 1.65 to 3.30 ms
ms = 1.65;
R = ms/0.0001; -- The total resistance needed on the LM1949 pin in Ohms
r = -(33000*R)/(R-33000); -- The resistance needed on the timer pin
duty = 33000/r; -- The duty cycle needed to get the equivalent resistance on the timer pin
startPwm(pin_lpg_timer, 100, duty);
LPG: injectors and pre-heat It was quite difficult to find the exact specs for LPG injectors. I ended up with AC Stag's W31 injectors since they allow clean installation, have relevant specs available and are not expensive. Also their reducer was nice and small.
To overcome a petrol based cool start I needed to pre-heat the coolant to the reducer's minimum operating temperature (±40 degrees Celsius).
I discarded the default coolant necks and 3D printed stainless steel coolant necks which allow you mount Volkswagen's coolant pre-heaters. They're just like diesel flow plugs, but for coolant.
A big 75A relay allows control of these glow plugs through the ECU. They consume about 25A each (!) and heat up the reducer by 1 degree every 3s.
A Lua script controls the reducer's temp and starts heating 1s after turn on. It has 5 degrees of hysteris and primes LPG whenever the reducer is at operating temperature, or enables LPG when the engine is cranking/running. See full code (including injector timer circuitry below):
Code: Select all
t = Timer.new();
t_prime = Timer.new();
-- Get user defined cranking threshold (RPM below which the engine is assumed cranking)
cranking = getCalibration("cranking.rpm");
-- Get user defined fuel pump priming time (amount of seconds the fuel pump must be primed)
prime_time = getCalibration("startUpFuelPumpDuration");
-- Status of priming: 0 = hasn't primed, 1 is priming or has primed or will not prime
prime = 0;
if prime_time == 0 then
prime = 1;
end
-- The minimum LPG reducer operation temperature
-- Note: we enable the LPG fuel valves when the temperature is higher than temp_good - temp_hysteresis
-- Note: we enable heating at startup or when the temperature has dropped to temp_good, until temp_good + temp_hysteresis has been reached
temp_good = 45;
-- The temperature hysteresis
temp_hysteresis = 5;
-- Whether heating is necessary: 0 = heating is not necessary, 1 = heating is necessary
heat = 1;
-- Opening time LPG injections
-- Note: range: 1.65 to 3.30 ms
ms = 1.65;
R = ms/0.0001; -- The total resistance needed on the LM1949 pin in Ohms
r = -(33000*R)/(R-33000); -- The resistance needed on the timer pin
duty = 33000/r; -- The duty cycle needed to get the equivalent resistance on the timer pin
-- LUA PWM pin for LPG reducer shutoff valve (probably includes tank shut-off valve as well)
pin_lpg_valves = 0;
-- LUA PWM pin for LPG reducer heater relay
pin_lpg_heater = 1;
-- LUA PWM pin for LPG injectors' high current opening time
pin_lpg_timer = 2;
startPwm(pin_lpg_valves, 100, 0);
startPwm(pin_lpg_heater, 100, 0);
startPwm(pin_lpg_timer, 100, duty);
setTickRate(2);
function onTick()
s = t:getElapsedSeconds();
temp = getSensor("AuxTemp1");
rpm = getSensor("RPM");
if rpm == nil or temp == nil then
-- For security, could be high from the last onTick() with valid values
setPwmDuty(pin_lpg_valves, 0);
setPwmDuty(pin_lpg_heater, 0);
print("LPG control: disabled due to rpm and/or temp sensor in error state");
return true;
end
message = "LPG control: fuel is ";
-- Only enable the LPG reducer when the temperature is good or back-up mode after 120 seconds
if (temp >= temp_good - temp_hysteresis or s >= 120) and (rpm > 0 or (prime == 0 or t_prime:getElapsedSeconds() < prime_time)) then
setPwmDuty(pin_lpg_valves, 1);
if (prime == 0) then
t_prime:reset();
prime = 1;
end
message = message .. "enabled";
else
setPwmDuty(pin_lpg_valves, 0);
message = message .. "disabled";
end
message = message .. " (" .. temp .. "/" .. temp_good - temp_hysteresis .. ") and heating is ";
-- Determine if heating is required and include some user definable temp_hysteresis
if temp < temp_good then
heat = 1;
elseif temp >= temp_good + temp_hysteresis then
heat = 0;
end
-- (1) Wait at least 1s after powerup to prevent heating when the user is instantly going to crank (see also (3))
-- (2) Check if heating is required
-- (3) Prevent high current draw due to heating while cranking the engine
if s > 1 and heat == 1 and (rpm == 0 or rpm > cranking) then
setPwmDuty(pin_lpg_heater, 1);
message = message .. "enabled " .. temp .. "/" .. temp_good + temp_hysteresis;
else
setPwmDuty(pin_lpg_heater, 0);
message = message .. "disabled";
end
print(message);
end
ENGINE: Fiat Twin Cam swapped to Lada 2105 (Lada 1300)
The block is from a Fiat 131 (2.0l), the head from a Lancia Beta and the intake manifold from a Fiat Croma 8v FI. I tapped the original injector holes to install a modified bolt to which I could directly attach the LPG injector’s output hoses. To further bring the engine to the 20th century I replaced the crankshaft pulley by a modern Lada Niva one. It comes with 60/2 toothed wheel and is a direct fit. I used a Hall effect sensor to detect RPM. Some custom 3D printed parts allowed me to fix a normal Bosch MAP/IAT sensor to the intake manifold.
What I didn’t realise I did by swapping both the head and the crankshaft pulley, is that I ended up with no front flange on all the timing belt pulleys. You guess what happens next… Luckily my timing belt snapped off while I was cranking, so I “only” had a few bent valves. I now have the Lada Niva pulley modified to have a flange for the timing belt.
The ETB saved me quite some work because the throttle body is on the other side compared to what it was on the original Lada engine. The ETB is from some Russian vehicle (UAZ Hunter?) or 0280750151 from Bosch. It was a direct fiat to the Fiat Croma 8v intake manifold, nice. The PPS (pedal position sensor) is from a Lada Niva, it is not a direct fit in the Lada 2105 but still very manageable.
After fitting the engine assembly to the Lada 2105 I quickly realised the intake manifold interfered with the brake booster. This was a big challenge! I ended up mounting the brake booster about 15cm further from the firewall and under an angle, but it’s still an incredible tight fit.
SCHEMATICS: electrics and coolant routing I will be spending some more weeks to install a CAM sensor, cleaning up the engine bay and getting some real-life experience with the system.