We were recently asked to add a set of port injectors and nitrous in an engine with full control over it. So we reprogrammed the ECU to not only control the injectors but to adjust the values live from OBD port! Check out the video below:
We started off by looking for non-essential pins that could be used to send activation signals to the injector. Here’s the pinout:
Hmmm, exhaust flap seems pretty useless.
Now that we have a pin we can use, lets observe the output we get on the stock file in ECU.
As we can see its a PWM output with 12V as max voltage, 11.7V on average almost 100% duty cycle and 100hz frequency.
We have to somehow find the source of this output in the code and modify it to suit our needs. Ghidra to the rescue.
On analyzing the code we found the main PWM function that is called to control every component attached to the engine (like the exhaust flap). After some more research we figured out the function signature and the data it requires to send out the sweet PWM signal (such as port, period, duty cycle)
All we have to do is add our own code now by replacing the exhaust flap code (bye bye exhaust gunfire :/ ).
Initialising it with some values :
Max duty cycle – 7FFF
Duty cycle – 50% – 3FFF
Period – FA0 (4000 us = 4ms), Frequency = 250 hz
Lets see the output,
Looks ok.
It would be nice to be able to test out different values on the go. We could flash the ECU with different values each time but that would be a painful process. Hence we shifted the variables to RAM and decided to modify them live using the OBD port.
We would need to send UDS commands to both read and write RAM variables on OBD port. Reading data is accessible. Writing to it? Not so much.
We had to write a patch so we could bypass the locked feature!
Now that is out of the way, we will conduct some experiments.
UDS command to write data is 3d 14 xx xx xx xx nn [yy .. ]
where xx = RAM address,
nn = Number of bytes to be written
yy = The bytes to be written ( since its tricore that we are dealing with, the byte format is little endian so the order of bytes is reversed)
Case 1:
Duty cycle = 10% (of 7FFF which is max duty cycle set by us) – > 0C CC
UDS command:
3d 14 d0 01 60 0c 02 cc 0c
(remember because of little endian the byte order is reversed)
Frequency = 300 hz, Period = 1/300 = 3333 us = 3.33ms -> 0D 05
UDS command:
3d 14 d0 01 60 02 02 05 0d
Resulting output:
Case 2:
Duty cycle = 75% (of 7FFF) – > 5F FD
UDS command:
3d 14 d0 01 60 0c 02 fd 5f
Frequency = 200 hz, Period = 1/200 = 5000 us = 5ms -> 13 88
UDS command:
3d 14 d0 01 60 02 02 88 13
Result:
Seems like its working! Now we can easily connect the injector to this pin and send the desired fuel quantity based on engine conditions.
Using this functionality we can add any aftermarket kits such as water methanol kits, nitrous kits or port injectors. We have designed an algorithm to activate nitrous after pressing a button on the steering wheel and that only works when all the conditions are right.
That’s it folks.