Nov 16

Next to the priority of the messages, also some though should go into the library that implements the protocol.

Sending a single frame will require about 110 bits on the CAN bus. Using a 500kbps speed this will take 220us limiting the total amount of frames to 4500 frames per second. Question to answer is if it is necessary to buffer multiple outgoing commands or is it enough to buffer one command and report back to the application it has been send before another command can be send. Based on the 4500 frames per second and assuming that an average command will require 3 frames (2 for the command, 1 for receiving the acknowledgement) it means transferring the command will take a bit less than 1ms.

But what if other higher priority devices are on the bus transferring data? What is they decide to transfer larger amounts of data? If the send command function would only return when it has completed this would be a problem, however the transfer is already interrupt based. So the send command function can return directly allowing the application to continue. Before a new command can be send a verify must be done if the previous was already send. If not, than there are again two options: than wait in the send command or return with an error code. From an application point of view, most cases you want to wait before continuing. Also in most cases the command will result in data being send back that than must be processed. But the difficulty lies within the most.

Best approach here is to pass an additional parameter to the send command that indicates when to return: directly or when the acknowledgement has been received. If the previous command has not been send, than it overrules the parameter and wait until the previous command has been send. In both cases a time out must be implemented on the maximum time allowed to wait before the previous has been send and a timeout must be implemented how long it can wait for a response. Next to a level of retrying of course.

The send command will return a status like OK, timeout, bus error and so on. Applications can than make the send command part of an if structure that is only execute when the send command was successful. If the option is selected so it return without waiting for the acknowledge, than it will return also with the OK status (if indeed it was executed OK). After this other actions can take place, if a t a certain time the application wants to check if the data actually has been send the global status field can be tested to see if it already has been send or that the acknowledge has been received.

In this assumption there is one part missing, when a command is received from another device it must be acknowledged by sending dummy data or the actual data that was requested. Since the process of receiving data is interrupt based the moment in time that data must be send is not defined. It can be just at the moment that the application also want to send a command. Or even worse, the command received might require some measurements that some time before a response can be send. Since the application is not processing incoming commands at that time there sure will be a timeout on the sender side which will “think” the transmission failed and it will retry.

Hmmm. This means any incoming command must be acknowledged for received, not for processed. When the application finally has time to process incoming requests than it send out the formal response (if needed). The problem of acknowledging data on time might also be encountered when a higher priority device decides to start communicating. It might be that these two items already use one of the reserved bits: the acknowledgement bit. By using this bit acknowledge frames will have a higher priority over the bus than command frames. Since the acknowledgement frame is only 1 frame long (potentially no data at all) this does not have a big impact on transferring larger commands but it prevent retries.

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

  • b28:          0=interrupt packet, 1=normal packet
  • b27:          0=acknowledgement packet, 1=command packet
  • b26..b24:  Reserved, should be 0b011 by default
  • b23..b17:  Address of receiver, 0×7F is lowest priority, 0×00 is highest priority device
  • b16..b10:  Address of sender, 0×7F is lowest priority, 0×00 is highest priority device
  • b9..b5:      Packet number, 0×00 is packet 1, 0×1F is last possible packet 32
  • b4..b0:      Total number of packets, 0×00 is 1 packet, 0×1F is maximum amount of 32 packages

The function that will handle incoming frames will than also be responsible for sending the acknowledge frame when a full command is received. After this, the command can be placed in a buffer and a flag can be set in the overall status that a new command has been received. This buffer needs to be able to hold several commands, it must also be able to handle several incoming commands at the same time. For example, when a command exists out of 6 frames it can be that after receiving frame 3 a new command is received from a higher priority device. Than in theory it is possible than the lower priority sender does not get an acknowledge and retries making the partially received command obsolete.

A single command can exists of 32 frames. This would require housekeeping if all frames have been received before a command is acknowledged. The sender can make sure that all frames are send in the right order, so 1 out of 3, 2 out of 3 and finally 3 out of 3. When the last one is received, the receiver can store it in the incoming command buffer and send an acknowledge frame to the sender. If reception is interrupted by a higher priority device and a timeout on the sender is triggered to resend the command, the receiver will suddenly receive 1 out of 3 again. At that moment, all previously received data from that sender can be ignored and deleted.

While processing an incoming frame the MOB is disabled, since it might take some time to process the MOB there must be more MOB’s monitoring the bus for incoming frames. This again presents a problem since this can mean that frame 3 out of 3 is processed before 2 out of 3 since the first one can be received in a lower number MOB and as a result is processed earlier if two frames have arrived before the processing starts. The solution for this problem can be a 32 bit wide variable in which each bit indicates if a frame has arrived. Only when all bits are 1 that should be 1 for matching the total number of frames than the command can be acknowledged.

The buffer that holds the incoming commands can be a simple list of “x” commands each claiming 255 bytes of possible data. In an embedded system were RAM is limited this should not be done, also the chance that all commands actually have 255 bytes of data is very limited. Instead, a linear FIFO buffer can be used that holds all received commands in a circular buffer. The receive function must claim the number of bytes in the buffer when the first frame of a new command is received. The amount of bytes is a sum of:

  • 4 bytes for storing the bit pattern to detect if all frames are received
  • 1 byte for the address of the sender
  • 1 byte for the command
  • 1 byte for storing the amount of data bytes
  • n bytes for storing the data

The circular buffer holds two pointers, one is pointing to the first free memory location and used for receiving commands and one is pointing to the first received command and used for reading. Since multiple commands can be received in parallel a function will be needed to claim memory (and so advance the incoming pointer) and return the original buffer location. When memory was claimed but the frame was canceled than it should be made invalid so that when data is read from the buffer this frame is skipped.

In order to read data, the first thing to do is to see if all frames are received. This can be done by checking if the number of frames to be received are reported as 1 in the first 4 bytes. However, an easier way is to check if all 4 bytes are 0xFF. If not, all frames are not received yet. That leaves the problem of how to detect if the received command has been aborted and so should be ignored and the memory released. This could be done by clearing all 4 bytes, this pattern is never used since the moment the first frame of a new command comes in one of the 32 bits (in most cases the first) will be set to one directly when the memory is allocated on the buffer.

Sending the acknowledgement frame can be done using a seperate MOB, since the acknowledgement frames have a higher priority than command frames there is no need for a second MOB.

The function that sends commands can indeed send frame by frame until all data is send. Than a timer needs to be started after which it can wait for an acknowledgement frame to be received. There is a timer available in the CAN controller, this can be used here since only one command is send at the time. When the acknowledgement frame arrives the senders address can be compared with the original to address. If they match, success can be reported. When the timer expires the whole command must be resend. It is possible here that just when the timer expires and the resend start the acknowledgment frame comes in. In that case it must be ignored. If after x (3?) retries the command still is not acknowledged than it is time to stop the transfer and report an error. If at that time a new command is send to another device to report a non-responsive device it is in theory possible that just at that moment (before or during sending of the new command) the acknowledgement still comes in. Since it is too late, it should be ignored as well. So there is only a specific time window that acknowledgement frames are used and at that moment they whould match the last used to address. 

Above results in:

  • 1 MOB for sending commands only to make sure frames are send in the right order
  • 1 MOB for receiving acknowledgements, only one needed since it will wait with sending the next command until this command is acknowledged
  • x MOB’s for receiving incomming commands. The number depends a bit on how much code is required for storing the incoming data compared with the time needed for receiving a new frame.
  • 1 MOB for sending acknowledgements

Time to stop now and think about it for some hours before implementation starts.

Leave a Comment

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