PROTOCOL VERSION INFO:
|06/29/2004||ADG: added error command, although it hasn't been implemented yet, implemented Ian's comments.|
|03/17/2004||ADG: moved from OSS TWiki to PSAS TWiki for safekeeping|
|11/25/2003||ADG: updated to implemented CANtalope behavior; 0xFFEF -> 0xFFFF 16bit message header.|
|09/02/2003||ADG: updated this protocol to reflect Larry's or Markus' (sorry, I forgot whose brilliant ideas this was) protocol that involves no headers, just an occasional "ping" packet for checking the synchronization.|
|07/?/2003||ADG: Updated the protocol spec with real numbers.|
The serial port uses 10 bits (1 start bit + 8 data bits + 1 stop bit) per character, implying a maximum throughput of 11.52kBps at 115.2kbps.
Running at CAN's maximum rate of 1Mbps, the obvious conclusion is that the CAN bus bitrate will swamp the serial port. Let's just see how hosed we really are (See CanBusUtilization for CAN bus bandwidth data used below):
If the CAN messages have no data, at 1Mbps you can get up to ~22,000 messages per second (mps). Each message requires at least two bytes over the UART (the 16 bits of the header: 11 bits ID, 1 bit RTR and 4 bits length) Which means the full 22 kmps over CAN requires 352 kbps (44k Bps) over serial - 3 times faster than the maximum supported speed of 115.2 kbps (11.5 kBps) on most UARTs.
Now if all of the CAN messages had the full 8 bytes of data, we can only get ~8 kmps over the CAN bus, but it's overall worse because we have more data per message which requires 640 kbps (80 kBps) over the serial port, an overrun of 5.6 compared to the 115.2 kbps UART. So we're hosed using the serial port either way - if the packs have no data, or if they have full data.
But: Who cares! And a factor of 3 or 5.5 too slow isn't too bad... is it? Especially since we don't want the added complication of USB to CAN interfaces (and no, a serial to USB adapter doesn't help because the PIC probably can't match the bps rate closely enough).
115.2 kbps (11.52 kBps) over serial translates into the ability to ship 5.76 kmps if there is no data in the packets, and 1.15 kmps if the CAN messages are packed with data. That's terrible, but it's not useless... most CAN applications which use the CAN bus as a control bus (i.e., control messages as opposed to a data bus which pipes large amounts of data) won't get near that kind of utilization. And what's more, you can configure the CAN message filters on your little microcontroller to ignore the high-frequency, data-heavy messages and never send them across the serial line. Furthermore, those poor slobs running the CAN bus at the standard automotive/industrial rate of 125kbps will easily be able to get every single one of their pathetically slow messages.
So there you go. Not so great - but useable - for high speeds control messages, and perfect for low speed CAN busses.
Need something very, very simple for CAN messages. How about this? Thanks to Markus (was it you, Markus?), who simplified the protocol a ton:
- Serial Byte 01: CAN Message ID High Byte: The top 8 bits of the CAN message ID
- Serial Byte 02: CAN Message ID Low Byte and more: The bottom 3bits of the CAN message ID, the RTR bit, and the 4bits of the DLC.
There's your minimum packet - a CAN message which has no data. Then you simply add data bytes according to the DLC of the minimum header (above), which gives you a maximum serial packet of:
- Serial Byte 01: CAN Message ID High Byte
- Serial Byte 02: CAN Message ID Low Byte and more
- Serial Byte 03: Data 1
- Serial Byte 04: Data 2
- Serial Byte 05: Data 3
- Serial Byte 06: Data 4
- Serial Byte 07: Data 5
- Serial Byte 08: Data 6
- Serial Byte 09: Data 7
- Serial Byte 10: Data 8
We use the DLC to caculate at what point a new serial packet should be coming. This means processing a multi-sized packet on the fly, which isn't difficult but is prone to errors. That's why we'll have a watchdog process going on at the same time: once every nth of a second, the PC and serial converter will exchange a "hi" packet. If neither get the packet, then we know we've lost sync. We then reset both sides and try to start over. Not exactly robust, but it'll work "most of the time" and we're not looking for a safety critical system here... just a lowly bus monitor.
Occasionally something will go wrong, and we'll want to hear about it. Like the CAN message FIFO on the PIC overflowed. Or maybe we want to set a new bit rate on the CANtalope PIC node. Or we'll want to do something random. So we need a "CANtalope only" control message. Well, how about this?
If: (1) the message ID is 0x7FF (which is fowned on as a CAN message ID for some reason) AND (2) the DLC = 0b1111 (which is invalid in CAN land - we can only have 0b1000 max) AND (3) the RTR bit is set THEN we say that the next byte coming is a "CANtalope command" byte (which may have more (predetermined) bytes after it. Here's an example:
- Serial Byte 1: CAN Message ID High Byte: 0xFF
- Serial Byte 2: CAN Message ID Low Byte and more: 0xFF
- Serial Byte 3: CANtalope Command Byte
... where the CANtalope command byte indicates what kind of command/report this is, and implies how many bits follow. Like, go to observe only mode (don't acknowledge messages). Or reset yourself. Or pull the RB3 pin low and kill the CAN bus by asserting a dominant bit forever. Or something.
Here are the currently implemented commands:
|0x00||Ping: CANtalope will fire this message right back if the serial ports are working correctly. E.g., 0xFF 0xFF 0x00 (in CANtalope format,
|0x01||Error: Sends one additional byte, which is the error encountered (cantalope_error_t) as specified in cantalope_exports.h in cvs. E.g., 0xFF 0xFF 0x01 <error_num>|
See HTML comment below this line for future functionality we haven't implemented yet.