Since none of them offer a desirable amount of control (for the price) I'm open sourcing an own design.
- full programmability - curves, upper and lower threshold limits
- reasonably fail-safe
- MCU agnostic - as far as possible
- preserve the original waveform signal
- easy to make - should not require exotic or expensive components
The overall architecture is simple: read sensor data into the microcontroller, process the signal, send an analog (PWM) signal out.
Disclaimer: this is probably not road-legal in many countries (missing certifications) and it might break the car subject. I am not responsible if anything bad happens, do it at your own risk.
However, it's not all dark, as I've already written there should be no damage as the unit still functions within factory settings and I will try to make everything as safe as possible.
In this first part I will focus on the driver electronics: concept, simulation, schematic and (perhaps) PCB. Since this is just a prototype I'm currently omitting protection circuitry.
The improved concept I came up with is applying the negative offset through an opamp subtractor. This way, if the microcontroller ceases to function the unmodified signal will be sent back to the car ECU.
The simulation above provides proof of concept: the yellow trace is the output from the pressure sensor, the blue trace is our modified signal that gets sent to the ECU.
Vdd is just the supply voltage, usually 5V.
Vpwm is the output from the microcontroller. In this case is a PWM waveform running at 4kHz with 10% duty cycle. This should mean a 0.1 x 5V negative offset. It starts only after 200ms. Tsl is the rising and falling slope of the MCU signal, some microcontrollers allow this to be set (fast/slow).
Vsensor is the original pressure sensor voltage. I've chosen 2V in this case plus some pulses that simulate injectors receiving fuel. I want these to be preserved in the modified signal.
U3 is just a buffer to isolate the MCU from the analog side and provide increased drive. It can also be used later to adjust the signal (divide or multiply it, depending on the MCU and its supply).
U2 is again just a buffer because the signal from the sensor might have a high output impedance.
U1 is used as a differentiating amplifier. The output is Vpwm- Vsensor, All resistors are identical but for R4adj - this is used to trim the gain error. See that it's 56.9k instead of 56k.
Other parts: R2 is just simulating ECU load, Rgpio simulating [a really bad] MCU output impedance, C2 filters the PWM waveform from the MCU, R4 simulating sensor output impedance.
The resistor values are not critical, but R1, R3 and R5 should be matched within 1%, otherwise offset and gain errors will exist.
The advantages of the above design: a sleeping (or dead) microcontroller will not interfere with the signal and the car will run with the factory defaults. The processing power doesn't need to be significant, for a fixed offset voltage there is no processing required. Large swings in the input signal will pass through unaltered if the uC does not have enough time to react.
I've used an LM324 quad op-amp since it's cheap, found everywhere and provides adequate response. The design also requires a single supply voltage and rail-to-rail outputs.
I've tried using LT1789-1 and LT1168 precision instrumentation amplifiers but the simulated offset was as big as with the LM324. Maybe just a simulation error but I think the added benefit for this application is minimal. Additionally, we would still need input and output buffering as those amplifiers are really weak and are not designed for that purpose. Plus availability might be limited.
Non-important features: bandwidth and slope, leakage, gain, power dissipation, noise.
It might seem that I'm under-speccing this part but just think of the part that's feeding the signal - the sensor is not that precise and it might have an offset voltage that modern ECUs will compensate for. This is why 'resistor in a box' mods do not work anymore.
Edit: ignore the choice above, LM324 is not rail-to-rail. I'll choose something else.
Edit2: seems like I'm back to the original choice of MCP6004 - it's pin compatible with LM324, rail-to-rail and available in both SMD and THT packages. A 1¢ cheaper option is LMV324, but it only comes in SMD package. Everything else in the post (including the schematic) remains unchanged.
Schematic and board
I've designed two variations - one home-made with through-hole components and large trace width and another one for SMD. Since this is just the IO board that's used for prototyping, it does not make much sense to design an SMD board - the end result will have everything integrated on it. This variant just provides a pin header for convenience of setup with an Arduino or similar boards.
Again, there is no protection, that's a separate topic. Should be fine for quick tests.
INSENS - the input from the sensor - is buffered through amplifier D, low-pass-filtered and sent back to the pin header to be used as an ADC input on the MCU.
It is also buffered by amp C and fed through the subtracting part of amp B.
INPWM - the output from the MCU - is low-pass-filtered and fed through the adding part of amp B. We want as little AC amplitude on the MCU as possible. While some parts do offer averaging (Stellaris/Tiva C) hardware averaging is more reliable.
C2 just provides a bit of supply power filtering to the LM324.
The board is my best attempt so far, it will not win any beauty contests. It's designed for through-hole components and the toner transfer method, only one side.
It's a bit smaller than 1.9 inches or 5cm. It could be designed as a shield if the pin header signals are rearranged, but I haven't bothered to do that: through-hole design, pin headers and jumper cables do not mix with automotive vibrations.
The design will be revised to include some power and transient protection.
I don't like the fact that the microcontroller could introduce such a high offset intrinsically. I think a 1 or 1.5V maximum offset should be more than enough. This could be enforced by introducing some feedback into IC1A or modifying the IC1B resistors.
Thinking of the above I should make sure in the code that the PWM output is not driven to digital 1 at any point in time (startup, reset).
The unfiltered (but buffered) signal could be made available to the MCU - more powerful processors could figure out small dips that correspond to engine RPM or provide useful injector telemetry.
Speaking of telemetry, I haven't decided yet on which (wireless) protocol the unit will rely on. Bluetooth is low power enough to not require a separate supply. ESP8266 would be nice that it could provide a web-server with Websocket, but in my tests it has proven unstable and power-hungry. 433MHz and similar ISM bands are also a possibility.
The design I'm shooting for is something that does nothing unless asked for and wakes up at a press of a button. This is especially important during the warming cycle or when running on public roads.
The circuit could easily be modified to allow injecting a positive offset signal via another PWM pin. Again, I don't think needing to drive a PWM pin at 50% duty cycle is safe, the safest behavior should be intrinsic at the off state. A separate filtered PWM signal at pin 8 of IC1C above should achieve this.