Electronic – How to determine the length of the last data field in a SDO block transfer

cancanopenprotocol

I've got a problem with the implementation of the CANopen SDO Block Transfer. The transmission is ok except the last block:

...
TX:  "     618   [8]  5B 65 73 74 0A 44 69 65"
TX:  "     618   [8]  5C 73 20 69 73 74 20 65"
TX:  "     618   [8]  5D 69 6E 20 54 65 73 74"
TX:  "     618   [8]  DE 0A 00 00 00 00 00 00" //last block (5E | 80 = DE)
RX:  "     598   [8]  A2 5E 00 00 00 00 00 00" //ACK from Server: last block 5E

The data is a file which only contains Dies ist ein Test\n (engl: This is a test\n) several times. So the last byte that contains data is the 0A of the last block but an SDO has to be always 8-Byte, so the rest is filled up with zeros.

On a SDO Block the first Byte counts the actual Block (max 7fh=127d). The MSB of the first Byte marks the end of a Block Download.

In this example the SDO-Block sequence no is 5E and it is the last block so the MSB has to be marked as 5E OR 80 = DE. But the last block has to mark the size of non data bytes, see [1].

So I didn't find any documentation which describes how the first byte has to look on the last sequence in block mode. In a 'normal' SDO the 2nd and 3rd bit masks the data. A good explanation can be found in [2].

My Question is:
Please, can someone explain how this first byte on the last sequence has to look like? Which bits must be set in this example?

  • [1] CIA 301, Chap 7.2.4.2.11 Service SDO block download end
  • [2] byteme, chap. Expedited Read Dictionary Object

Best Answer

TL;DR: The bits aren't set in the last segment of a sub-block. They are set in a separate message that follows the last sub-block.


Unfortunately, the answer is a little bit more complicated. CiA 301 defines a SDO block download in three phases, see 7.2.4.3.8:

  1. SDO block download initiation (7.2.4.3.9)
  2. SDO block download sub-block (7.2.4.3.10)
  3. SDO block download end (7.2.4.3.11)

As per 7.2.4.3.10, a block download ends when the MSB of the frame is set to 1 (called c in the documentation). That's where you apply 0x80. Your log and logic seems to follow the specification so far.

However, there are no bits to set for the length. At least not in that frame. Instead, the server's acknowledgement must be followed by another frame that contains the following data:

(1) (2) X C | CRC               | Reserved
110 NNN 0 1 | CCCCCCCC CCCCCCCC | 00000000 00000000 00000000 00000000 00000000
0             1        2          3        4        5        6        7        (Byte)

Here, (1) is the client command specifier and should be 6, due to the block download. C is the client subcommand and should be 1 (otherwise you would initiate another block download). X is not used and should be 0.

The important bits are now NNN, which indicate the number of bytes that didn't contain any data in the last segment of the last block. As your last block only contained a single byte, NNN should be 110 (bytes [8-6,7]=[2,7] didn't contain valid data).

So in your notation, the end of the block transfer should look like this:

TX:  "     618   [8]  DE 0A 00 00 00 00 00 00" // your last message
RX:  "     598   [8]  A2 5E 00 00 00 00 00 00" // Server ACK of block transfer
TX:  "     618   [8]  DD ?? ?? 00 00 00 00 00" // Block End, 0xdd = 0xc1 + (n << 2)
RX:  "     598   [8]  A1 00 00 00 00 00 00 00" // Server ACK of block end

?? indicate CRC bytes that depend on the transfer. Apparently, both sides of your CANopen implementation did not conform to the protocl as defined in 7.2.4.3.8 and ignored the missing download end; you should probably check both sides whether they follow CiA 301 in that regard.

Related Topic