Login Register

Vida CEM swapping

A mid-size luxury crossover SUV, the Volvo XC90 made its debut in 2002 at the Detroit Motor Show. Recognized for its safety, practicality, and comfort, the XC90 is a popular vehicle around the world. The XC90 proved to be very popular, and very good for Volvo's sales numbers, since its introduction in model year 2003 (North America). P2 platform.
Post Reply
User avatar
bobbik
Posts: 10
Joined: 13 February 2012
Year and Model: '05 V50 2.4i
Location: Poland
Has thanked: 1 time
Been thanked: 5 times

Re: Vida CEM swapping

Post by bobbik »

Hi . I didn't knew about such good topic , i already found it. I've got basic knowledge about CAN, limited knowledge about programming, good knowledge about Volvo electronics. I cloned few CEMs of different platforms, but old school way: with programmers. I can help with P1 platform, I've got everything you want: VIDA, oscilloscope, programmers, can sniffer , two my own P1 cars , few dumps on my computer, and will to help. I've got also few questions: anyone successfully read newer P1 CEM with 1M84E mask Motorola MCU's? Are they secured ? With known pin, what is the order to read/write eg. config table , what is CAN frames structure , and other stuff? Anyone could me explain it, as I'm not CAN expert ?

User avatar
Jackw16
Posts: 7
Joined: 15 January 2023
Year and Model: 2014 V40 D3
Location: March
Has thanked: 1 time
Been thanked: 1 time

Post by Jackw16 »

just spent a few days reading this thoroughly, its honestly the most informative and useful forum post on the internet about this stuff, got all the parts and currently trying the fantastic code with the p3 branch on my 2014 v40, will post back the results! :)

brobert
Posts: 29
Joined: 1 May 2010
Year and Model: 2006 V70
Location: Canada
Has thanked: 9 times
Been thanked: 13 times

Post by brobert »

Gang,

I have an '06 V70 and would like to make backup copies of my critical modules.
From what I understand, the modules are the CEM, (Denso) ECU, UEM and possibly the REM.
I have extracted my CEM PIN using a Teensy, thanks to the hard work of vtl and others.
If possible, I would prefer to backup my CEM via OBD/CAN as it is a pain to remove from the car.
I think that the other modules can be backed-up by hardware with UPA or Xprog.
I use a Mongoose cable with VIDA - I cannot seem to find a reasonably-priced DICE box.

My questions:
-Is it possible to use a Mongoose cable to dump the CEM or do I need a DICE?
-If using a DICE is best, has anyone seen a (full-chip) DICE clone < $200?
-It seems that many Secondary Boot Loaders (SBLs) exist. What is the best one to use?

Thanks from BC, Canada,
Benoit

dikidera
Posts: 1304
Joined: 15 August 2022
Year and Model: S60 2005
Location: Galaxy far far away
Has thanked: 67 times
Been thanked: 175 times

Post by dikidera »

You don't need dice. You need a CAN controller(with transceiver), and using your favorite tool to send and receive CAN commands. I can share with you my Python tools but they use SocketCAN on Linux.

In fact I am writing a fast dumper for exactly Denso(just the ECU). You can think of it as a custom SBL.

rkam
Posts: 102
Joined: 19 October 2022
Year and Model: 14473_96090_XC7007
Location: Norway
Has thanked: 5 times
Been thanked: 25 times

Post by rkam »

Software compiled to use DiCE will have to be rebuilt to use another J2524 device.
My Kvaser interface lacks K-line support, and opening MS-channel crashed. But after removing those it works.

If your Mongoose is fully compatible, you could cheat by copying its registry entries into entries named as a DiCE would be.

SBLs must match the controller.

dikidera
Posts: 1304
Joined: 15 August 2022
Year and Model: S60 2005
Location: Galaxy far far away
Has thanked: 67 times
Been thanked: 175 times

Post by dikidera »

As long as the memory model is the same, it should all work out. I believe the P2 S60 that use Denso should be mostly similar, but this is speculation, either way I will share the source code so anyone will be free to modify.

rkam
Posts: 102
Joined: 19 October 2022
Year and Model: 14473_96090_XC7007
Location: Norway
Has thanked: 5 times
Been thanked: 25 times

Post by rkam »

Yes, homemade and special boot loaders can be made to work on several controllers.

brobert
Posts: 29
Joined: 1 May 2010
Year and Model: 2006 V70
Location: Canada
Has thanked: 9 times
Been thanked: 13 times

Post by brobert »

I appreciate the great information and offer to help.
So if I get this right, every module should support the transfer and execution of an SBL (i.e.: 0xBA to upload and 0xE6 to execute)?
Obviously, the SBL has to take into account the module's architecture, memory range, watchdog requirements, etc.
Given the number of CAN cables and different modules to dump, it sounds to me like Python is a great choice.
In my case, the simplest would be to get my Mongoose cable to work in Python.
Come to think of it, it would be cool to bake all these SBLs into an Arduino program (using the Teensy PIN cracker circuit).
The Teensy could select what SBL to use (much like the PIN cracker uses different parameters based on the CEM p/n) and echo the dump back to the PC.
First, let me try and get this Mongoose cable to work...
Thanks,
Benoit
dikidera wrote: 15 Jan 2023, 12:38 You don't need dice. You need a CAN controller(with transceiver), and using your favorite tool to send and receive CAN commands. I can share with you my Python tools but they use SocketCAN on Linux.

In fact I am writing a fast dumper for exactly Denso(just the ECU). You can think of it as a custom SBL.

dikidera
Posts: 1304
Joined: 15 August 2022
Year and Model: S60 2005
Location: Galaxy far far away
Has thanked: 67 times
Been thanked: 175 times

Post by dikidera »

I suggest trying this for the watchdog first and if that doesn't work only then focus on finding the trigger.

Code: Select all

PB.DR.WORD ^= 0x8000;
(should be toggled at least every 45 000 microseconds, any higher and it would reset the ECU(provided the conditions are the same)

and maybe disabling the internal watchdog

Code: Select all

    WDT.WRITE.RSTCSR = 0xA500;
    WDT.WRITE.RSTCSR = 0x5A00;
    WDT.WRITE.TCSR = 0;
I also suggest simply cloning npkern and using it's headers, and most importantly, it's linker files. Without those it's simply a dead end.

https://github.com/fenugrec/npkern

My code is ugly but should give you some headstart perhaps on uploading a custom SBL

Code: Select all

# import the library
import can
import time
import sys

tSleep = 0.01

if len(sys.argv) > 2:
    binFile = sys.argv[2]
else:
    binFile = 'main2.elf'

bus = can.Bus(interface='socketcan',
              channel=sys.argv[1] if len(sys.argv) > 1 else 'can0',
              receive_own_messages=False)

# send a message
message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=[0xFF, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
print(message)                      
bus.send(message)

#sleep to ensure ECU got this message. 

time.sleep(1)

address = 0xFFFFA000 #HARDCODED, UPDATE as needed
msgdata1_template = [0x7A, 0x9C, 0x00, 0x00, 0x00, 0x00]
msgdata2_template = [0x7A, 0xAE, 0x00, 0x00, 0x00, 0x00]

computedAddress =  bytearray(address.to_bytes(4, 'big'))

msgdata1_template[2] = computedAddress[0]
msgdata1_template[3] = computedAddress[1]
msgdata1_template[4] = computedAddress[2]
msgdata1_template[5] = computedAddress[3]

message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata1_template)
bus.send(message)
time.sleep(1)
file_contents = []
f = open(binFile, 'rb')
fileData = f.read()
f.close()
file_len = len(fileData)
print("File len {}", file_len)
ptr = 0


msgdata2_template[2] = fileData[0]
msgdata2_template[3] = fileData[1]
msgdata2_template[4] = fileData[2]
msgdata2_template[5] = fileData[3]

message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata2_template)
print(message)
bus.send(message)
ptr += 4
address += 4
for msg in bus:
    print(msg)
    if(ptr+4 >= file_len): #problemo!! 
        break

    if msg.arbitration_id == 0x00000021:
       
        print(msg.data[2:])    
        if msg.data[1] != 0x9C:
            continue

        computedAddress =  bytearray(address.to_bytes(4, 'big'))
        msgdata1_template[2] = computedAddress[0]
        msgdata1_template[3] = computedAddress[1]
        msgdata1_template[4] = computedAddress[2]
        msgdata1_template[5] = computedAddress[3]

        message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                              data=msgdata1_template)
        print(message)
        bus.send(message)
        time.sleep(tSleep)
        print("File pointer {}", ptr)
        msgdata2_template[2] = fileData[ptr]
        msgdata2_template[3] = fileData[ptr+1]
        msgdata2_template[4] = fileData[ptr+2]
        msgdata2_template[5] = fileData[ptr+3]

        message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata2_template)
        print(message)
        bus.send(message)
        time.sleep(tSleep)
        
                        
        address += 4
        ptr += 4
            
    #print(hex(address - 2) + ': ' + hex(msg.data[2]))  
msgdata1_template = [0x7A, 0x9C, 0xFF, 0xFF, 0xA0, 0x00]
msgdata_execute = [0x7A,0xA0]
message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata1_template)
print(message)
bus.send(message)

time.sleep(tSleep)
message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata_execute)
print(message)
bus.send(message)

f.close()

Note, when in the car you may need to send the FF86 messages several times to ensure all modules are "sleeping".

Another advice I have is to dump the ECU fw and maps several times and compare the data for irregularities. Only then should you consider your dump as successful.

Here is the dumper, but I should warn you since it was a prototype there are almost no sanity checks and the last few bytes of data are missing due to the infamous off by one error, so I advise you to rewrite this piece of crap. Also it works when on the bench, there may be other requirements for when the ECU is in the car and especially the CEM.

Code: Select all

# import the library
import can
import time

# create a bus instance
# many other interfaces are supported as well (see documentation)
bus = can.Bus(interface='socketcan',
              channel='can0',
              receive_own_messages=False)

# send a message
message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=[0xFF, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
bus.send(message)

# iterate over received messages
address = 0x00000000
msgdata1_template = [0x7A, 0x9C, 0x00, 0x00, 0x00, 0x00]
msgdata2_template = [0x7A, 0xB4, 0x00, 0x00, 0x00, 0x00]

computedAddress =  bytearray(address.to_bytes(4, 'big'))

msgdata1_template[2] = computedAddress[0]
msgdata1_template[3] = computedAddress[1]
msgdata1_template[4] = computedAddress[2]
msgdata1_template[5] = computedAddress[3]

address = address + 1
computedAddress =  bytearray(address.to_bytes(4, 'big'))

msgdata2_template[2] = computedAddress[0]
msgdata2_template[3] = computedAddress[1]
msgdata2_template[4] = computedAddress[2]
msgdata2_template[5] = computedAddress[3]

message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata1_template)
bus.send(message)
message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                      data=msgdata2_template)
bus.send(message)
f = open('my_file', 'a+b')
for msg in bus:
    if msg.arbitration_id == 0x00000021:
    
        if address >= 0x7FFFF:
            break

        if(msg.data[1] != 0xB1):
            continue
            
        f.write(bytearray(int(msg.data[2]).to_bytes(1, 'big')))
    
        computedAddress =  bytearray(address.to_bytes(4, 'big'))

        msgdata1_template[2] = computedAddress[0]
        msgdata1_template[3] = computedAddress[1]
        msgdata1_template[4] = computedAddress[2]
        msgdata1_template[5] = computedAddress[3]

        address = address + 1
        computedAddress =  bytearray(address.to_bytes(4, 'big'))

        msgdata2_template[2] = computedAddress[0]
        msgdata2_template[3] = computedAddress[1]
        msgdata2_template[4] = computedAddress[2]
        msgdata2_template[5] = computedAddress[3]

        message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                              data=msgdata1_template)
        bus.send(message)
        message = can.Message(arbitration_id=0x000ffffe, is_extended_id=True,
                              data=msgdata2_template)
        bus.send(message)
        
        #time.sleep(0.002)
            
    print(hex(address - 2) + ': ' + hex(msg.data[2]))

f.close()

User avatar
Jackw16
Posts: 7
Joined: 15 January 2023
Year and Model: 2014 V40 D3
Location: March
Has thanked: 1 time
Been thanked: 1 time

Post by Jackw16 »

just an update, worked perfectly, got 909/s speed, took about 4:30hrs to crack a p3 cem from a 2014 v40, trying a 2016 v40 tomorrow, im thinking of doing a little wiki write up about this info etc does anyone mind? just some bench info and how to find and use the p3 branch as the info is spread about these 250 odd pages

Post Reply
  • Similar Topics
    Replies
    Views
    Last post