Pages: [1]
Author Topic: MED 9.1 tweaking ignition timing, fuelling and load with VCDS  (Read 9598 times)
Basano
Full Member
***

Karma: +90/-3
Offline Offline

Posts: 192



Part 1

A long while ago, I wrote about how to send bespoke CANBUS messages to the ECU, which could be added/subtracted from a map’s output with a bit of ASM, effectively changing the map’s output by changing the value in the incoming CANBUS message. Interesting maybe, but it also relied upon specific CAN hardware and ideally RAM dumps, plus some obfuscated ASM and programming of external hardware. Stuff not available in everyone’s workshop so I guess it remained a curiosity for the most part.

Now this topic is similar but uses VCDS (or a similar tool that can log MB’s) so no need for bespoke microprocessors or CANBUS transceivers. You don’t even need any RAM dumps. Hopefully that makes it more appealing to the MED9.1 community – all you need is VCDS. It’s based upon Measuring Blocks and if you can create the custom measuring blocks described here, then you can do this.

You need a way to talk to the ECU and I chose to use a channel that’s already working and well understood – the Measuring Blocks. But while you usually use MB’s to read values in the ECU, I’ve changed it around so the act of reading the MB causes a byte of RAM to be changed. So when VCDS requests a specific MB and the ECU steps through the specific ASM for that MB, instead of using a lbz instruction (read from a byte of RAM), it uses a stb instruction (write to a byte of RAM).

  • Reading MB x causes the byte to increment (rolling over at 255 to 0)
  • Reading MB y causes the byte to decrement (rolling over at 0 to 255)
  • Reading MB z show the current value of the byte

Since VCDS polls the MB’s periodically (several time a second), if you keep reading MB x the byte will count up. Stop reading the MB and the byte stops. Read MB y and the byte counts down. With a bit of practice you can use the up and down MB’s to get the count to stop at whatever value you want. The count changes about once a second (or faster if you set VCDS to Turbo [High-Speed] mode).

In the example below, MB49 contains the byte value. MB48 decrements the value and MB47 increments the value. I used MB 47, 48 & 49 because they were unused in my ecu bin and also because MB 175, 176 & 177 were free as well (47 + 128 = 175, 48 + 128 = 176, 49 + 128 = 177). VCDS reads your current block plus another block 128 higher, that’s just the way the protocol works.

To look at the current value without changing it. Just look at MB49:



To decrement the value. Look at MB 48:



To increment the value. Look at MB 47:



When the count in MB49 has reached the value you want, stop looking at MB 47 or MB48 (change VCDS to another MB) to stop reading them and stop the value changing.

Q. But why not use diagnostic services like DynamicallyDefineLocalIdentifier and WriteDataByLocalIdentifier? Or Adaptation Channels or Output Tests? Surely that’s why they are there in the first place?
A. Firstly I never could get WriteDataByLocalIdentifier to work and secondly I wanted to keep it within the capabilities of what VCDS can do. It can definitely do MB’s. If someone wants to show me how to reverse-engineer and re-task the adaptation, that would be nice as well Smiley But for now it’s Measuring Blocks.

But why would you want to change a byte?  Well, if we write the byte like this:

255 dec = 1111 1111 bin

We can then start using different parts of the byte to do different things. For example:

1111 11xx

00 – add nothing to KFZW
01 – subtract 0.75 degrees from KFZW
10 – add 1.5 degrees to KFZW
11 – add 0.75 degrees to KFZW

1111 yy11

00 – add nothing to LDRXN
01 – subtract 20 from LDRXN
10 – add 25 to LDRXN
11 – add 10 to LDRXN

11zz 1111

00 – add nothing to LAMFA
01 – subtract 0.02343 from LAMFA
10 – add 0.05468 to LAMFA
11 – add 0.02343 to LAMFA

The byte itself is part of NVRAM (Non-volatile RAM) so it remembers the value when you switch the ignition key off. But if you remove the battery or flash a new bin, then it resets. It’s not stored in EEPROM (E2P) which is a different topic described here. All I did to find a free NVRAM location was to look at the FR for a random variable with NV (for NVRAM) written next to it in the pictures, look up where that variable was in IDA and choose an empty (unused) location as close to that as possible. The ECU won’t store individual variables in NVRAM, it’ll do an entire range so if you are close to an existing variable, you should be OK.

Q. Could you use E2P instead of NVRAM?
A. Sure, but then you have to figure out where the E2P is and also calculate a checksum for the E2P. It’s all described here, but honestly being able to reset it back to default by just unplugging the battery is not always a bad thing.

Looking at the actual code for the measuring blocks in more detail, here’s a step-through of the count-up routine as an example. VCDS polls several times a second and that means the count flies past too quickly to read. I used an outer loop and inner loop to slow things down - for every four outer loop cycles the inner loop cycles once (just like a gearbox, what a terrific pun on an automotive forum). The net effect is to slow the count to once a second with VCDS in non-turbo mode and if you want it to change faster then put VCDS in turbo mode.

ROM:0047E200                 lbz       r12, byte_807FD0 <- temporary scratch variable for the outer loop (count 0 – 1 – 2 – 3 – 0 …) Just normal RAM, not NVRAM
ROM:0047E204                 cmplwi    r12, 3
ROM:0047E208                 bne       loc_47E230
ROM:0047E20C                 lbz       r11, byte_7FA04E <- load NVRAM into r11, wrap back to 0 if 255
ROM:0047E210                 cmplwi    r11, 0xFF
ROM:0047E214                 bne       loc_47E220
ROM:0047E218                 li        r11, 0
ROM:0047E21C                 b         loc_47E224
ROM:0047E220                 addi      r11, r11, 1 <- increment r11 and store back in NVRAM
ROM:0047E224                 stb       r11, byte_7FA04E
ROM:0047E228                 li        r12, 0
ROM:0047E22C                 b         loc_47E234
ROM:0047E230                 addi      r12, r12, 1
ROM:0047E234                 stb       r12, byte_807FD0
ROM:0047E238                 li        r3, 0x11   <- measuring block type 0x11 which is a ASCII character MB type
ROM:0047E23C                 li        r4, 0x55 <- ASCII ‘U’
ROM:0047E240                 li        r5, 0x50 <- ASCII ‘P’
ROM:0047E244                 b         sub_43930C

More comments about the code in the attached spreadsheet as well
« Last Edit: May 12, 2017, 06:39:12 AM by Basano » Logged
Basano
Full Member
***

Karma: +90/-3
Offline Offline

Posts: 192


« Reply #1 on: May 12, 2017, 06:39:53 AM »

Part 2

Now to tweak the maps. KFZW (and LDRXN and LAMFA) use a lookup routine – you pass the location and axes in some registers to the function and the result comes back from the function in another register (by convention, the result always comes back in r3). All the ignition timing maps seem to use the same function, so instead of modifying the function (which would globally effect everything that calls the function, I made a copy of the function and made some changes to the copy. Then just for KFZW and KFZW2 I replaced the address of the global function with the address of my own modified function.

My code modifications then add or subtract a fixed amount from the maps. This is the same as incrementing every value in the map – even at RPM/Load points you may not be interested in! For example it will add 1.5 degrees timing to KFZW at 5000rpm/190% load, but it’s also adding that same 1.5 degrees to KFZW at 800rpm/10% load. Just something to bear in mind, it suits some maps more than others and I’d be curious to get suggestions from the community. I mean, be creative. Maybe you could also use it for adjustable NLS or antilag as well if that’s your thing.

Here’s the assembly instruction to extract a couple of bits from the byte for each function (KFZW/2, LDRXN, LAMFA). From the MPC562 instruction set manual:

rlwinm rA,rS,SH,MB,ME
To extract an n-bit field, that starts at bit position b in rS, right-justified into rA
(clearing the remaining 32 – n bits of rA), set SH = b + n,
MB = 32 – n, and ME = 31.

1111 11xx
SH = b + n = 30 + 2 = 32
MB = 32 – n = 32 – 2 = 30
ME = 31
rlwinm rA, rS, 32, 30, 31

1111 yy11
SH = b + n = 28 + 2 = 30
MB = 32 – n = 32 – 2 = 30
ME = 31
rlwinm rA, rS, 30, 30, 31

11zz 1111
SH = b + n = 26 + 2 = 28
MB = 32 – n = 32 – 2 = 30
ME = 31
rlwinm rA, rS, 28, 30, 31

Once you have xx and yy and zz, then just compare it and add/decrement a fixed value appropriately. The attached spreadsheet is pretty comprehensive with the comments and code.

As a worked example, here’s the details for KFZW. In my bin KFZW is located here (three maps, variant coding):

KFZW_0_A   0x001C8484
KFZW_1_A   0x001C8544
KFZW_2_A   0x001C8604

In IDA it look like this:

ROM:005C8484 word_5C8484:    .short 0x1B1B           # DATA XREF: ROM:off_5C8E44 o

In turn, those locations are cross-referenced in the code (IDA pops up with a XREF):

ROM:005C8E44 off_5C8E44:     .long byte_5C8484       # DATA XREF: sub_4DE96C+14 o

Which has another cross-reference (which IDA kindly works out).

ROM:004DE980                 addi      r11, r2, -0x11AC # off_5C8E44
ROM:004DE984                 clrlslwi  r10, r10, 24,2
ROM:004DE988                 lbz       r30, byte_7FC36A
ROM:004DE98C                 .using byte_7FC36A, r30
ROM:004DE98C                 lwzx      r3, r11, r10
ROM:004DE990                 lhz       r4, word_5CA3A8
ROM:004DE994                 lwz       r5, dword_7FF1E0
ROM:004DE998                 lwz       r6, dword_7FF204
ROM:004DE99C                 bl        sub_58D81C <- and this is the jump to the original lookup function.

So I make a copy of the function and put it at a spare location, then change the code to jump to my new location.

ROM:004DE980                 addi      r11, r2, -0x11AC # off_5C8E44
ROM:004DE984                 clrlslwi  r10, r10, 24,2
ROM:004DE988                 lbz       r30, byte_7FC36A
ROM:004DE98C                 .using byte_7FC36A, r30
ROM:004DE98C                 lwzx      r3, r11, r10
ROM:004DE990                 lhz       r4, word_5CA3A8
ROM:004DE994                 lwz       r5, dword_7FF1E0
ROM:004DE998                 lwz       r6, dword_7FF204
ROM:004DE99C                 bl        sub_47E2A0 <- and this is the jump (branch and link) to the new location, with the modified copy of the code.

So the modified version of the function starts off exactly the same as the original function.

ROM:0047E2A0                 addi      r7, r3, 0
ROM:0047E2A4                 clrlwi    r3, r5, 16

all exactly the same code as the original function

ROM:0047E328                 extsb     r3, r7 <- penultimate line of original function

then at the last line of the function where the original code had a blr instruction to jump back, instead I insert a few extra lines. Remember, at this point r3 contains the looked-up value from the map and we are going to add/subtract from r3 and then store the result back in r3 to return.

ROM:0047E32C                 lbz       r12, byte_7FA04E   <- load NVRAM byte 0x7FA04E into r12 (r12 can be used as a scratchpad)
ROM:0047E330                 clrlwi    r12, r12, 30      <- retrieve ‘soft coding’ value. clrlwi is a mnemonic for rlwinm
ROM:0047E334                 cmplwi    r12, 3      <- if its equal to three, add 1 to r3, put the result in r3 and jump to the end to return. A value of 1 represent 0.75 degrees
ROM:0047E338                 bne       loc_47E344
ROM:0047E33C                 addi      r3, r3, 1
ROM:0047E340                 b         locret_47E360
ROM:0047E344                 cmplwi    r12, 2      <- if its equal to two, add 2 to r3, put the result in r3 and jump to the end to return. A value of 2 represent 1.5 degrees
ROM:0047E348                 bne       loc_47E354
ROM:0047E34C                 addi      r3, r3, 2
ROM:0047E350                 b         locret_47E360
ROM:0047E354                 cmplwi    r12, 1      <- if its equal to one, subtract 1 from r3, put the result in r3 and jump to the end to return. A value of -1 represent -0.75 degrees
ROM:0047E358                 bne       locret_47E360
ROM:0047E35C                 addi      r3, r3, -1
ROM:0047E360                 blr            <- return to the original calling point.
Logged
Basano
Full Member
***

Karma: +90/-3
Offline Offline

Posts: 192


« Reply #2 on: May 12, 2017, 06:41:38 AM »

zipped original and modified bin (8P0907115H / 387951)
Audi S3 8P MY2008 UK
« Last Edit: May 12, 2017, 06:43:36 AM by Basano » Logged
littco
Hero Member
*****

Karma: +52/-7
Offline Offline

Posts: 903


« Reply #3 on: May 12, 2017, 09:39:50 AM »

Awesome,

Read through it once, lost me on after the 1st few lines but see exactly what you are trying to achieve. Just need to read a few more times to get my head around it.

It sounds a similar to what Lemmiwinks used to do with the me7 ecu, especially the timing being able to add and subtract a set amount over the whole map..

I think this has a real application for anyone wanting to use KFLDRL as an open loop boost control, being able to make quick changes via vcds without the 10 minute wait to flash a change will help a lot.. not ideal changing the whole map at once but very handy to log and see what each DC is doing,

Nice work as always
Logged
vwaudiguy
Hero Member
*****

Karma: +53/-37
Offline Offline

Posts: 2024



« Reply #4 on: May 12, 2017, 10:06:40 AM »

Basano for president.  Smiley
Logged

"If you have a chinese turbo, that you are worried is going to blow up when you floor it, then LOL."
gman86
Hero Member
*****

Karma: +45/-128
Offline Offline

Posts: 705


« Reply #5 on: May 12, 2017, 10:12:41 AM »

Outstanding work as usual. Can imagine this would be very useful to do some steady state tuning instead of the usual sweep test.
Logged
nihalot
Full Member
***

Karma: +40/-3
Offline Offline

Posts: 116


« Reply #6 on: May 12, 2017, 08:13:36 PM »

I've done something similar on the EDC15 but not using VCDS/MB.
I've used the clutch and cruise control buttons as inputs.
Press clutch and then press cc set, ignition advances by 0.5 degree at a time for a max of 3 degree. I've limited this advance to be active only under high loads(iq>40mg) so that the entire map is not advanced.
Obviously the number of maps is limited in my case to the permutations of all ecu inputs(clutch,brake,cc,etc)...
Logged

www.tangentmotorsport.com

multimap/LC/rolling antilag for MED17/EDC17/MED9/EDC15

contact for reverse engineering services of any ECU/TCU
teobolo
Full Member
***

Karma: +24/-6
Offline Offline

Posts: 112


« Reply #7 on: May 14, 2017, 11:06:57 AM »

One more time very good work...
Logged
BraxS4
Full Member
***

Karma: +2/-6
Offline Offline

Posts: 162



« Reply #8 on: July 08, 2017, 10:53:25 PM »

anyone familiar with egr / pcv and 2nd o2 delete? ive got my bin dumped and a partial damos... 2007 b7 2.0 thanks
Logged

stage 3 b5 S4
amd is the best
Sr. Member
****

Karma: +11/-5
Offline Offline

Posts: 268



« Reply #9 on: July 10, 2017, 06:21:29 AM »

We just need to somehow use an ethanol content sensor to make these changes Wink
Logged

2012 Golf TDI
2001 Audi A4 2.8 30v Supercharged
1991 Audi 200 20v
Pages: [1]
  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Page created in 0.033 seconds with 17 queries. (Pretty URLs adds 0.001s, 0q)