VPW DPID support?


I reached out a while back about the custom VPW payload support and had my first track weekend last weekend. It worked great! I now have brake module data that I never had before which is awesome.

I have a question about how the software handles VPW packets with different headers.

Since the GM VPW bus is very slow (10.4 kbps), GM has DPID support. Which basically allows you to cut down on the number of requests needed. You can request up to 4 PIDs with a single request message. This has the advantage of getting rid of up to 3 messages transmitted on the bus.

Does the software do a request, and then wait for a reply before moving onto the next request/PID?

Reason I ask is that I am able to achieve higher throughput with some diagnostic tools I programmed (for development of hardware) by taking advantage of DPIDs.

The general process is to send a request message to a module, asking for up to 4 parameters. The module replies with 4 seperate messages like normal, of the PIDs in question as quickly as it can, and time synched. As the messages come in, i know the response prefix since I know I sent the DPID request. So i don't necessarily have to do a single request/response when polling, which helps my throughput.

I'm not sure if this is something that's possible to support, as it would require multiple responses to a single request to be processed for different PIDs. Almost like a filter as they come in.

You can see on the green and yellow traces (brake and throttle), the refresh rate can be a bit slower, which i know is due to the fact that they come from different modules, and probably waits for one to respond before requesting a pid from the other. I poll multiple parameters from the ECU so using DPID could help.



  • Can you provide me an example ELM327 communication for multi-PID-request?
  • Sure, It's similar to a regular request, expect that the first byte is different, signaling a DPID mode to the module. Then the module will give responses back.

    Here's an example from a bus datalog. Headers and the checksum are shown.

    1) 6C 28 F1 2A 03 20 21 40 41 A6

    2) 6C F1 28 6A 20 00 00 00 00 00 FF 42

    3) 6C F1 28 6A 21 9B 00 A5 00 82 01 4F

    4) 6C F1 28 6A 40 83 05 7F 00 00 00 11

    5) 6C F1 28 6A 41 00 00 05 00 00 00 B9

    1) Request from tool ($F1) for DPID data (mode 2A). 03 corresponds to an internal time interval for automatic sending, but for a single poll event, you can use 01 instead. 20, 21, 40, and 41 are all the PIDs that the module is requesting be sent (in a single request message). You can request up to 4 PIDs at a time, I believe. For my custom PIDs, I am using this mode (ABS module only supports mode $2A for data requests), but I specify only 1 PID since the software throws the rest away, and requesting more would be a waste of throughput.

    2-4) The module sends the requested data as separate messages, but you can see the affirmative response ($6A) followed by the PID that is being send (20, 21, 40, 41), followed by the data.

    The way I understand your implementation is that you do a single request, single response method and throw any additional responses away. This implementation would require that you have a way to tie a single request to multiple logged PIDs/groups of PIDs, and then parse the messages as they come in/filter them to determine which PID they correspond to.

    I realize this is likely a large undertaking. A potential work around for me might be to make a custom piece of hardware that handles this efficient polling by itself and can send the data over BLE as requested by RaceChrono. It would be nice if multiple response support were possible.

    In addition to DPID support, these OEM scanning tools also send a "bus silence" message out that will ask the modules not to transmit lower priority messages in order to help throughput further, but this is probably not needed.

  • To summarize, the main difference is that you can request a vehicle module send multiple messages with a single request message instead of the 1 request = 1 response model that is used now.

    With this, 1 request = up to 4 responses, with very little time between the responses (as short as the module can possibly deliver), to further improve throughput.

  • edited March 2021
    OK thank you. I think you can already configure this, it might work depending how ELM327 will present the multiple responses.

    Try this

    Channel 1:
    PID: 0x 2A 03 20 21 40 41 A6
    Response prefix: 0x 6A 20

    Channel 2:
    PID: 0x 2A 03 20 21 40 41 A6
    Response prefix: 0x 6A 21

    And so on... Of course it's not very nice to have to manually stack the requests. And it makes it hard to select different channel combinations. But if it makes your bus more efficient then why not :)

    RaceChrono already bundles channels with same PID as one single request, so this should work in theory...
  • I didnt' realize it did this. So if multiple PIDs have the same request, the software is smart enough to only send one request?
  • We used this on Suzuki SDS K-Line bus that has only one request, but multiple channels in single response.
  • This is awesome. I've confirmed the ECU-defined DPIDs work. Now i'm curious if we can take this a step further and build custom DPIDs.

    I'll explain in more detail what a DPID is. Basically, it's a group of PIDs that get mushed together into a single response.

    A basic example of this is requesting a DPID #FE from the ECU with
    61 f1 10 2A 01 FE. I've requested only a single DPID, but within this DPID, there are 4 PIDs (you can see why this is so helpful for throughput).

    The ECU will respond with
    6C F1 10 6A FE 00 00 00 00 00 6C. This is on a bench ECU, so al lthe values are 0 right now, but bytes [0:1] = RPM, [2:3] = MAF, [4]=TPS, [5]=map.

    This is helpful with the support you have, but what if I don't want to record MAF and instead want to record spark? Well, I can build a custom DPID with mode $2C. The downside is that it must be built every time the ECU is power cycled and it takes multiple initialization messages to do it.

    So here's an example of building a DPID (we'll use #26 as an example, I'm not 100% sure what the acceptable range is by the ECU, but I know in the 20s works).
    Lets build a DPID with the following PIDs, we have up to 5 bytes to return data with
    1) $000C: high res RPM (2 bytes)
    2) $000B: MAP (1 byte)
    3) $0005: ECT (1 byte)
    4) $000F: IAT (1 byte)

    Initialization requirement with the ECU to build the DPID:
    1) 6C 10 F1 2C 26 4A 00 0C: the 4A assigns the byte location, and number of bytes for the PID. Bits [7:6] say its a PID, [5:3] explain which return byte, [2:0] say how many data bytes are returned for the PID
    2) 6C 10 F1 2C 26 59 00 0B
    3) 6C 10 F1 2C 26 61 00 05
    4) 6C 10 F1 2C 26 69 00 0F

    Once these are loaded up, then we can request the DPID with our normal DPID request PID for the remainder of the time the ECU is powered.

    TX: 6C 10 F1 2A 01 26
    Response with 4 PIDs: 6C F1 10 6C 26 aa aa bb cc dd xx
    aa is RPM
    bb is MAP
    cc is ECT
    dd is IAT

    Any chance the software already supports sending these DPID request initialization commands on the start of a datalog?

  • I see there are initialisation commands, i'm not quite sure where they occur in the setup timeline though. I'll play with this and see if I can get it to build a DPID packet.
  • I'll be damned. SO I piled all the commands into the initialization and it worked!

    Only thing I'm noticing now. I made sure to group my DPIDs into fast and slow groups, so that all the fast PIDs would use 1 DPID and all the slow would use another.

    I'm seeing when I sniff the bus that it simply polls between fast and slow. It's not hitting the fast one several times and then hitting the slow. So my fast and slow channels have the same sample rate right now. I'd like to prioritize engine RPM and stuff and let air and trans temps be slow.
  • Alright, sorry for spamming you. This is my last post. I've been working on this because I have a track even this weekend so I was tryign to figure eveyrthing out before hand. Quick test shows it does work.

    Few things:
    1) Fast vs slow channels don't seem to get differentiated when I look at data bus with a sniffer. It seems the software is literally just alternating between the two PIDs, even though I have 1 set to slow and one set to fast. Realistically, my "slow" channels can be read every 2-5 seconds (oil, intake, trans temps). I'd rather read my RPM and throttle/brake data quickly.

    2) Since they both seem to fire off at the same rate, I tried combining my PID request into 1. RC did NOT like this. Remember I have 2 separate DPIDs (groups of PIDs), one is fast (0xFE), and the other is my slow PIDs (0xFD). I can request them both at the same time with
    6C 10 F1 2A 01 FD FE: This says send me DPIDs FD and FE once.

    Response is 2 separate messages
    1) 6C F1 10 6A FD aa bb cc 00 00 00 xx
    2) 6C F1 10 6A FE dd dd ee ff gg 00 xx

    aa = air temp
    bb = ect
    cc = trans temp
    dd dd = rpm (2 bytes)
    ee = oil pressure
    ff = throttle %
    gg = knock
    xx = crc

    My thought process here is that by combining all of my PIDs into the single request, I at least get rid of 1 request and improve my overall throughput (they have the same header and PID now, only different is the response prefix).
    Race chrono seemed to only look at the first response it got to the request.

    Since the first response is the FD DPID, only the PIDs with the 6a FD response prefix recognized it. All the 6A FE prefix PIDs showed red text with the raw data in the menu.

    If I swapped FD and FE around in the request, the opposite became true of the PIDs.

    It seems like RC is unable to handle getting 2 responses for some reason? Once I split the PIDs back to either FD or FE only, RC was happy and processed the data, but my throughput went down since it would send FD request, wait for response, then send FE request, wait for response.

    Ultimately, i'd like to see the slow data sample slower than the fast.

    **** Stuff for your debugging if it's helpful ****
    Here's what I put in my initialization part of the profile: atsh6c10f1\n2cfe4a000cffff\n2cfe59115cffff\n2cfe610011ffff\n2cfe6911a6ffff\n2cfd49000fffff\n2cfd510005ffff\n2cfd591940ffff\n
    It just sets up the DPIDs as I illustrated above

    Here's the raw dump from my bus when RC was data logging: I stripped the module heart beat messages out to make it only RC's traffic

    6C 10 F1 2C FE 4A 00 0C FF FF CC <-- This is where RC starts its custom initialization
    6C F1 10 6C FE 4A CB
    6C 10 F1 2C FE 59 11 5C FF FF 5C
    6C F1 10 6C FE 59 21
    6C 10 F1 2C FE 61 00 11 FF FF 59
    6C F1 10 6C FE 61 83
    6C 10 F1 2C FE 69 11 A6 FF FF F4
    6C F1 10 6C FE 69 6B

    6C 10 F1 2C FD 49 00 0F FF FF 34
    6C F1 10 6C FD 49 38
    6C 10 F1 2C FD 51 00 05 FF FF A2
    6C F1 10 6C FD 51 1D
    6C 10 F1 2C FD 59 19 40 FF FF 18
    6C F1 10 6C FD 59 F5
    6C 10 F1 01 00 E2 <-- No idea what this is. I assume this is you in RC doing something
    6C F1 10 7F 01 00 11 A8 <-- ECU didn't like whatever request this was, sends a "Mode not supported" message
    6C 10 F1 2A 01 FD B1 <--- This is the first time RC starts polling, asks for the low speed PIDs first (FD)
    6C F1 10 6A FD 01 01 01 00 00 00 3A <-- The response, with 3 PIDs in this response
    6C 10 F1 2A 01 FE 96 <-- Now RC asks for the high speed
    6C F1 10 6A FE 00 00 01 00 00 01 EC <-- The response with RPM and other high speed PIDs
    6C 28 F1 2A 01 41 19 <-- It now asks my ABS module for brake pressure (fast PID)
    6C F1 28 6A 41 00 00 05 00 00 00 B9 <- Gets response
    6C 10 F1 2A 01 FD B1 < - Back to slow PID??
    [Cycle repeats below]
    6C F1 10 6A FD 01 01 01 00 00 00 3A
    6C 10 F1 2A 01 FE 96
    6C F1 10 6A FE 00 00 01 00 00 01 EC
    6C 28 F1 2A 01 41 19
    6C F1 28 6A 41 00 00 05 00 00 00 B9
    6C 10 F1 2A 01 FD B1
    6C F1 10 6A FD 01 01 01 00 00 00 3A
    6C 10 F1 2A 01 FE 96
    6C F1 10 6A FE 00 00 01 00 00 01 EC
    6C 28 F1 2A 01 41 19
    6C F1 28 6A 41 00 00 05 00 00 00 B9
    6C 10 F1 2A 01 FD B1
    6C F1 10 6A FD 01 01 01 00 00 00 3A
    6C 10 F1 2A 01 FE 96
    6C F1 10 6A FE 00 00 01 00 00 01 EC
    6C 28 F1 2A 01 41 19
  • edited March 2021
    I don't mind spam :) But you might not get answers to all your questions, if you bury them in a lot of content, or if I interpret that you've already figured it out.

    1) Slow/Fast channels work like this: All fast channels are requested once. After that one of the slow channels are requested. Then the loop starts from beginning. It does not really work if you have only one fast and one slow channel.

    2) No idea where "6C 10 F1 01 00 E2" comes from... shouldn't be me... something in the configuration.

    3) So the request "bundling" does not work like I described? RaceChrono looks at all the response lines, but it maybe failing for other reasons. What does the response look like when requesting multiple PIDs in one? Please be exact I will use it to write an emulator.

  • edited March 2021
    Alright, I have gone and setup a profile again (btw, whenever I import a profile, it overwrites the existing profile, not add another. This issue exists on Android and iOS).

    Here's where I'm at. Here's an exact datalog for when I request 2 PIDs with a single request.

    6C 10 F1 2C FE 4A 00 0C FF FF CC <== ECU DPID request for 0xFE
    6C F1 10 6C FE 4A CB
    6C 10 F1 2C FE 59 11 5C FF FF 5C <== ECU DPID request for 0xFE
    6C F1 10 6C FE 59 21
    6C 10 F1 2C FE 61 00 11 FF FF 59 <== ECU DPID request for 0xFE
    6C F1 10 6C FE 61 83
    6C 10 F1 2C FE 69 11 A6 FF FF F4 <== ECU DPID request for 0xFE
    6C F1 10 6C FE 69 6B
    6C 10 F1 2C FD 49 00 0F FF FF 34 <== ECU DPID request for 0xFD
    6C F1 10 6C FD 49 38
    6C 10 F1 2C FD 51 00 05 FF FF A2 <== ECU DPID request for 0xFD
    6C F1 10 6C FD 51 1D
    6C 10 F1 2C FD 59 19 40 FF FF 18 <== ECU DPID request for 0xFD
    6C F1 10 6C FD 59 F5
    6C 10 F1 01 00 E2 <== Still no idea where this came from
    6C F1 10 7F 01 00 11 A8
    6C 10 F1 2A 01 FD FE 93 <== First request by RC for polling. This requests DPIDs 0xFD and 0xFE
    6C F1 10 6A FD 01 01 01 00 00 00 3A <== Response for 0xFD from ECU
    6C F1 10 6A FE 00 00 01 00 00 00 F1 <== Response for 0xFE from ECU
    6C 28 F1 2A 01 41 19 <== Request for ABS module PIDs
    6C F1 28 6A 41 00 00 05 00 00 00 B9 <== Response from ABS
    6C 10 F1 2A 01 FD FE 93 <== Request from ECU for DPIDs 0xFD and 0xFE again thigns repeat again
    6C F1 10 6A FD 01 01 01 00 00 00 3A
    6C F1 10 6A FE 00 00 01 00 00 00 F1
    6C 28 F1 2A 01 41 19

    Race chrono does not like this for some reason. In this case, all the PIDs that ahve OBD response prefix of "0x6A FE" are just read, even though the data is valid. I have a screenshot, but can't show it to you on this forum for some reason...

    all of my PIDs have a OBD header of "0x6C 10 F1" and a PID of "0x2A 01 FD FE", and the OBD response prefix varies between "0x6A FE" and "0x6A FD"
  • Thank you. Can you also email me the profile to tracks(at)racechrono.com or my real email if you have it? I'll try to figure out the mystery request too.
  • Sent the profile to you.
  • Also just wanted to say regarding the partial support I have here, that my throughput is SUBSTANTIALLY improved!

    I went from logging 4 PIDs at ~2-3 Hz to logging 8 PIDs at 5-6 Hz
  • Would this possible work on CAN vehicles too? via $2C logging or some other DPID based logging method. On my 2017 Audi S3 (Simos18.6), I went from about a 100 pid/s rate using standard mode $22 logging, to about 3500+ pid/s with a custom software patch that uses DPID logging very similar to $2C, but is hung off $3E tester preset instead.

    I think many of the newer Bosch ECUs have $2C implementation in stock form though.
  • I can't comment on that. It appears that it would, as you can definitely have multiple PIDs come from a single message.
  • @aaronc7 I'd have to see the ELM327 input/output log to be able to comment on it. Once I fix the problem @jvaldez is having, I would guess it could be used with any other bus/ECU that supports stacking the requests.
  • @jlvaldez Bugs fixed and usability improved in v7.2.4, please give me feedback again. I think there's a good chance it works now!
  • Got your email. Thanks for the update.

    I just tested 7.2.4. I can confirm that this multiple responses from single PID request now works as expected! Thank you!

    One thing i see still is that when I import a profile, it overwrites my existing profile instead of adding another (they have different names).

    I would like to be able to have a few profiles for specific data sets, since each PID has to be custom built using this approach.

  • @jlvaldez on my TO-DO list to fix
  • Awesome. Thank you!

  • @jlvaldez Would you mind sharing your profile? Would like to see how you get it all set up with DPIDs. I want to test it on my C5 first (assuming that will be no issue since you got it working), then I want to give it a shot on my other vehicle as well, once I wrap my head around the process/syntax a bit more.
  • edited July 2021
    Hello, about to test this out on the same car and just had a few questions going into it.

    I think I understand the general concepts here.

    - Input init string to "build out" the DPIDs are desired....in the example some params were loaded up into FD and FE locations.

    - Define a "custom PID" in RaceChrono that is basically requesting to read FD and FE locations: 6C 10 F1 2A 01 FD FE

    - From what I understand, as part of the init DPID building process, you know what byte will be which param in the response.

    But how do I set up RC so that it knows that FD byte 5 is air temp, FE byte 6 is knock (for example), etc.? @aol I poked around the software, but I can't seem to find anything along those lines.....but I could very well be missing it.

  • @aaronc7 The basic idea is to set the same OBD-II header and PID for several channels (here two, for FD and FE). The ECU will respond with two lines, one of FD and one for FE. The OBD-II response prefix is used to select the correct response line.

    @jvaldez has the following:
    OBD-II header: "0x6C 10 F1"
    PID: "0x2A 01 FD FE"
    OBD-II response prefix: "0x6A FE" for one channel and "0x6A FD" for the other channel
  • Thank you, I'll give it a go today!
  • edited July 2021
    OK great, got it working. So much faster logging rate is great.

    I guess now we just need a way to parse out the individual bytes into known parameters such as RPM, oil pressure etc?



  • @aaronc7 I'm sorry I haven't been active on the forum recently. Do you still need my profile? I'd be happy to upload it to the web for others to use! Perhaps it makes sense to have a "Car specific profile" upload for some of these special car features. I'm not sure how to upload it.

    Everything you mentioned about understanding the DPID above is correct.
    I had to create new custom PIDs for each of the bytes in the responses to pull out the specific bytes of interest. @aol updated the software to recognize when multiple PIDs use the same request message and it only sends it once and is able to use the same response for multiple custom PIDs.

    FWIW the C5 ABS module does report steering angle, but for some reason it doesn't seem to work on my car. When I poll it with my Tech 2, it always shows 0*, even though the raw voltage output of the steering sensor changes. I'd like to get some steering sensor input data...

    Events are non existent right now by me, so I'm off track until September at least.
  • @jlvaldez yes I would like your profile still if able! Will take a little of the guesswork out of it. I got it working in a limited capacity, but I seem to have lost the info in the profile (doh).

    As you saw I got it working for CAN stuff. I'm not quite as familiar with VPW message format, but I'm sure I can figure it out when I re-visit this soon...

    Thanks for leading the way on this and @aol for supporting/implementing in the app as needed!
Sign In or Register to comment.