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.
Subaru SSM protocol over OBDII
-
- Posts: 9
- Joined: Fri Nov 04, 2016 12:12 am
- Location: San Jose, CA
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
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
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'.
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: Select all
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);
}
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!
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.
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).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.
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.
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: Select all
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;
}
}
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.
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.
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_ ... AN_mapping
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_ ... AN_mapping