RegisterSearchFAQMemberlistUsergroupsLog in
Reply to topic Page 1 of 1
Subaru SSM protocol over OBDII
Author Message
Reply with quote
Post Subaru SSM protocol over OBDII 
Diving into the world of logging from the Subaru ECU I found a good bit of information from the RomRaider site (a tool I've begun using because of the tuner who is working on my engine/map).

The Subaru ECU uses the SSM protocol to handle request/responses to the ECU (reading and writing):

http://romraider.com/RomRaider/SsmProtocol

so.... now to start reading up on Lua and figure out if the ECU can be queried this way.

View user's profile Send private message
Reply with quote
Post  
Sorry to hi-jack your thread, but I've got a question:
Im close to pulling the trigger on an MK3 system for my 914-WRX project here. Its got a 2002 EJ motor and Im going to be running a custom flash via RomRaider. Does the RaceCapture interface well enough with the Subaru ECU to pull RPM and speed #s? First and foremost, I need the RaceCapture to send the basic information over bluetooth to an android tablet. If there are compatibility issues, how extensive are they? Id like to know if there are compatibility issues before buying a whole bunch of expensive gear!
Thanks,
Mat

View user's profile Send private message
Reply with quote
Post  
Yes, SSM over an ISOTP layer will get you what you want.
Doing a Single "Byte" or "U8" read is very easy

The layout goes [0xA8,0x00,ptra<<16,ptra<<8,ptra]. where prta is a 24 bit point to your reading object.
This takes 5 bytes in the ISOTP layer, then 6 bytes total on CAN Physical Layer

0x7E0 [DLC=7], data{ (PCI_SINGLE<<4) + (tx->size&0x07), 0xA8,0x00,ptra<<16,ptra<<8,ptra}

This is effectively sending a "Single ISO" Frame, where the payload of the "SSM" message is 7 bytes or less.

What is complicated is when you want to ask for multiple U24 points to read larger datatypes inside the ECU.

[0xA8,0x00,ptra<<16,ptra<<8,ptra,ptrb<<16,ptrb<<8,ptrb]
lets say you want to SSM request ptra, then ptrs ( which would be 1 byte away as an example to get a U16)

This is 8 items, and thus ISOtp needs to include sending a First Frame, wait for the FLOW, then send the consecutive frames.


I ending up making an external bare metal device that does this all for me, polling for response @ 200uSec / 5khz. This then pumps up straight up CAN messages to RCP directly. Lua was going to be too slow, and requires tight coupling of the ISOtp layer.

I could consider porting and placing all of this inside a branch build of RCP, but it might be skew the product a bit and make it too specific for Subarus'.







Code:

void sendIsoSingleFrame(IsoTpMessage* tx)
{
    uint8_t t = 0;
    if(tx->size <= 7)
    {
        isotp_can_tx.id      = tx->id;    /* standard frame */
        isotp_can_tx.dlc  = 8;/* Length = 8 */
        isotp_can_tx.data8[0] = (PCI_SINGLE<<4) + (tx->size&0x07);
        while(t<tx->size)
        {
            isotp_can_tx.data8[1+t] = tx->payload[t];
            t++;
        }
                CAN_Write ( CAN_BUS1, &isotp_can_tx);
    }
}

void sendIsoFlowFrame(uint32_t id, uint8_t iso_flow, uint8_t iso_block, uint8_t times)
{
      isotp_can_tx.id      =  id;    /* standard frame */
      isotp_can_tx.data8[0] = (PCI_FLOW_CONTROL_FRAME<<4) + (iso_flow&0x07);
      isotp_can_tx.data8[1] = iso_block;
      isotp_can_tx.data8[2] = times;
      isotp_can_tx.data8[3] = 0x00;
      isotp_can_tx.data8[4] = 0x00;
      isotp_can_tx.data8[5] = 0x00;
      isotp_can_tx.data8[6] = 0x00;
      isotp_can_tx.data8[7] = 0x00;
            CAN_Write ( CAN_BUS1, &isotp_can_tx);
}

void sendIsoFirstFrame(IsoTpMessage* tx )
{
    uint8_t t = 0;
    isotp_can_tx.id      = tx->id;    /* standard frame */
    isotp_can_tx.data8[0] = (PCI_FIRST_FRAME<<4) + ((tx->size>>8)&0x0F);
    isotp_can_tx.data8[1] = ((tx->size)&0xFF);
    tx->index = 1;
    while(t<6)
    {
        isotp_can_tx.data8[2+t] = tx->payload[t];
        t++;
    }
    tx->dataIndex += t;
        CAN_Write ( CAN_BUS1, &isotp_can_tx);
}

void sendIsoConsecutiveFrame(IsoTpMessage* tx )
{
    uint8_t t = 0;
    isotp_can_tx.id      = tx->id;    /* standard frame */
    isotp_can_tx.data8[0] = (PCI_CONSECUTIVE_FRAME<<4) + ((tx->index)&0x0F);
    tx->index++;
    if(tx->index>15)
    {
        tx->index = 0;
    }

    while((t < 7) && ((t+tx->dataIndex) < tx->size))
    {
        isotp_can_tx.data8[1+t] = tx->payload[t + tx->dataIndex];
        t++;
    }
    tx->dataIndex += t;

        CAN_Write ( CAN_BUS1, &isotp_can_tx);

}



View user's profile Send private message
Reply with quote
Post  
jlwall, huge thank you for the info; the explanation is very thorough. I just need to figure out what I actually need from the ECU - I may be able to get away with a single channel... and unpack the info you provided!

MichiganMat wrote:
Does the RaceCapture interface well enough with the Subaru ECU to pull RPM and speed #s? First and foremost, I need the RaceCapture to send the basic information over bluetooth to an android tablet.


In my install I've been able to use alternate means to get the RPM and speed. For RPM I tapped the RPM signal wire to the combination display and ran that to one of the RaceCapture/Pro RPM signal inputs. Works fine for me. Also, the built in GPS functions accurately display speed (my LCD display now blocks the speed on combo display, but I verified speed vs speed).

I imagine you could pull the RPM signal from the ECU this way without the OEM display, or if not use the coil-X module to read directly from the ignition pulses?

I can't verify yet, but I expect these methods give a higher sample rate than polling the ECU.

View user's profile Send private message
Reply with quote
Post  
There are also items in the wild, this is what I pull off the main bus, which is also the bus that is on the orbit/ssm 0x7e0, This is for a '13 still

Code:
void can_decode_22b_ids(CANRxMsg_t *canMsg)
{

  switch(canMsg->id)
        {
        case 0x070:
            mDC_yaw = (float)(canMsg->data8[0]    + canMsg->data8[1]*256)*(float)0.005-(float)163.84;
            mDC_yaccel = (float)(canMsg->data8[4]    + canMsg->data8[5]*256)*(float)0.00012742 - (float)4.1768;
            break;
        case 0x410:
            mDC_transTorque = (float)canMsg->data8[1]*(float)1.6;
            mDC_engTorque = (float)canMsg->data8[2]*(float)1.6;     //USED
            mDC_lossTorque = (float)canMsg->data8[3]*(float)1.6;
            mDC_accel = (float)canMsg->data8[4]*100/255;     //USED
            mDC_engineSpeed = canMsg->data8[5]    + canMsg->data8[6]*256 ;     //USED
            break;
        case 0x411:
            mDC_gear = canMsg->data8[4];     //USED
            mDC_cruise = canMsg->data8[5];
            mDC_bMIL = canMsg->data8[7]&0x01;     //USED
            mDC_SImode = ((canMsg->data8[7]&0x18)>>3)*0x03;     //USED
            break;
        case 0x501:
            mDC_ABS_MReduction = (float)canMsg->data8[2]*(float)1.6;
            mDC_ABS_MAllowed = (float)canMsg->data8[3]*(float)1.6;
            mDC_bBABS = (canMsg->data8[4]>>2)&0x01;
            mDC_bBABSReduce = (canMsg->data8[4]>>0)&0x01;
             break;
        case 0x511:
            mDC_steerAngle = (int16_t)(canMsg->data8[0]    + canMsg->data8[1]*256);     //USED
            mDC_Msteering = (int16_t)(canMsg->data8[2]    + canMsg->data8[3]*256);     //USED
            mDC_brakePercent = canMsg->data8[4]*100/255;     //USED
            break;
        case 0x512:
            mDC_vCar = (float)(canMsg->data8[2]    + canMsg->data8[3]*256)*(float)0.05625;     //USED
            mDC_bVDC = (canMsg->data8[0]>>4)&0x01;
            mDC_bBrake = (canMsg->data8[4]>>4)&0x01;     //USED
            mDC_FaultCode = (uint16_t)(canMsg->data16[3]);
            break;
        case 0x513:
            mDC_vCarFL = (float)(canMsg->data8[0]    + canMsg->data8[1]*256)*(float)0.05625f;     //USED
            mDC_vCarFR = (float)(canMsg->data8[2]    + canMsg->data8[3]*256)*(float)0.05625f;     //USED
            mDC_vCarRL = (float)(canMsg->data8[4]    + canMsg->data8[5]*256)*(float)0.05625f;     //USED
            mDC_vCarRR = (float)(canMsg->data8[6]    + canMsg->data8[7]*256)*(float)0.05625f;     //USED
            break;
        case 0x514:
            mDC_bReverse = (canMsg->data8[0]>>2)&0x01;
            mDC_tAmbient = (float)canMsg->data8[2]/2-40;     //USED
            mDC_bWiper = (canMsg->data8[3]>>6)&0x01;
            mDC_bLightHigh = (canMsg->data8[3]>>3)&0x01;
            mDC_bLightLow = (canMsg->data8[3]>>2)&0x01;
            mDC_bLightSwitch = (canMsg->data8[3]>>1)&0x01;
            mDC_bDefogger = (canMsg->data8[3]>>0)&0x01;
            mDC_rFuelLevel = (canMsg->data8[4]>>6)*0x03    + canMsg->data8[5]*4 ;
            mDC_bParkingBrake = (canMsg->data8[7]>>7)&0x01;
            break;
        case 0x600:
            mDC_rFuelFlow =  canMsg->data8[1]    + canMsg->data8[2]*256 ;     //USED
            mDC_tWater =  canMsg->data8[3]-40;     //USED
            mDC_bClutch = (canMsg->data8[6]>>2)&0x01;     //USED
            break;
        default:
        //No Message Passed
    break;
    }
}


View user's profile Send private message
Reply with quote
Post  
I finally have some time to work on this, and my results so far have been unsatisfactory.

Ignoring Lua scripting for now (failure after failure to even get a response from the ECU), I looked into the available documentation the Subaru Select Monitor protocol uses an ISO9141 interface which I thought was supported by the Legacy OBD-II cable. After trying all available options in the OBD-II channel page no response is ever seen in RaceCapture.

I would be interested to know if there is some way I can test the Legacy OBD-II cable -but I don't have any cars that are old enough to use it except the one that has produced nothing but failures.

View user's profile Send private message
Reply with quote
Post  
Nice that you have an external box to decode the subaru data and broadcast it over CAN; that's a perfect application of the technology!

If you're broadcasting the data in a straightforward manner, then you should be able to use the newer direct CAN mapping instead of Lua it runs at native speed and has an easy to use mapping interface:
https://wiki.autosportlabs.com/CAN_Bus_Integration#Direct_CAN_mapping


_________________
Brent Picasso
Founder, Autosport Labs
Facebook | Twitter
View user's profile Send private message Send e-mail
Display posts from previous:
Reply to topic Page 1 of 1
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum