SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By paimon.soror
#131643
Hey guys, I was hoping there was someone on here that could help me out with some extended can messaging? I am currently using the following library for my CANBUS Shield

https://github.com/franksmicro/Arduino/ ... es/MCP2515

Which has proven to be amazing, however, I am having some trouble with extended CAN messaging. I found that on my car, there is the tire pressure monitor module which is at

ECU: 0x751
Address: 0xC901
Mask: 0x00FF

So with my test application, I am setting the following:
Code: Select all
    message.adrsValue = 0x751;
    message.isExtendedAdrs = true;
    message.extendedAdrsValue = 0xC901;
    message.rtr = false;
    message.dataLength = 8;
    for(int i = 0; i < 8; i++) {
      message.data[i] = 0x00;
    }
I then have my software listen for the push of the joystick, and when pressed, it will transmit this message and listen on the bus, in a loop while the button is held down. I am not sure if my syntax above is correct? Here is a snippet of the library where the developer is setting the can message to transmit:
Code: Select all
boolean MCP2515::transmitCANMessage(CANMSG msg, unsigned long timeout)
{
  unsigned long startTime, endTime;
  boolean sentMessage;
  unsigned short val;
  int i;
 
  startTime = millis();
  endTime = startTime + timeout;
  sentMessage = false;

  val = msg.adrsValue >> 3;
  writeReg(TXB0SIDH,val);
  val = msg.adrsValue << 5;
  if(msg.isExtendedAdrs)
    val |= 1 << EXIDE;
  writeReg(TXB0SIDL,val);
  if(msg.isExtendedAdrs)
  {
    val = msg.extendedAdrsValue >> 8;
    writeReg(TXB0EID8,val);
    val = msg.extendedAdrsValue;
    writeReg(TXB0EID0,val);
  }
  
  val = msg.dataLength & 0x0f;
  if(msg.rtr)
    bitWrite(val,TXRTR,1);
  writeReg(TXB0DLC,val);
  
  //Message bytes
  digitalWrite(SLAVESELECT,LOW);
  SPI.transfer(WRITE); 
  SPI.transfer(TXB0D0);
  for(i = 0; i < msg.dataLength; i++)
    SPI.transfer(msg.data[i]);
  digitalWrite(SLAVESELECT,HIGH);

  //Transmit the message
  writeRegBit(TXB0CTRL,TXREQ,1);

  sentMessage = false;
  while(millis() < endTime)
  {
    val = readReg(CANINTF);
    if(bitRead(val,TX0IF) == 1)
    {
      sentMessage = true;
      break;
    }
  }

  //Abort the send if failed
  writeRegBit(TXB0CTRL,TXREQ,0);
  
  //And clear write interrupt
  writeRegBit(CANINTF,TX0IF,0);

  return sentMessage;

}
I would be beyond grateful if someone could help me out. Greatful to the point of a donation if it has to come to that lol.
By monstrum
#131759
Maybe I'm missing something but after reading your post twice I still can't figure out what the problem is.
By paimon.soror
#131807
Bah sorry not sure why I kinda stopped mid thought. I was wondering if anyone actually got extended messaging to work and or if the library I am using correctly transmits the extended messages.
By benstabler
#131833
I know that the MCP2515 can transmit extended frames. It looks like the code you're using doesn't really handle the address in an intuitive way.

First off- you have an ECU address of 0x751 and a sensor address of 0xC901- which of these addresses are you trying to populate the CAN message with? Presumably the 0x751? A CAN message can only have one address- if the address is extended it's 29 bits long, otherwise its 11 bits long.

Try the following code for your transmit method:
Code: Select all
boolean MCP2515::transmitCANMessage(CANMSG msg, unsigned long timeout)
{
  unsigned long startTime, endTime;
  boolean sentMessage;
  unsigned short val;
  int i;

  startTime = millis();
  endTime = startTime + timeout;
  sentMessage = false;

  if(msg.isExtendedAdrs)
  {
    val = msg.extendedAdrsValue >> 21;
    writeReg(TXB0SIDH,val);
    val = ((msg.extendedAdrsValue >> 13) & 0xE0);
    val |= 1 << EXIDE;
    val |= ((msg.extendedAdrsValue >> 16) & 0x03);
    writeReg(TXB0SIDL,val);
    val = msg.extendedAdrsValue >> 8;
    writeReg(TXB0EID8,val);
    val = msg.extendedAdrsValue;
    writeReg(TXB0EID0,val);
  }
  else
  {
    val = msg.adrsValue >> 3;
    writeReg(TXB0SIDH,val);
    val = msg.adrsValue << 5;
    writeReg(TXB0SIDL,val);
  }
  
  val = msg.dataLength & 0x0f;
  if(msg.rtr)
    bitWrite(val,TXRTR,1);
  writeReg(TXB0DLC,val);
  
  //Message bytes
  digitalWrite(SLAVESELECT,LOW);
  SPI.transfer(WRITE); 
  SPI.transfer(TXB0D0);
  for(i = 0; i < msg.dataLength; i++)
    SPI.transfer(msg.data[i]);
  digitalWrite(SLAVESELECT,HIGH);

  //Transmit the message
  writeRegBit(TXB0CTRL,TXREQ,1);

  sentMessage = false;
  while(millis() < endTime)
  {
    val = readReg(CANINTF);
    if(bitRead(val,TX0IF) == 1)
    {
      sentMessage = true;
      break;
    }
  }

  //Abort the send if failed
  writeRegBit(TXB0CTRL,TXREQ,0);
  
  //And clear write interrupt
  writeRegBit(CANINTF,TX0IF,0);

  return sentMessage;

}
Then, in your test application, just use one of the address fields (extendedAdrsValue if it's an extended message, adrsValue otherwise)

Ben
By paimon.soror
#131835
benstabler wrote:I know that the MCP2515 can transmit extended frames. It looks like the code you're using doesn't really handle the address in an intuitive way.

First off- you have an ECU address of 0x751 and a sensor address of 0xC901- which of these addresses are you trying to populate the CAN message with? Presumably the 0x751? A CAN message can only have one address- if the address is extended it's 29 bits long, otherwise its 11 bits long.

Try the following code for your transmit method:
...

Then, in your test application, just use one of the address fields (extendedAdrsValue if it's an extended message, adrsValue otherwise)

Ben
I am beyond grateful that you took the time to type this up for me, and I will implement and test it when I get home from work.

As far as your question goes, I essentially want to see what data is currently in 0xC901

For example, my current application is reading generic information like Engine RPM, and I am able to obtain that value by sending the following message across the bus:
Code: Select all
    message.adrsValue = 0x7DF;
    message.isExtendedAdrs = false;
    message.rtr = false;
    message.dataLength = 8;
    message.data[0] = 0x02;
    message.data[1] = 0x01;	
    message.data[2] = pid;	
    for(int i = 3; i <= 7; i++)	
      message.data[i] = 0x00;
Where I then am able to obtain the response message on the bus (this is essentially all done via his queryOBD call. I actually changed his call a bit because I wanted to worry about the message parsing myself, so I just return the message object back to my code instead of doing the parsing that he does at the end of queryOBD)

I don't intend on writing data to the 0xC901 sensor, just reading (as the sensor will give me the current pressures on each tire)

Hope that helps.
By benstabler
#131838
Hi,

In that case, your original code will probably work (you're sending a message to address 0x751 which is a standard identifier, so you don't need my changes for sending to an extended address). You do, however, need to implement extended addresses in the receive code if you expect to receive a message back addressed 0xC901.

That said, I haven't seen extended identifiers implemented in OBD before... I was under the impression that you transmitted on an address like 0x751, the response came back on a similar address (perhaps 0x759) and one of the bytes indicated the sensor id.

Which ECU are you using? It doesn't look anything like traditional ECU format.
By paimon.soror
#131840
benstabler wrote:Hi,

In that case, your original code will probably work (you're sending a message to address 0x751 which is a standard identifier, so you don't need my changes for sending to an extended address). You do, however, need to implement extended addresses in the receive code if you expect to receive a message back addressed 0xC901.
Ok that makes sense. Does his receive code not properly do the extended addressing? At first glance I see a lot of stuff being done, shifts and whatnot, and the isExtendedAdrs flag being checked
That said, I haven't seen extended identifiers implemented in OBD before... I was under the impression that you transmitted on an address like 0x751, the response came back on a similar address (perhaps 0x759) and one of the bytes indicated the sensor id.
I was thinking that the message would come back at a different address as well, as the standard CAN messages sent to 0x7DF respond on 0x7F8. But when I transmit to 0x751 per the example in my first post, I dont see any messages printed that look like they could be responses. Basically my code will send and sniff, and here is a screenshot of what my typical messages look like on that bus:

Image

where the address 0x650 is the cruise control module's power status and 0x4B0 is the address of the ABS ecu that tells the wheel speeds, etc.
Which ECU are you using? It doesn't look anything like traditional ECU format.
This is from a 2010 Mazda RX8
By paimon.soror
#131980
So I took your advice and tried just sending a message to 0x751. The great thing is that I see a message printed on the bus @ 0x759 which seems to follow the CANBUS standard, but I am not too sure exactly what it means.

Here is the message i sent:
Code: Select all
message.adrsValue = 0x751;
    message.isExtendedAdrs = false;
   // message.extendedAdrsValue = 0x751C901;
    message.rtr = false;
    message.dataLength = 8;
    for(int i = 0; i < 8; i++) {
      message.data[i] = 0x00;
    }
and here is the response I got:

0x759 09 7F 00 11 00 00 00 00
By benstabler
#132034
Can you try sending:

0x751 01 0C 00 00 00 00 00 00

If your ecu follows spec, that should request engine rpm- you should get something back like

0x759 41 0C ?? ?? 00 00 00 00
By paimon.soror
#132044
benstabler wrote:Can you try sending:

0x751 01 0C 00 00 00 00 00 00

If your ecu follows spec, that should request engine rpm- you should get something back like

0x759 41 0C ?? ?? 00 00 00 00
I can try but I dont think that would work, 0x7DF is my main ECU address, and thats actually how I currently read RPM by sending

0x7DF 01 0c 00 00 00 00 00 00
By benstabler
#132102
Oh- I see, and you want the pressure monitor device which is at 751. What about sending packets of the format 0x751 01 ?? 00 00 00 00 00 00 until you get a response that looks correct? It seems the response you're currently getting is an error of some kind (7F)- perhaps the pressure monitor is canbus compliant and you just need to find the right parameter for pressures.
By paimon.soror
#132175
Thanks for the tips, I will toy around a bit and see what I can get with different id's on x751. Btw not sure if this helps any, but here is some more information that i managed to uncover:
Code: Select all
Name: Tire pressure - wheel unit No. 1
ParamType:	  Read	 
Mask: 0x00FF	   
Shift: 24
Address: 0xC901	      
ParamAddr: 51457	
ConverterName: CV_PRESSURE_1373_1000