Title: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: Basano on May 12, 2017, 06:37:17 AM Part 1
A long while ago, I wrote (http://nefariousmotorsports.com/forum/index.php?topic=7470.0)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 (http://nefariousmotorsports.com/forum/index.php?topic=5941.0), 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).
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: (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=12562.0;attach=22665) To decrement the value. Look at MB 48: (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=12562.0;attach=22667) To increment the value. Look at MB 47: (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=12562.0;attach=22669) 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 (http://nefariousmotorsports.com/forum/index.php?topic=271.msg55054#msg55054) 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 :) 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 (http://nefariousmotorsports.com/forum/index.php?topic=6159.0), 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 Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: Basano 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. Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: Basano on May 12, 2017, 06:41:38 AM zipped original and modified bin (8P0907115H / 387951)
Audi S3 8P MY2008 UK Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: littco 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 Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: vwaudiguy on May 12, 2017, 10:06:40 AM Basano for president. :)
Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: gman86 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.
Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: nihalot 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)... Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: teobolo on May 14, 2017, 11:06:57 AM One more time very good work...
Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: BraxS4 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
Title: Re: MED 9.1 tweaking ignition timing, fuelling and load with VCDS Post by: amd is the best on July 10, 2017, 06:21:29 AM We just need to somehow use an ethanol content sensor to make these changes ;)
|