Nov 16

On top of the basic CAN interface I will add a communication layer that allows devices to send each other commands. I will call this communication layer RoboCAN and will use it in all my robots (at least that is my intention while writing this).

The amount of data that is part of the command should not be limited to the standard 8 data bytes that can be stored in a single CAN frame. Next to this there is a set of basic commands that each device must support, from example GetStatus. In most cases the sender want to be sure the command has been received so any command send must be acknowledged by the receiver. This acknowledgement is only required when a command is received for sending data. When a command is received for receiving data the acknowledgement is the response itself. This response does not have to be acknowledged by the original sender, if this sender did not get the response it will repeat the original request again.

In order to support sending a command to a device it will be necessary to give each device an unique identifier. A device only needs to respond to commands send to it, not to commands send to other devices. The unique ID can be stored in the priority field of the frame. The benefit of this is that the priority filtering mechanism can be used which reduces the software overhead of the device application. A second benefit is that this automatically provides a priority mechanism between the devices. On a busy bus, messages send to a device with a lower identifier value will have higher priority and other data will (temporarily) be put on hold.

Big question to solve it how to handle the transport of data block larger than 8 data bytes? In principle this can be solved by storing in the data fields something like frame x out of y frames. This presents some problems. For one, next to the command it will consume 3 out of the 8 bytes available, so a relative large overhead. Next to this, if the application send two commands directly after each other, how will the receiving device know which frame is part of which command? If an error occurs during transmission of a frame it will be resend, but at that moment another message can have higher priority, the sending order does not have to match the receiving order (like in HTTP). This would require a “command ID”, so consuming in total 4 bytes out of the 8. We can reduce this overhead by limiting the maximum to 16 frames, so x out of y frames can be packed in a single byte. The same can not be done for the command, I guess complex devices will have more than 16 commands. For the command ID it can be done but there is no other byte available to combine it with.

The priority field of a frame is 11 or 29 bits (CAN rev A or B). Using the 11 bits this would mean 2048 devices on the bus. I guess this is a bit much, perhaps we can use a range of priorities per device. For example, limiting the number of devices on the bus to 127 (7 bits) gives us 4 bits per device, so 16 “addresses” per device. Next, in the driver an implementation can be made that commands are queued, a new command can be send before the previous has been finished but is placed on hold in the driver until the previous command is fully handled. The 16 addresses can not be used for commands since 16 commands is not enough. For sending multiple frames for data this might be different.

The CAN controller itself provides an additional priority structure. When one or more MOB’s are enabled and the bus is free the CAN controller will first check if MOB0 is enabled. If not, than MOB1 and so on. So, if a command needs 3 frames for sending it’s data it can be placed in MOB0, 1 and 2. Only when MOB0 has been successfully transferred MOB1 will be send. However, this does not guarantee that the frame send by MOB0 has been received by the device. It is possible that the CAN controller was disable for a while on the receiving device, as a result it receives the frame send by MOB1 and MOB2 only (in that order). MOB0 frame is gone forever.

This does however provide a benefit, the order of frames can be controlled making the x in x out of y obsolete. The receiving device will receive part 2 out of 3 first, it thinks this is part 1 out of 3, since the other 2 parts have not been received yet it does not send an acknowledgement. Than comes part 3 out of 3, this is received as part 2 out of 3. Again no acknowledgement which triggers a timeout on the sender. The sender will than resend the whole message and than it goes wrong because part 1 out of 3 is received as part 3 out of 3…. Hmmm, this would require again the command ID allowing the device to see a new command is being send and so ignore all previous data.

While thinking about this, another problem is that when two devices start sending a command to the same device. Depending processing speed and the content of the data fields it can result than frame 1 is received from device 1 and frame 2 from device 2, theoretically using the same command ID. There is no way to differentiate between to senders, so the senders address must be part of the message somewhere. This also allows the receiver to send back the acknowledgement to the sender.

The problem of two senders in parallel can only be solved if each frame contains the sender of the frame. In total that means every frame should have:

  • The destination address
  • The senders address
  • Packet number
  • Total number of packets

This can also be done using a 29 bits long priority identifier in stead of the 11 bits. Above order can than also be used as priority information: A device with a higher priority gets data faster than with a lower priority. If two devices want to send data to it, the sender with a higher priority wins and the first packet is send before the last packet. Since the number of packets is always the same this has no impact.

Having more than 128 devices on the bus is not likely, so 14 bits will be required for the two address fields. This leaves 15 bits for the packet fields, also here 2 times 7 bits should be enough. As a result, 1 bit is free for which no function is defined yet. It might be a good idea to make this the most significant bit so it can be used later for even higher priority messages like alarm status or “interrupts”.

Since all required data for package transfer is now included in the priority field, all 8 data bytes are available for data. Except the command of course, so this is the first byte of the first frame. Also the total number of bytes that are included in the command (different than the number of packages) needs to be included, this will be the second byte of the first frame. As a result, there are 256 possible commands that each can include 255 bytes of data. Small calculation, since there are 7 bits to indicate the number of packages so a maximum of 127 packages. In total this allows us to send (127*8)-2=1014 bytes of data which is more than the 255 bytes previously mentioned.

If the limit would remain 255 bytes, the maximum amount of frames would be (255+2)/8=32.125 so 33. This would require 6 bits for storing the amount of packages instead of the previously indicated 7. This leaves 3 bits reserved for future use. Since the amount of packages will always be 1 (or more) the bit pattern 0b000000 can be used as well to indicate packet 1. When using 6 bits for the amount of packages this means we can send 32 packages, so (32*8)-2=254 bytes of data. The maximum was 255 (the value 0 is a valid number as well), so one bytes less might be a good compromise to save another 2 priority bits bring the total number of reserved bits to 5.

This brings up an interresting debate, if we limit the amount of devices to 6 bits so to 64 than we have 7 bits that can be used for storing the command and as such increase the maximum number of data bytes to 255. The advantage is that we can include the command in the priority, the dis-advantage is there is no reserved bits anymore. Is the command in priority higher than a sender? The sender can control this by itself, so the command should than be placed between “to address” and sender address making it possible for a lower priority device to interrupt a higher priority device with a higher priority command. Confused?

The only reason to do this is so (indeed) interrupt somebody. For this 1 bit should be enough. Secondly, each device must support a basic set of commands which than should remain constant in time, but the true priority can only be set during design time and can vary over projects. So this is not a smart thing to do. So the conclusion is we remain using 7 bits for the device addresses and using the first byte in the first packet as the command.

The interrupt feature is an interesting one, it is not a real time interrupt, but it will be beneficial to use the highest bit for this. If two high priority devices decide to exchange larger amount of data this can result in many frames before a lower priority device can actually report it is in panic mode… If used sparingly this adds value. Also here the interrupt of a higher priority device wins over an interrupt of a lower priority device, all very logic.

As a result, the 29 bits of the priority field are used as indicated below:

  • b28:          0=interrupt packet, 1=normal packet
  • b27..b24:  Reserved, should be 0b0011 by default
  • b23..b17:  Address of receiver, 0x7F is lowest priority, 0x00 is highest priority device
  • b16..b10:  Address of sender, 0x7F is lowest priority, 0x00 is highest priority device
  • b9..b5:      Packet number, 0x00 is packet 1, 0x1F is last possible packet 32
  • b4..b0:      Total number of packets, 0x00 is 1 packet, 0x1F is maximum amount of 32 packages

The reason for the 0b0011 pattern on the reserved bits is that this allows future expansions using a higher and a lower priority.

I will write a library that implements above to get some experience with this structure.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.