Nanocom One log converter

Sunday, May 14, 2017 - 08:00

Updated: I decided to revisit the Nanocom One log converter code today with view to incorporating it into a larger project. When I made a couple of changes to tidy things up, I discovered that I'd managed to wallpaper over a small problem in the Nanocom One log format, and also missed the bleeding obvious in regard to the record delimiter. The post is getting a rewrite to correct.

While the Nanocom One is viewed as a bit of a dinosaur there is still a body of opinion that it is far more reliable for .map uploads than it's replacement - the Evo. And there are still a lot of them in circulation, and that means there a quite a few logs in the binary .fu1 format.

The usual procedure is to open up the old graphic viewer PC application and use that to check files or to export as a.csv file and then use a spreadsheet app to look at the data. Either way it's not especially flexible and a bit of a PITA.

Anyway last night I sat down with a copy of Synalyze It! (Hexinator on Windows/Linux) and worked out the structure of the .fu1 log files.
Synalyze It! uses "grammar" files to apply structures a binary file which is a fairly nice way of reverse engineering file formats.

This shows how a single fuelling record looks with the fu1 grammar applied:

       Fuel Record [0] (0)
            RecordDelimiter: CR LF: 0D 0A  [0]
            FuelData [0] (2)
                DiagRequest_0x09 [0] (2)
                    RPM: 754 [0]
                DiagRequest_0x0D [0] (4)
                    RoadSpeed: 1 [0]
                DiagRequest_0x1A [0] (5)
                    ECT: 3523 [0]
                    ECT mV: 772 [0]
                    IAT: 3311 [0]
                    IAT mV: 1309 [0]
                    AAT: 3200 [0]
                    AAT mV: 1681 [0]
                    FT: 3325 [0]
                    FT mV: 1260 [0]
                DiagRequest_0x1B [0] (21)
                    TPS1 mV: 571 [0]
                    TPS2 mV: 4460 [0]
                    TPS3 mV: 4677 [0]
                    Throttle %: 0 [0]
                    TPS Supply mV: 5021 [0]
                DiagRequest_0x1C [0] (31)
                    MAP: 10143 [0]
                    MAP raw: 10158 [0]
                    MAF: 575 [0]
                    MAF mV: 1977 [0]
                DiagRequest_0x21 [0] (39)
                    idleErrorRpm: -3 [0]
                DiagRequest_0x40 [0] (41)
                    Cyl 1: 3 [0]
                    Cyl 2: -2 [0]
                    Cyl 3: -1 [0]
                    Cyl 4: -2 [0]
                    Cyl 5: 2 [0]
                DiagRequest_0x23 [0] (51)
                    AAP: 9971 [0]
                    AAP raw: 10013 [0]
                DiagRequest_0x37 [0] (55)
                    EGR Inlet: 0 [0]
                0x38 [0] (57)
                    WGM Duty: 0 [0]
                0x38 [0] (59)
                    WGM Duty: 0 [0]
                0x10 [0] (61)
                    BAT mV: 13807 [0]
                    BAT_MSB_only: 35  [0]

The format is actually pretty simple. It consists of a CRLF ('0x0D0A') pair delimiting each "observation" and then the block of data which makes up the observation. The final byte of the file looks to be a mod256 checksum.

The hex number appended to each DiagRequest_0x refers to a predefined diagnostic request used by the ECU to look up engine parameters. These are common to MSB, and EU2 and EU3 NNN, so if you request 0x10 you'll always get back 4 bytes of data containing corrected and uncorrected Battery Voltage. The problem I discovered when revising the script is that the Nanocom One logs only 3 of the 4 bytes of data for the Battery Voltage. This means the corrected voltage is OK, but only the most significant byte for the uncorrected voltage is available making it useless. I've corrected the script so it ignores the corrupt value.

Note also that until the most recent update (v1.32) the Nanocom was making duplicate requests for the WGM Duty Ratio, and using one read for the EGR Output. This update fixed the duplication in fueling mode, but it remained in Instrument mode when I last looked.

What is interesting is that the full data for each request is saved in the file, so that the Throttle % and AAT reading is present in the data. As can be see from the decoded structure the file also includes sensor voltages for all temperature sensors, and the MAF.

I found that there is also a small error in the Nanocom One's AAP value - there are two values returned - one is the raw reading, and the other is the reading corrected for variation in sensor supply voltage. The corrected value is used by the ECU for fuelling and boost limiting purposes, however the Nanocom (One) reports the raw value.


I've put together a small python script which is attached.

It's is a bit less basic than previous version, and has only been tested on macOS 10.13 with Python 2 and 3. You'll need to remove the txt extension.

The script is run from command line, with the path to the file to be converted as an argument.

python file.fu1  

The converted file is saved as filename.csv in the current working directory. The .csv contains the full data from the log saved in the same order the requests appear in the .fu1 file. This is different to the Nanocom CSV order. The converter alters temperatures from Kelvin to Celsius, and adjusts decimal points to match the the Nanocom, with the exception of voltages which are left as millivolts.

Note that the AAT and TPS3 voltages will read 5000mV if the input is not connected.

Wastegate Modulator: Operation

Thursday, May 4, 2017 - 09:00

This is a bit of background on how the physical waste gate modulator unit operates.

It has only been in the last few weeks that it finally dawned on me that I'd been uncritically accepting the "Active to Limit" theory as correct. While it doesn't seem that important on the surface, it's difficult to make sense of code when the behaviour seems to be at odds with how you believe the hardwares should be operating.

Let's start by looking the Active to Limit Boost theory of operation:

  • power off, the valve is in an open position and boost flows from turbo outlet pipe to the Wastegate Actuator;
  • power on and no PWM signal from the ECU, the valve is in a closed position and boost is prevented from reaching the Wastegate Actuator;
  • power on and PWM signal from the ECU, the valve opens and allows boost to reach the Wastegate Actuator, opening the waste gate.

Active to Limit Boost is the most commonly expressed explanation of how the WGM operates, even if it's not explicitly stated.

This example is from Urban Panzer's excellent website...

"trying to the rev the engine over 2500 RPM the waste gate modulator info that Nanocom shows under "read fuelling" went to zero occasionally, so it basically was not controlling turbo charger boost / waste at certain times and was very "hit and miss" at best. That all seems to make sense and description in RAVE would appear to confirm that view. And the Nanocom logs seem to suggest this is what happens in practice.

You can clearly see the WGM active = controlling boost, WGM inactive = boost uncontrolled aspects of the Active to Limit Boost theory.

You'll see this theory of operation informing most forum posts relating to over boosting and WGM diagnosis. It's difficult not to fall into this way of thinking due to it's prevalence - that's my excuse anyway.

So lets look at this in detail...

Hardware first

After a bit of digging I found a couple Pierburg service information sheets for electric switch over valves. These were for parts identical in appearance to the D2's waste gate modulator, but with different part numbers. The test methodology given in the service information required a hand vacuum pump, so I decided put the site donations fund to use and purchased a Mityvac kit. Thanks again to those who have contributed!

The test procedure is fairly straight forward, but the main question I had was whether the valve on the D2 behaved in the same way as described.

WGM testing
WGM diagrams

Testing the modulator on my D2 suggests that the flow through the modulator does match that outlined in the test procedures.

  • power off, boost flows from turbo outlet pipe into port 1 for the modulator and out of port 3 to the waste gate actuator;
  • power on, engine running, and no pwm, boost flows in from turbo outlet pipe into port 1 for the modulator and out of port 3 to the waste gate actuator;

In the course of doing these tests I discovered that while the WGM seemed to be OK, it wasn't passing the Tightness test 1.3.
It was possible to pull down to 0.5 bar vacuum but this dropped to 0 within roughly 10-15 seconds. Similarly, applying pressure to port 1 with port 3 capped resulted in a loss of pressure over 10-15 seconds.

To confirm normal operation I ordered a Pierburg OEM modulator and bench tested.
Out of the box the modulator would hold 0.5bar vacuum on port 2 for 20 minutes with no visible loss of vacuum.
Testing with port 3 capped and 2.0 bar applied to port 1, there was no visible loss of pressure after 20 minutes.

The pin to pin resistance of the new WGM was 29.3ohm, which is within the 28.4ohm +/-1.5ohm specification.

Powered Benchtests

Rather than leave the testing hanging I decided to perform tests 1.1 and 1.2 from the Pierburg service information. This was done with a bench power supply and confirmed the new WGM behaved as described.

For test 1.1 Electrical Function there was distinct click as the solenoid activated, as you'd expect
For test 1.2 Internal Fouling the air flow matched the required values:

  • no power: air flowed from port 1 -> port 3.
  • power: air flowed from port 3 -> port 2.

The thing to note here is that port three is the common outlet. The solenoid is switching between port 1 and port 2.

Next step was to connect the WGM to my tester ECU. Power to the + pin on the WGM was taken from the "master relay" on the interface board. The - pin was connected to A21 on the ECU.

I also hooked up the Bitscope Micro with the scope probe connected to the - pin and the earth clip hooked up to the power supply earth. Add in the Mityvac and Nanocom and it all starts getting a bit messy!

WGM Testing

The main difference between unpowered (ignition off) and powered (ignition on) without a PWM signal is the voltage level.
Unpowered and no PWM gives 0V on both +ve and -ve pins.
Powered and no PWM gives supply voltage on both +ve and -ve pins.

Because there is no voltage differential between +ve and -ve no current flows and no "work" is done.

In the case of power applied to +ve pin and PWM operation, the +ve pin is at supply voltage and -ve pin at earth reference when the PWM completes the earth path. Because there is a voltage differential of around 13.5V and the solenoid coil has resistance around 29ohms the WGM will draw 0.46 amps and dissipated about 6.28 Watts when it is activated.

I can attest that leaving the WGM hooked up to a 12V supply for 5 minutes results in the WGM becoming hot to the touch. oops!

The Bitscope capture below shows the Nanocom Wastegate Modulator Test in action.

Nanocom WGM test

You can see the effect of the PWM completing the earth path resulting in the voltage at the - pin of the WGM dropping by just under 12V.

The pulse width is 100ms or 10Hz, and the duty cycle is roughly 50%, which corresponds with frequency and duty cycle requested by the Nanocom test routine.

I couldn't work out how to capture on video but with the port 3 capped and port 1 pressurised to 2 bar, there was a distinct "puff" as pressure was released through port 2 each time the WGM activated.

As can been seen from the video the WGM is directing pressure to the capped port 3 when it's not receiving a PWM signal.
When PWM is active the pressure in the capped waste gate actuator outlet is released via port 2.
The small drop in pressure seen on the gauge with each activation is due to the small internal volume of the cap I've used.

Revised Theory of Operation

At this point it should be apparent the theory of operation outlined at the start of the post was a bit back-to-front.

Updating the theory to reflect real world behaviour we get:

  • power/ignition off, air pressure flows from port 1 (turbo outlet) -> port 3 (waste gate actuator) - wastegate receives full boost
  • power/ignition on, and no PWM signal, air pressure flows from port 1 (turbo outlet) -> port 3 (wastegate actuator) - wastegate receives full boost.
    In these cases the WGM is de-energised.

WGM de-energised

  • power/ignition on and PWM signal, air pressure flows from port 3 (waste gate actuator) -> port 2 (turbo intake pipe) - wastegate isolated from full boost.

In this case the WGM is energised.

WGM energised

This means when the WGM is recieving a PWM signal it is operating to reduce pressure at the Wastegate Actuator. Rather than "Activate to Limit Boost" the system is "Activate to Increase Boost".

But RAVE says...

So what does RAVE actually say to support the "activate to limit boost" theory?
The following sentence is often pointed to as evidence:
When full boost is reached a control signal is sent to the wastegate modulator, and a vacuum is applied to the wastegate valve.

Interestingly this sentence incorrectly states that vacuum rather than boost operates the waste gate valve. This is often excused as a typo but there is clearly an error in the statement.

Nothing else in RAVE indicates a specific method of operating, just that the system controls boost pressure to prevent overboost.

What about the Nanocom logs....

The Nanocom samples engine data once every 1.2 seconds in the current EVO guise - Nanocom 1 was a bit quicker at 1 second.
The WGM control code samples boost pressure and engine load once every 10ms and updates the PWM amount at that speed.

This means the WGM PWM has potentially been updated 120 times for each data point the Nanocom logs show. Transitions between PWM on and off to control limit boost occur quite quickly. 500ms is not uncommon, and the actual switch off occurs faster than the 70ms sample time of the logs.

In conclusion...

Looking back at the opening quote it's pretty obvious what is occurring.

... the waste gate modulator info that Nanocom shows under "read fuelling" went to zero occasionally, so it basically was not controlling turbo charger boost / waste at certain times and was very "hit and miss" at best.

The waste gate modulator PWM drops to 0% because the ECU is trying to direct full boost pressure to the waste gate actuator. And from the diagnostic information you can surmise the failure mode is either loss of spring tension in the valve or internal fouling of the modulator.

The next post in the Wastegate Modulator series will look at the WGM control maps.

Fuel Density Compensation maps

Thursday, April 27, 2017 - 09:45

The main of the function of the Fuel Temperature Sensor is to correct for the decrease in fuel density as fuel temperature increases.

RAVE states this quite clearly so no real surprises....

The FT sensor is located at the rear of the engine in the fuel rail with the tip of the sensor inserted at least 10 mm into the fuel flow. This allows the sensor to respond correctly to changes in fuel density in relation to fuel temperature.

This function is handled by two maps:

Fuel Density Lower:

  • EU2 - Map 62
  • EU3 - Map 96

Fuel Density Upper:

  • EU2 - Map 63
  • EU3 - Map 97

These maps have Inject Quantity Request as the X axis, and Fuel Temperature as the Y axis, and output density corrected Inject Quantity.
The lower map is the density corrected IQ at 1000rpm while the upper map is the density corrected IQ at 4200rpm.
For engine speeds between these two points the density corrected IQ is interpolated between the upper and lower maps.

The Density Correction is effectively a four dimensional map - with IQ request, Fuel Temp and RPM as inputs, and the density corrected IQ as output.

The Fuel Density Compensation maps are located after the group of maps consisting of Driver Demand, Smoke Limiter, Torque Limiter, and immediately prior to the Duration Maps. Corrections applied here have a direct effect on the final inject duration.

Because the these maps act to modify the IQ request they have sometimes been identified as a performance enhancing map.
I'd strongly advise against taking this approach as changes to the lower map, and lower parts of the upper map will destroy the temperature -> density relationship and modify the relationship between the duration maps and DD, SL and TL.

Limiter function

A less obvious function of the Fuel Density maps is that they act as limiter on Inject Quantity.
This limiting function is an effect of the last column of the upper map which sets a maximum IQ at 4200rpm of 60mg/fire (stroke). While the Fuel Density maps will output up to 100mg at 1000rpm, the effect of interpolation between the upper and lower maps means the maximum amount injected for 100mg request reduces as rpm increases.

The following plots show the interpolated value returned from the stock Fuel Density Compensation maps at various engine speeds.

1800rpm 75degrees

2600rpm 75degrees

3200rpm 75degrees

4000rpm 75degrees

The "corner" at 60mg is quite obvious, and while it would have minor impact on a Stg 1 tune, once you start playing with 80-90mg/fire (or stroke) it becomes a major problem.

How to solve

Fortunately this is reasonably easy to rectify by changing the upper map. The lower map does not need any alteration.

The simplest solution is to alter the final header value from 6000 to 10000.
Then either use 10000 for each of the cell values in that column.
Alternatively use extrapolated values:
- 9769
- 9977
- 10057

A slightly safer approach is to set the header to your maximum IQ value,
and then interpolate the values between the current last column and 10000.

Current donor XDF's have been updated to include these maps. These are now being distributed in an archive of XDF's for all 49 variant-fuel map pairs listed in Nanocom Map Wizard.

AAP/AAT sensor swapping

Friday, April 7, 2017 - 12:15

This is a fairly niche modification.

EU2 and EU3 engines are fitted with significantly different airbox sensors.

The EU2 uses a three wire Ambient Air Pressure sensor, while the EU3 uses a four wire Ambient Air Pressure/Ambient Air Temp sensor.

The curve of the AAP portions of the two sensors are different and require different parameters to give the correct reading.

Without adjusting the parameters there is a misread of around 10kPa. You'll get an over-read ( -700 m altitude) with EU2 AAP + EU3 tune, and under read (+700m altitude) with EU3 AAP + EU2 tune.

The problem is not so bad with EU2 AAP + EU3 tune as the engine assumes higher air density in some correction maps and will INCREASE injected fuel and give a 0.1 bar increase in the boost limit. The boost level is MAP - AAP so reducing AAP by 0.1 results in boost levels 0.1 higher than the would be with correct setup. I suspect this is why you often hear the comment that an EU3 tune drives better that the correct EU2 tune.

If you've addressed the issue by installing a 4-wire sensor - replace airbox lid, sensor and run an extra wire back to the ECU - the problem occurs when you want to run an EU2 map on the motor. The under-read means the ECU uses corrections which reduce the fuelling plus the boost limit is reduced by 0.1 bar. It guarantees bad performance.

The fix is in

The way to fix this problem is to use the correct parameters for the AAP you have installed. Search for the values for the base map and replace with values for the sensor you are using.

EU3 - 4 wire sensor
multiplier: 13171 ( 0x3373 )
offset: 267 ( 0x010B )

EU2 - 3 wire sensor
multiplier: 10410 ( 0x28AA )
offset: 1227 ( 0x04CB )

It's not too hard to find these values with a hex editor as I think they are fairly unique. As a rough guide they are somewhere around an offset of 0x6A0 from the start of the fuel map. In a Nanocom .map the fuel map always begins at 0x19010.

The donor-ware XDF's now have a patch that swaps the values. It's a bit rough as it shows a stock EU3 tune as being patched, so installing the EU2 parameters requires "reversing" the patch.

Header editing in Tuner Pro

Wednesday, April 5, 2017 - 13:45

Update I've added a short video giving a run through on adding a column header editor to a table.

A few people have asked how to edit headers for map tables, so this is quick how-to on setting up header edit maps.

The screen shots are for a EU2 map, so don't assume that the values in the screen shots will work for you - they most likely won't.

  1. Open up the smoke map definition (right click / F2) and noted the Address, Data Size and Number of Columns under the Columns tab.

Find column details

  1. Add a new table (right click, Insert new XDF parameter), On the general tab add a name, the address from the columns tab of the original map and the data size.

New Table - General Tab

  1. Add the number of columns under the columns tab.

 Columns Tab

And save.

This will give you a “table” which looks like this...

 Completed header editor

You can now edit the header values in the cells of the new table.

This video gives a quick run through of the process, and should hopefully fill in any gaps.

ABS Modulator Option A additional fix

Tuesday, April 4, 2017 - 11:15

I can't say I've had this issue personally, but when my brother owned his D2 he made an interesting find in relation to the Option A fix.

While this information was posted to AULRO at the time it seems to have been ignored and/or forgotten, so I've decided to post the information up here.

One of the potential causes of the Three (or Four) Amigos is an dry or cracked solder joint on the "snout" that the Shuttle Valve Switch plugs into.

Option A (2/3rds the way down this page) provides a way of solving the issue by removing the plastic from behind the snout pins to allow the joint to be resoldered. When my brother went to do this fix he discovered these solder joints were fine. Even after a precautionary resoldering the earth connection was still intermittent.

What Steve noticed was that the "snout" could be moved up and down slightly. After a bit of exploratory digging into the external potting he found a second location with two solder connections where the "snout" joins to the circuit board that holds the external connectors. Apparently these two pins had some kind of corrosion and required a bit of clean up before they could be soldered. After soldering these two joints the play in the "snout" was eliminated and solved the connection remained solid even when the snout was wiggled. So if you are planning on doing the Option A fix it's worthwhile checking that the connection remains solid when moving the "snout".

This photo shows the location of the pins and the kind of excavation required to access. The hole needs to be filled post repair but is hidden behind the mounting so this doesn't need to be especially tidy.

location of snout pins

Tech Note No.1: MAP sensor recalibration and replacement

Monday, March 13, 2017 - 08:00

Note link to calculator spreadsheet added at bottom of post


The 1.42 bar boost limitation of the stock Land Rover Td5 engine management system has been a long standing issue when increasing boost levels as a performance upgrade.

The standard solution has been to insert a boost box or some other type of "cheater circuit" in line with the MAP sensor to lower the sensor voltage to provide the ECU with false reading of the boost levels.

In the course of disassembling the ECU firmware it became apparent that the sensor parameters could altered with minor adjustments to the settings in the fuel map to accomodate alternative MAP sensors. The advantage to this approach is that the ECU receives a true reading of the boost pressure rather than a falsified reading that effects pressure readings across the range.

This modification was originally tested on a range of Td5 powered vehicles by members of the forum in January and February 2014.

Under the hood

In order to understand why and how this modification works, it is useful to understand the signal flow from the MAP sensor through the ECU hardware and the processing the ECU firmware applies to the converted analog voltage.

Sensor Signal Flow

The starting point of the conversion process from manifold pressure to ECU representation of the pressure is MAP/IAT sensor which is mounted on the TD5 inlet manifold. The voltage the MAP sensor outputs in response to a given manifold pressure is determined by the characteristics of the sensor used. The relationship between pressure and output voltage is often described as the transfer function of the sensor.

Signal Flow

Once the MAP sensor voltage enters the ECU housing it passes through a voltage divider formed by two resistors. The effect of the voltage divider is to reduce the incoming MAP sensor voltage to 90.7% of the original value.

The reduced MAP sensor voltage is then processed by a 10 bit Analog to Digital Convertor (ADC). The 10 bit range of the ADC allows the sensor voltage to be converted to one of 1024 ( 2^10) values. The conversion process is referenced to a 5 volt supply within the ECU, meaning the maximum ADC value of 1023 represents 5000mV and the minimum ADC value of 0 represents 0mV.

At this point the signal flow moves from hardware to pure software. The ECU code first checks that the raw value retrieved from the ADC is within the preset range. Both the minimum and maximum values are related to characteristics of the sensor being used and the range of sensor voltages that are considered within normal range. The maximum value set for the MAP in stock tunes is the equivalent of a pressure reading of 2.42 bar, which will familiar as the point the ECU limits with over boost. Any value that lies outside the initial check range causes an “out of range” fault to be logged.

In the next stage of processing the range checked ADC value is scaled so the converted value is returned to the required units. In the case of the MAP sensor this is millibar * 100. The scaling and offset values reverse the transformations applied by the ADC conversion, voltage divider and the sensor transfer curve to give the pressure value the sensor measured.

Reverse engineering from the stock MAP sensor

At this point we have a basic outline of how the MAP sensor voltage progresses to a digital representation of the pressure, and where intervention is required if we wish to replace a MAP sensor.

To illustrate the process of configuring the ECU values for a specific sensor the following section works from first principles using the stock MAP sensor.

While the explanation of the process may seem long winded and overly detailed the aim here is to explore the underlying assumptions, so that the same procedure can be applied to other sensors.


The sensor datasheet

The starting point is to acquire the specification of the MAP sensor as this provides the key information required to accurately configure the ECU. The stock MAP sensor for the Td5 is Bosch part 0 281 002 205, and the key parameters from the data sheet are shown below.

Sensor Data

Note that the data table pressure range refers to two points - p1 and p2 The information about these points is given in the plot of the sensor Characteristic Curve.

Characteristic Curve

From the spec sheet we can determine that that this sensor has an output of 400mV at 20kPa and 4650mV at 250 kPa.

Sensor Transfer Curve

Calculating the transfer curve is fairly simple and uses only basic high school algebra.
First we calculate the slope of the sensor curve from the two points given by the datasheet.

p1(mV) = 400
p1(kPa) = 20
p2(mV) = 4650
p2(kPa) = 250

The slope of the sensor curve (m) is the change in voltage divided by the change in pressure.

$ m = \frac{p2(mV) - p1(mV)}{p2(kPa) - p1(kPa)} $

Substituting in the stock MAP sensor values

$$ m = \frac{4650- 400}{250 - 20} = \frac{4250}{230} = 18.478260869565217 mV/kPa $$

The slope m tells us that for 1 kPa change in manifold pressure the output of the sensor increases by 18.4783 mV.

The second piece of information required is the voltage the sensor outputs when the pressure is 0 kPa. This is the sensor offset.

 offset = p1(mV) - (m * p1(kPa)
= 400 - (18.4783 * 20)
= 400 - 369.566
= 30.434 mV 

The slope (m = 18.4783 mV/kPa) and offset (30.434 mV) provide us with sufficient information about the MAP to configure the ECU.

ECU Hardware

As discussed in the Sensor Signal Flow section the output of the MAP sensor passes through two fixed stages of processing - a voltage divider and the Analog Digital Convertor.

Voltage divider

The Td5 ECU uses a resistor divider arrangement on sensor inputs to provide a form of over voltage protection for the Analog to Voltage Convertor inputs. The divider consists of two resistors:

resistor1 = 121000 ohm
resistor2 = 12400 ohm

$ voltDivider = \frac{121000}{ 121000 + 12400} = 0.9070 $

The divider therefore reduces the sensor voltage to 90.7% of the original value. This means that a sensor output of 5000mV is reduced to 4535mV at the input of the ADC.

ADC Conversion

The 10 bit ADC divides the range of voltages between ground/0mV and the sensor supply voltage/5000mV into 1024 discrete steps.
Dividing the total number of steps by the voltage range gives the step size of 1 millivolt of input voltage. The output of the ADC is a value between 0 and 1023 that represents the measured voltage.

Note that there is debate as to whether n or n-1 steps is correct. Comparing both methods to the ECU curves indicates that n-1 gives the closest match when compared with stock values.

The voltage of each ADC step (or ADC code) is calculated as:

$ step/mV = 1023/5000 = 0.2046 $

Note that it requires a change of at least 4.8876 mV to cause a change of 1 ADC code.

Putting together the hardware scaling factors

The combined effect of the voltage divisor and ADC allows us to calculate the value in "adc codes" the ADC will output for a given sensor voltage at the ECU connector.

 hwScale = ADCstep/mV * voltDivider
 hwScale = 0.2046 * 0.9070 = 0.18557

Using this hardware scaling factor we can calculate the ADC codes produced by a voltage at the ECU MAP input.
For example if we have 4650mV input...

$ adc codes = 4650 * 0.18557 = 862.9 $

This can be extended to calculate the ADC output for a given pressure.

Using 242kPa as an example...

pressure = 242kPa;
adcCodes = ((pressure * sensor slope ) + sensor offset) * hwScale
adcCodes = ((242 * 18.4783) + 30.434) * 0.18557 $  
adcCodes = 4502.18  *  0.18557= 835.47 $

As another illustration lets use the sensor maximum of 250kPa...

pressure = 250kPa;
adcCodes = ((pressure * sensor slope ) + sensor offset) * hwScale
adcCodes = ((250 * 18.4783) + 30.434) * 0.18557
adcCodes = 4650  * 0.18557 = 862.9

Error handling

At this point in the process the ECU does error checking against minimum and maximum values defined for the specific sensor input. These are the values that are available as scalar editors (ai_limit_min : MAP and ai_limit_max : MAP) in my "donor-ware" Tuner Pro .XDF's.

If the sensor value in ADC codes is below the minimum the ECU logs "below minimum" and "out of range" faults, if the value is above the maximum, "above maximum" and "out of range" faults are logged.

These are the faults the Nanocom reports as "logged low" (1-2,x), "logged high"(3-4,x) and "current" (5-6,x). "Current" simply indicates that there is either a "logged low" or "logged high" fault set.

Using the stock MAP ADC limit check values as example we can work backwards to find the voltages and pressures that have been set.

min = 93
max = 836

By reversing the transforms performed by the ADC and voltage divisor we can reconstruct the input voltage.

sensorV = ( limits /  mvStepADC ) / vDivider
sensorVmin = ( 93 /  0.2046 ) / 0.9070 =  501
sensorVmax = (836 / 0.2046) / 0.9070 = 4505

So it appears the limits are set to a minimum of 500mV and a maximum of 4500mV.

To find the pressure these voltages correspond to we divide the voltage minus the offset by the mV/kPa value m

$ pressureLimits = (sensor voltage - sensor offset) / m $
$ pressureMin = (501 - 30.434) / 18.4783 = 25.46kPa $
$ pressureMax = (4505 - 30.434) / 18.4783 = 242.15 kPa $

25kPa is well below anything you'd encounter while driving on the surface of this planet but higher than the minimum sensor hardware limit. 242kPa matches the well known stock boost limit.

When recalibrating for a new MAP sensor, or using the stock sensor at higher boost it is essential that these limit values are reset to match the new boost levels and sensor curve.

Software: From ADC codes to pressure readings

Working backwards from ADC codes to pressure is a good warmup for the remaining steps of calculating new multiplier, divisor and offset parameters which makes possible substitution of alternative sensors.

In effect we are reversing the transformations done by the sensor curve m, sensor offset, the voltage divisor and the steps/mV of the ADC process in the same way the limiter pressures were checked.

The value used internally by the ECU for MAP is kPa*100. Additionally the divisor in the stock configuration is set to 1000. This is done due to the integer math used in processing - the multiplier is x1000 to give three decimal places of additional precision, and after the multiplication is completed the result is divided by 1000 to the required two places. This means the multiplier should be multipled by 100000 to bring it to correct units for use in a engine map.

$ multiplier = (1/(m * hwScale ))* 100000 $
$ multiplier = (1/(18.4783 * 0.18557 ))* 100000 $
$ multiplier = (1 / 3.429018) * 100000 = 0.2916287 * 100000 $
$ multiplier = 29163 $

The stock value for this parameter is 29163, so the calculated value is a match for the factory calculations.

Stock divisor parameter is 1000, and reverses the three places precision noted above.

The final parameter is the offset which is the sensor offset calculated in the intial steps converted to ADC codes then scaled by the multiplier and divisor.

$$ offset = \frac{sensor offset * hwScale * multiplier}{divisor} $$

$$ offset = \frac{30.434 * 0.18557 * 29163} {1000} = 164.7 $$

Rounding up to the next highest integer value gives 165.

As noted earlier the offset indicates the voltage the sensor would output at 0kPa pressure. This means that to correct so the sensor curve so the output is 0 mV at 0 kPa you need to subtract the offset if it is positive and add if it is negative.

The ECU math uses addition for this calculation, so if the offset is positive we need to swap the sign to make the number negative. And if the offset is negative the number added needs to be signed swapped to make it a positive number.

So in this case the ECU offset parameter should be -165 to remove the positive offset of 165.

In summary, the values calculated from the datasheet information match the stock parameters:

MAP ADC Maximum: 836  
MAP Multiplier: 29163  
MAP Divisior: 1000  
MAP Offset: -165  

Current XDF's have a changed naming scheme for scalars which reflects LR documentation.

ai_limit_max : MAP  = 836  
ai_anlg_multip : MAP = 29163  
ai_anlg_divisor : MAP = 1000  
ai_anlg_divisor : MAP = -165  

1.5 Bar MAP Recalibration

This is a super simple mod to do!

  • Change the MAP ADC Max (ai_limit_max : MAP) value from 836 to 863, which raises maximum input to 250kPa.
  • Change the Boost Limit (tb_over_pres_enbl) from 14200 to 15000.
  • Change the Boost Limiter Recovery (tb_over_pres_disbl) value to 14800.

This mod uses the stock MAP sensor and does not require any hardware changes.
It's a good choice if you are running stock intercooler and turbo.

In the Tuner Pro .XDF's I give as a "thank you" to donors these parameters can be edited using a simple graphical interface. XDF MAP editing

The parameters can be located by searching for the stock values using a hex editor of course, so it's your choice.

MAP Setting Calculator

There is now a MAP Parameter calculator on Google Spreadsheets.
It's read only so you'll need to download as an XLSX or ODS spreadsheet (or copy to your Google account) from the File menu.

The spreadsheet contains the values required for the VAG 3 Bar and Bosch 3.5 Bar (PN# 0 281 002 244) sensors.
- Copy the values you need across to the area highlighted in yellow or enter for the sensor you want to use.
- Set the boost limit required (pressure from Point 2 or lower *100). Recovery is calculated as 2kPa below this.
- If the calculated multiplier is greater than 32767 you'll need to lower the divisor. Try 750 as a starter.

MAP calculator on Google Spreadsheet

Td5 NNN ECU "Base" Code

Sunday, March 5, 2017 - 14:15

One of the very early posts one this site shows a diagram of the firmware layout used on the Td5 NNN ECU's.

The portion of memory located between addresses 0x0000 - 0xFFFF was cryptically called "ECU Base Code", with the note that this is not touched during Nanocom .map uploads.

The "Base" code is possibly better described as management or boot loader code. In normal usage the main function it performs is basic setup of the ECU hardware, verifying that certain check points are present in the Variant and Fuel maps, then running the variant map code if everything correct.

The secondary function of the management code is to provide support for factory programming of the ECU. Without a variant or fuel map installed the ECU will boot into a special diagnostic mode that provides access to the functions need to upload .map files, program injector codes, synchronise with the BCU immobiliser, and set the throttle pedal type. I assume this mode would have been used on the production line to program new ECU after installation into a vehicle.

The management code is identical across all the NNN ECU's with two minor differences.

The first difference is the code identifier. Like engine maps each variant management has a unique identifier. The second difference is the ECU hardware code, which reflects the well know NNN numbering. So the thbtp001 ecu code has the indentifer NNN000120, whereas the thbtp005 has the identifier NNN500250.

The complete list is:

NNN000120: thbtp001
NNN000130: thbtp002
NNN500020: thbtp003
NNN500030: thbtp004
NNN500250: thbtp005

If you are simply uploading .map files using a diagnostic tool you don't need to worry about this as the management code is not touched even if you brick the ECU.

Where you can run into problems is if you upload a complete .bin file from a different ECU type.

One of the differences between the NNN000xxx and NNN500xxx ECU's is that the power driver chips used to control the injectors were changed from Intersil HIP0060 to Infineon TLE6220GP parts. While both types of chips use Serial Peripheral Interface bus to communicate with the MCU the format of the messages and the representation of faults differs.

The ECU code uses the identifier from the management code to determine which driver chip is present.

So if you fit a .bin from a NNN000120 to a NNN500020 or NNN500250 for example the Variant code will read the NNN000120 identifier and use the code for the HIP0060 driver chip, rather than the TLE6220GP.

What makes this problematic is that one chip arranges it's fault codes:

A_OverTemp, B_OverTemp, C_OverTemp, D_OverTemp,  A_OpenLoad, B_OpenLoad, C_OpenLoad, D_OpenLoad

with a value of 1 signalling a fault.

The other uses:

A_bit1, A_bit2, B_bit1, B_bit2, C_bit1, C_bit2, D_bit1, B_bit2

If both bit1 and bit2 are set to value of 1 the channel is operating normally, and if both are set to zero there is a "short to ground" fault present.

This means if you send the diagnostic bits from a HIP0600 showing no faults (all zeros) to an ECU configured for a TLE6220GP the best you can hope for is "short to ground" faults on all channels.

The injector fault check is called in the main loop of the ECU code and it's potentially updated every 10 milliseconds or so. I haven't been able to confirm how this impacts general running, but I've been speaking to someone who has had ongoing issues with poor starting who appears to be running NNN000120 management code on an NNN500250 so it seems fairly likely this is related.

Anyway, it's something to be aware of...

Using an XDF with Td5 engine maps...

Thursday, March 2, 2017 - 06:45

There are a couple of little tricks to loading up the Tuner Pro defintions so thought I'd make a quick post on the procedure.
You'll have to excuse the "retro" Win XP look n feel. I'm running a Windows virtual machine under macOS and XP does the job without too much bloat.

1. Open a file to edit.

Use File >> Open Bin to open the file to edit.
For nanocom .map file select "All Files" as the file type.

Open dialog

2. Open the XDF

Use XDF >> Select XDF to open the appropriate XDF file.

Open XDF

3. Add Compare Bin

Use Compare >> Load Compare Bins... to load one or more compare bins.

Load compare bins

With a compare bin loaded you can use the "Show compare difference" and "Show compare bin data".

  • Using a random mod to illustrate, select a range of cells and multiply by 1.05
    Random mod

  • Clicking the "Scales" icon gives "Show compare bin data" - table values from the Compare Bin.
    compare bin data

  • With "Show compare bin data" on, clicking "Show compare difference" shows the difference between the map being edited and the compare bin.
    compare difference

If you find yourself having to load the same base file and xdf every time you start Tuner Pro, go into Tools >> Preferences and under the "Genera"l tab enable the two options to load the last used file at startup.


I'm offering what I describe as a "basic" XDF as donor-ware. These have a bit more detail on tables than Td5MapEditor, have some unit converted to more human friendly representations, and allow direct editing on MAP and Boost limits using the GUI.
The "deal" is anyone who makes a donation will receive an XDF of their choice. How much you donate is entirely up to you.

Desktop diagnostics...

Tuesday, January 24, 2017 - 08:00

Garmen has posted up a Python script which at the moment allows the user to read out the "Nanocom Fuelling" parameters. github

The project uses a cheap serial programming interface based on the CP2102 USB to TTL converter plus some external circuitry to interface with comms levels. The trick is that the CP2012 needs to be reconfigured to suit the "non-standard" baud rates, and to allow sending a 0x00 byte with a period of exactly 25ms. It's a fairly neat trick.

Anyway Garmen's work prompted me to pull out a "dumb" OBD-II interface that I'd picked up a couple of years ago and thrown in the cupboard. Most OBD-II interfaces are based on the ELM-327 chip which basically does all the grunt work of managing the diagnostic connection and allows users to simply send OBD commands over a serial connection and read back the response.

A "dumb" interface is a USB to serial converter chip (usually a variant or clone of the FTDI FT232) and hardware to interface with the diagnostic port line levels. These are usually sold as something like "VAG-COM KKL USB Interface" - just google it... These require that the user application to handle all of the communications protocol details.

The interface I have has a cloned FT232BL. The complete lack of markings on the chip is the give away. But as the part cost $14.00AUS including postage it's hard to feel ripped off...

The nice thing about the FTDI chips is that they have a "Bit Bang" mode. This allows you to write a byte to the chip and it will hold that state until you write another byte. It's perfect for doing things like sending the 25ms wake-up message or bit-banging the 5 Baud initialisation sequence.

There are a couple of Python modules that allow access to these FTDI specific features. I'm using pyftdi.

As a rough example of how you do it...


from pyftdi.ftdi import Ftdi
import time

HIGH = bytearray([0x01])
LOW = bytearray([0x00])
message = bytearray([0x81,0x13,0xF7,0x81])

uart = Ftdi(), 0x6001)
uart.set_line_property(8, 1, 'N')

# Enable Bitbang Mode
uart.set_bitmode(0x01, 0x01)

# Set TX line high

# Short sleeps in the loop seem to improve accuracy...
# Using time.sleep(.025) for the full delay is very jittery.
# time.perf_counter() can be used instead time.monotonic()
# requires Python 3.3 or later

start = time.monotonic()
while (time.monotonic() <= start + 0.35):

# Set TX line low

start = time.monotonic()
while (time.monotonic() <= start + 0.0245):

# Set TX line high

start = time.monotonic()
while (time.monotonic() <= start + 0.0245):

# Disable Bitbang Mode
uart.set_bitmode(0x00, 0x00)

# Send serial message

Which should give you something like:

Wakeup Sequence

The ISO14230 spec states the total time for the wakeup time (Twup) should be 50ms +/- 1ms. This code gives Twup of 50.67ms, so is within spec.
As reference the Nanocom sets the line low for 26.54ms and then idles high for 118.9ms giving a Twup = 145.44ms. The Td5 ECU is pretty forgiving.