Announcement

Collapse
No announcement yet.

Flashing the MK60 with ZCP software

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    #91
    Oh shit, I might have found CCP commands in the PT(?)-CAN table.

    Table decodes out to a bunch of CAN IDs that I was going through and, after some indirection, I found a read of the presumed-CCP EEPROM flag through a function pointer. Fortunately 0x797 was the towards the top of the table

    Looking through the payload handler:

    Click image for larger version

Name:	Screenshot 2026-10-30 at 1.28.47 AM.png
Views:	175
Size:	410.7 KB
ID:	614066
    Click image for larger version

Name:	Screenshot 2026-10-30 at 1.20.47 AM.png
Views:	173
Size:	190.1 KB
ID:	614064
    tbl_0f2eb:
    Click image for larger version

Name:	Screenshot 2026-10-30 at 1.21.40 AM.png
Views:	161
Size:	97.2 KB
ID:	614065
    Click image for larger version

Name:	Screenshot 2026-10-30 at 1.49.32 AM.png
Views:	172
Size:	435.5 KB
ID:	614067

    (I still don't know what the `_DAT_00400948` check is. Presumably a `wheel_speed == 0` check since it comes from RAM?)

    So now we know the second conditional in `can_rx_797_payload()` will evaluate to true (because the CCP flag is set). If we go to the function that gets evaluated in the conditional, we see something that looks suspiciously like an interpreter:

    Click image for larger version

Name:	Screenshot 2026-10-30 at 2.24.00 AM.png
Views:	169
Size:	543.1 KB
ID:	614069

    Looking at a CCP command ref (e.g. https://mxhelp.danlawinc.com/ccp_xcp_reference.htm), the `UPLOAD` function (0x4) is immediately interesting. Follow the function call in `case 4:` and jackpot:

    Click image for larger version

Name:	Screenshot 2026-10-30 at 2.05.16 AM.png
Views:	159
Size:	99.9 KB
ID:	614070
    Click image for larger version

Name:	Screenshot 2026-10-30 at 2.05.39 AM.png
Views:	167
Size:	218.6 KB
ID:	614068

    An unauthed, unbounded read in a loop that writes to a buffer (ignore the decompiled C code in that last screenshot, it's not looking all that great). Looks like the `UPLOAD` function to me!

    Lots of words and code to say that I was wrong and I'm now pretty convinced that CCP is supported on the e5 AND it can dump flash.

    Since the EEPROM flag is present on the MK60 dump, I'm pretty confident that it will be supported there too. Amazing.

    I know what the first thing I'm going to do when I get that MK60 is!
    2002 Topasblau M3 - Coupe - 6MT - Karbonius CSL Airbox - SSV1 - HJS - Mullet Tune - MK60 Swap - E86 Front Triangulation - ZCP Rack - Nogaros - AutoSolutions - 996 Brembos - Slon - CMP - VinceBar - Koni - Eibach - BlueBus - Journal

    2012 Alpinweiss 128i - Coupe - 6AT - Slicktop - Manual Seats - Daily - Journal

    Comment


      #92
      Oh baby! Now we’re getting somewhere
      ‘02 332iT / 6 | ‘70 Jaguar XJ6 electric conversion

      Comment


        #93
        Nice work Heinz - this is epic! very much enjoying following this along!

        Originally posted by heinzboehmer View Post
        (ignore the decompiled C code in that last screenshot, it's not looking all that great)
        FWIW pretty much all of the weirdness in the Ghidra C-code view can be resolved by making sure your function parameters (number and datatype) and return value (datatype) are correct. For example
        Code:
        int can_rx_797_payload(void)
        I'm willing to bet if you follow where it's called the return value isn't actually used. If so, and you modify the function prototype in Ghidra to be a void return type you'll see a bunch of that weirdness clean itself up.

        2005 ///M3 SMG Coupe Silbergrau Metallic/CSL bucket seats/CSL airbox/CSL console/6 point RACP brace/Apex ARC-8s
        Build Thread | Community Patch | MSS54 DS2 Tool

        Comment


          #94
          Originally posted by karter16 View Post
          FWIW pretty much all of the weirdness in the Ghidra C-code view can be resolved by making sure your function parameters (number and datatype) and return value (datatype) are correct. For example
          Code:
          int can_rx_797_payload(void)
          I'm willing to bet if you follow where it's called the return value isn't actually used. If so, and you modify the function prototype in Ghidra to be a void return type you'll see a bunch of that weirdness clean itself up.
          That's good to know! First time using Ghidra for this kind of work, so still stumbling through it. Will try to fix all this weirdness now.

          Edit: Oh man, it's so much nicer with these fixes. Thanks! Repo updated with this in mind, so any .0pa you feed the workflow will generate these nice Ghidra projects automagically.
          Last edited by heinzboehmer; 10-30-2026, 02:51 PM.
          2002 Topasblau M3 - Coupe - 6MT - Karbonius CSL Airbox - SSV1 - HJS - Mullet Tune - MK60 Swap - E86 Front Triangulation - ZCP Rack - Nogaros - AutoSolutions - 996 Brembos - Slon - CMP - VinceBar - Koni - Eibach - BlueBus - Journal

          2012 Alpinweiss 128i - Coupe - 6AT - Slicktop - Manual Seats - Daily - Journal

          Comment


            #95
            Nice work heinzboehmer!

            Comment


              #96
              Non-M MK60 sent by George has arrived. I'm still waiting on some pins to finish up the bench harness, so haven't poked at the CCP thing yet, but I will soon. These are supposedly non-flashable, but we'll see about that

              I did immediately cut it open, though, just to see what I could learn from probing the PCB:

              Click image for larger version  Name:	20261102_193700.jpg Views:	0 Size:	181.8 KB ID:	614481

              Lowest hanging fruit in my mind was to figure out the M track mode input. Bry5on did some digging into this earlier, so a lot of this is just redoing his work. Here's the pin that would be used for M track mode and the DSC button input. Keep in mind that this is on the non-M board, the ZCP board has slightly different values for the components:

              Click image for larger version  Name:	Screenshot 2026-11-04 at 12.48.46 AM.png Views:	0 Size:	145.4 KB ID:	614482

              Math checks out with some previous measurements.

              Poked around and found a few other input pins with similar layouts:

              Click image for larger version  Name:	Screenshot 2026-11-04 at 12.50.53 AM.png Views:	0 Size:	38.3 KB ID:	614483
              Click image for larger version

Name:	Screenshot 2026-11-07 at 11.54.30 AM.png
Views:	40
Size:	240.4 KB
ID:	614778

              The last two are interesting. Same exact layout as pin 38, but with some more circuitry attached at the point that would usually be grounded. This makes me think the TI IC is keeping the pin attached to R14 pulled _up_ when the MK60 is powered on, but I haven't tested. I think that makes sense, cause otherwise you'd have a permanent pull up line running all the way to the brake fluid reservoir and the parking brake.

              Anyway, I think getting the M track mode input working on a non-ZCP module is doable. The shunt resistor is different, but the RC filter is the same. If the input is too touchy, the SW debounce can be tweaked (once I figure out the reflashing of these modules) to make up for it. Worst case, you can cut a small access hole into the cover and swap the resistor out.

              Originally posted by karter16 View Post
              Re the TI chip I think it’s maybe a custom ASIC for controlling the hardware, it sits on the headers side of the board and some very similar part numbers are labeled on some 3rd party sites as “Teves PCU60”. I’m guessing “PCU” stands for “Pump Control Unit” or something similar.
              I think you might be right. At least one of the pins on the TI chip is connected to the network of transistors/MOSFETs right by the pump connector, so that would make sense.
              Last edited by heinzboehmer; 11-07-2026, 11:58 AM.
              2002 Topasblau M3 - Coupe - 6MT - Karbonius CSL Airbox - SSV1 - HJS - Mullet Tune - MK60 Swap - E86 Front Triangulation - ZCP Rack - Nogaros - AutoSolutions - 996 Brembos - Slon - CMP - VinceBar - Koni - Eibach - BlueBus - Journal

              2012 Alpinweiss 128i - Coupe - 6AT - Slicktop - Manual Seats - Daily - Journal

              Comment


                #97
                Updated the pin 9/27 schematic above after some more probing. I'm not at all convinced it's correct in the areas around Q1/Q2 (they both look so wrong, but I probed it a million times and this is what the meter says), but that section isn't really relevant at all to the button inputs.

                I think the general idea is this:
                • R14 goes to an `enable` output from the TI IC, which is likely just high whenever the module is booted. This pulls up the Pin 9 and Pin 27 inputs as well.
                • I bet R15 goes to an input in the TI IC. Probably used for monitoring pump current or short/open circuit faults.
                • R16 is probably another input. Highly likely that it controls the pump.
                Again, the schematic doesn't really agree with the above logic, but I trust this general idea more than my probing. The module is built with a multi layer board, so tracing stuff is super tedious and easy to mess up.

                Anyway, harness stuff has all arrived. I need to sit down this weekend and get it built. For this early prototype, I'm going to use a V4 Gauge.S board I have lying around, since it's ESP32 based and it has all the HW needed to do both K line and CAN communications. I found this, which would be perfect for in car flashing, but I haven't heard back from the creator yet: https://github.com/muki01/OBD2_K-line_Reader (scroll down to "Custom PCBs" for pictures of the thing)

                I'd like to avoid designing a custom PCB or building this around a J2534 pass through adapter ($$$ for the real ones), because I think it will limit the audience significantly. If I can make an off the shelf product (like the `muki01` device or a Gauge.S) work for reading/flashing, then anyone can buy one, flash custom FW on it and do as they please with their MK60.

                Just for clarity, a normal K+DCAN cable will not work for this because CCP is not a supported protocol on them. It's essentially impossible to find diagnostic type cables that support it, so you're left with crafting and sending out the CAN packets yourself. Easiest way to do this is have HW that (electrically) translates CAN to something a computer can understand (serial over USB or whatever), then have the computer do all the protocol logic. For this project, the HW will just act as a dumb pass through.

                The other option is to reflash an ELM327 bluetooth adapter with custom FW, similar to what's described in the ediabaslib repo: https://github.com/uholeschak/ediaba...p-obd-firmware

                This option is attractive cause those adapters are cheap and easy to find, but there are some drawbacks. It's a little tricky to get a genuine ELM327 with a real CAN controller (not transceiver) and there's also something that just doesn't sit well with me about trying to hit all these timing target over bluetooth. I know the protocol can handle it in theory, but man, my faith in bluetooth stability is basically nonexistent.

                Anyway, going forward with the Gauge.S route for now, will reevaluate the `muki01` device once I hear back from the creator.

                Also, here's some closeups I took of the board, just for posterity:

                Click image for larger version

Name:	20261102_193627.jpg
Views:	47
Size:	205.2 KB
ID:	614782
                Click image for larger version

Name:	20261102_193630.jpg
Views:	48
Size:	231.3 KB
ID:	614783
                Click image for larger version

Name:	20261102_193700.jpg
Views:	47
Size:	181.8 KB
ID:	614784
                Click image for larger version

Name:	20261102_203253.jpg
Views:	47
Size:	219.2 KB
ID:	614785
                Click image for larger version

Name:	20261104_182322.jpg
Views:	46
Size:	190.9 KB
ID:	614786
                2002 Topasblau M3 - Coupe - 6MT - Karbonius CSL Airbox - SSV1 - HJS - Mullet Tune - MK60 Swap - E86 Front Triangulation - ZCP Rack - Nogaros - AutoSolutions - 996 Brembos - Slon - CMP - VinceBar - Koni - Eibach - BlueBus - Journal

                2012 Alpinweiss 128i - Coupe - 6AT - Slicktop - Manual Seats - Daily - Journal

                Comment


                  #98
                  Might just be worth using a candlelight interface or something and just 'speak' CAN frames directly? Lot of hardware out there that can be flashed with that firmware and pretty cheap. Open source too if certain mods make CCP (and other stuff) easier.

                  Comment


                    #99
                    Originally posted by terra View Post
                    Might just be worth using a candlelight interface or something and just 'speak' CAN frames directly? Lot of hardware out there that can be flashed with that firmware and pretty cheap. Open source too if certain mods make CCP (and other stuff) easier.
                    The one thing with those CAN devices is that most of them don't speak K line and you need to enable CCP over K line first. I could use two separate devices, one for each protocol, but that feels a bit messy. Gauge.S can speak both directly with a bit of custom FW.

                    I actually already have "working" FW and an accompanying desktop CLI/GUI to drive the read/flash. It's unit tested and appears to work, but I haven't finished up the harness, so I haven't tested on the HW. Soon though.

                    The K line/CAN passthrough FW is super simple, so it should be very easy to port to other ESP32-S3 based boards. It seems like a new implementation of those types of boards pops up every few days now 🙂
                    2002 Topasblau M3 - Coupe - 6MT - Karbonius CSL Airbox - SSV1 - HJS - Mullet Tune - MK60 Swap - E86 Front Triangulation - ZCP Rack - Nogaros - AutoSolutions - 996 Brembos - Slon - CMP - VinceBar - Koni - Eibach - BlueBus - Journal

                    2012 Alpinweiss 128i - Coupe - 6AT - Slicktop - Manual Seats - Daily - Journal

                    Comment


                      Ah I see.

                      Realistically CAN isn't exposed on the OBDII port anyway, so in my mind it doesn't seem completely unreasonable to have two separate devices, but I definitely get the desire to have an all-in-one solution so to speak.

                      Comment

                      Working...
                      X