CANopen SDO Explained: Expedited, Segmented, Block

By | August 21, 2026

Every CANopen device carries an object dictionary, and the SDO is the only way to reach into it from outside. Read a serial number, change a gear ratio, remap a PDO, save the configuration to flash — all of it is SDO traffic.

Unlike a PDO, an SDO frame carries its own address. The first byte says what kind of operation this is, the next three say which object, and whatever is left holds data. That structure means you can read an SDO exchange straight off a bus trace without a decoder, once you know what the command byte is telling you.

This guide takes the frame apart byte by byte, walks through the three transfer types with real hex, and covers what the abort codes actually mean when a write comes back rejected. Verified against CiA 301.

Client, server, and who owns what

An SDO is a peer-to-peer channel between exactly two devices, and the roles are not symmetric.

The server owns the object dictionary being accessed. The client initiates every transfer, in both directions. A slave device never starts an SDO exchange on its own — it answers.

That last point catches people who expect “upload” and “download” to describe the direction of travel from the master’s point of view. The names are written from the server’s perspective:

  • Download — client writes into the server’s object dictionary.
  • Upload — client reads out of it.

So a PLC reading a drive’s status is doing an SDO upload, even though from the PLC’s side the data is coming in.

Every device supports at least one SDO server, and the default channel uses two identifiers from the predefined connection set:

DirectionCOB-IDCarries
Client → server600h + node-IDRequests
Server → client580h + node-IDResponses

For node 12 that is 60Ch and 58Ch. A trace full of traffic on 60Ch and 58Ch is a configuration tool talking to node 12, and you can read the exchange directly.

SDOs work in NMT pre-operational and operational states. They stop in stopped state — worth remembering when a device that was answering suddenly does not.

The eight bytes

Every SDO frame is eight bytes, always. Short transfers are padded.

SDO frame

Bytes 1 to 3 are the multiplexer: index low byte, index high byte, sub-index. Object 6041h sub-index 00h appears on the wire as 41 60 00. The byte swap trips everyone up once — CANopen is little-endian throughout, including inside PDO payloads.

Byte 0 is the command byte, and it does the real work. The top three bits are the command specifier, and their meaning depends on which side is talking:

Bits 7–5Client sends (ccs)Server sends (scs)
0Download segmentUpload segment
1Initiate downloadDownload segment ack
2Initiate uploadInitiate upload response
3Upload segmentInitiate download ack
4AbortAbort
5Initiate block uploadBlock download response
6Initiate block downloadBlock upload response

The remaining five bits carry flags whose meaning changes with the command. For an initiate, they are:

BitNameMeaning
3–2nNumber of bytes in the data field that are not data
1e1 = expedited, 0 = normal (segmented)
0s1 = size is indicated

The n field is defined backwards from what you would guess: it counts the unused bytes, not the used ones. Two bytes of payload in an expedited frame means n = 2, because bytes 6 and 7 are padding.

Expedited transfer: four bytes or fewer

If the data fits in four bytes, it rides along in the initiate frame and the whole transaction is two CAN frames. This covers the overwhelming majority of real SDO traffic — control words, mode selections, timeouts, mapping entries, node IDs.

Expedited transfer is mandatory. Every CANopen device supports it.

Write: 16-bit value to the control word

Writing 000Fh to object 6040h sub-index 00h on node 3.

Request   COB-ID 603h   2B 40 60 00  0F 00 00 00
Response  COB-ID 583h   60 40 60 00  00 00 00 00

The request command byte, 2Bh:

2Bh = 0010 1011
      001        ccs = 1, initiate download
         0       reserved
          10     n = 2, so bytes 6-7 are padding
             1   e = 1, expedited
              1  s = 1, size indicated

Two bytes of payload, 0F 00, little-endian, value 000Fh. The response, 60h, is scs = 3 with no flags: the write succeeded. Nothing else in the response matters — the multiplexer is echoed back and the data field is empty.

Command bytes for expedited writes are worth memorizing, because you will read them constantly:

PayloadCommand byte
1 byte2Fh
2 bytes2Bh
3 bytes27h
4 bytes23h

Some clients send 22h — expedited, size not indicated — and let the server work out the length from the object dictionary. It is legal and common. It also means a mismatched data type fails at the server instead of being caught in the frame, so 2Bh-style writes with the size declared are the better habit.

Read: status word

Request   COB-ID 603h   40 41 60 00  00 00 00 00
Response  COB-ID 583h   4B 41 60 00  37 06 00 00

The request is 40h — ccs = 2, no flags, since a read carries no data. The response 4Bh is scs = 2 with n = 2, e = 1, s = 1: two bytes of data follow. Value 0637h.

Segmented transfer: more than four bytes

Anything longer than four bytes goes out in pieces. A device name, a domain object, a firmware block. Segmented transfer is mandatory only if the device has objects larger than four bytes — a simple I/O module may legitimately not support it.

The initiate frame declares the total size, then each segment carries up to seven data bytes.

Reading a 12-byte string from 1008h (manufacturer device name) on node 3:

Request    603h   40 08 10 00  00 00 00 00      initiate upload
Response   583h   41 08 10 00  0C 00 00 00      size = 12 bytes

Request    603h   60 00 00 00  00 00 00 00      segment, toggle 0
Response   583h   00 44 72 69  76 65 20 58      "Drive X"

Request    603h   70 00 00 00  00 00 00 00      segment, toggle 1
Response   583h   15 4C 33 30  30 00 00 00      "L300", last

Three things are happening here.

The initiate response declares the size. 41h is scs = 2 with e = 0 and s = 1: not expedited, size indicated. Bytes 4 to 7 hold the length as a 32-bit little-endian value — 0Ch, twelve bytes.

The toggle bit alternates. Bit 4 of the command byte starts at 0, flips on every subsequent segment, and must match between request and response. 60h has it clear, 70h has it set. If two consecutive segments arrive with the same toggle value, the receiver discards the second one. This is the entire retransmission defense of segmented transfer: no sequence numbers, one bit.

The last segment is flagged. In a segment frame the bit layout changes — bits 3 to 1 are n, and bit 0 is c, the completion flag:

15h = 0001 0101
      000        scs = 0, upload segment
         1       toggle = 1
          010    n = 2, so 2 of the 7 data bytes are unused
             1   c = 1, no more segments

Seven bytes minus two unused gives five bytes of data: 4C 33 30 30 00, which is “L300” plus the terminating null. Seven from the first segment plus five here is twelve, matching the size the server declared at initiate. That reconciliation is the check worth doing whenever a string comes back truncated.

It is also exactly where hand-decoding goes wrong, which is why the CANopen message decoder exists — paste the trace and the segments come back reassembled.

Segmented transfer costs two CAN frames per seven bytes. A 200-byte object is around 58 frames. It works, and it is slow.

Block transfer: the fast path nobody uses

Block transfer exists to fix that overhead. Instead of acknowledging every segment, the client and server agree on a block size, then the sender pushes up to 127 segments back to back with only one acknowledgment at the end.

The mechanism is a go-back-N scheme. Each segment carries a sequence number in its command byte. After the block, the receiver reports the sequence number of the last segment it got cleanly, which implicitly acknowledges everything before it, and states how many segments it wants in the next block. Anything after that point is retransmitted.

The initiate exchange also negotiates a 16-bit CRC over the complete data set, checked at the end of the transfer. Both sides have to advertise CRC support for it to be used.

Two details matter in practice. Block size is 1 to 127 segments, and the receiver can shrink it mid-transfer if it is falling behind. And there is a threshold mechanism on upload: the client tells the server the smallest data size worth using a block transfer for, and the server may fall back to normal segmented transfer if the object is smaller than that.

Block transfer is optional, and support in the field is patchy. Configuration tools generally probe for it and quietly fall back. If you are moving firmware images over CANopen it is worth checking whether both ends support it — the difference on a 64 kB file is substantial. For everything else, it rarely comes up.

Choosing a transfer type

The client picks, based on size, but it is not entirely free:

Data sizeAvailable
≤ 4 bytesExpedited, segmented, or block
> 4 bytesSegmented or block

In practice: expedited for anything that fits, segmented for the rest, block only if both ends support it and the object is large enough to pay back the setup cost.

Reading an abort

When a transfer fails, either side sends an abort. It is unconfirmed — the frame goes out and the transfer is over. Nobody responds.

The command byte is always 80h, the multiplexer is echoed, and bytes 4 to 7 carry a 32-bit abort code, little-endian.

583h   80 40 60 00  02 00 01 06

Read bytes 4 to 7 backwards: 06 01 00 02 → abort code 06010002h, “attempt to write a read-only object”. The byte reversal is the reason abort codes so often look unfamiliar in a raw trace.

The codes group by their first byte, which tells you where to look:

Abort codeMeaning
0503 0000hToggle bit not alternated
0504 0000hSDO protocol timed out
0504 0001hCommand specifier not valid or unknown
0504 0002hInvalid block size (block mode only)
0504 0003hInvalid sequence number (block mode only)
0504 0004hCRC error (block mode only)
0504 0005hOut of memory
0601 0000hUnsupported access to an object
0601 0001hAttempt to read a write-only object
0601 0002hAttempt to write a read-only object
0602 0000hObject does not exist in the object dictionary
0604 0041hObject cannot be mapped to the PDO
0604 0042hNumber and length of mapped objects would exceed PDO length
0604 0043hGeneral parameter incompatibility
0604 0047hGeneral internal incompatibility in the device
0606 0000hAccess failed due to a hardware error
0607 0010hData type does not match, length of service parameter does not match
0607 0012hData type does not match, length too high
0607 0013hData type does not match, length too low
0609 0011hSub-index does not exist
0609 0030hInvalid value for parameter (download only)
0609 0031hValue written too high
0609 0032hValue written too low
0609 0036hMaximum value is less than minimum value
060A 0023hResource not available: SDO connection
0800 0000hGeneral error
0800 0020hData cannot be transferred or stored to the application
0800 0021hData cannot be transferred or stored — local control
0800 0022hData cannot be transferred or stored — current device state
0800 0023hDynamic object dictionary generation failed, or no object dictionary present
0800 0024hNo data available

Three of these dominate real troubleshooting.

0602 0000h — the object does not exist. Nine times out of ten this is the wrong index, or a manufacturer-specific object that this particular firmware revision does not implement. Compare against the EDS for the exact firmware version, not the family datasheet.

0800 0022h — wrong device state. The write is valid but not right now. Communication parameters usually cannot be changed while the associated PDO is active, and many devices refuse configuration writes in operational state. Drop to pre-operational and repeat.

0607 0010h — length mismatch. The client sent a different number of bytes than the object expects. Writing a 16-bit object with a 4-byte expedited frame produces this, and so does the reverse. Check the data type in the EDS.

More than one SDO channel

A device can support several SDO servers. Each one gets its own record:

RangePurpose
1200h–127FhSDO server parameters
1280h–12FFhSDO client parameters

1200h describes the default server, and its identifiers are usually read-only — they are fixed by the node-ID. Additional servers at 1201h upward can be assigned freely, which is how you give two masters independent access to the same device without their transactions colliding.

The client records at 1280h upward are what make a device capable of initiating SDO transfers itself. A PLC configuring drives on the same bus needs these; a sensor does not. Each record holds the two COB-IDs plus the node-ID of the server it talks to.

One SDO channel supports exactly one transfer at a time. A second request on the same channel while a segmented transfer is in progress aborts the first. Tools that appear to configure several nodes in parallel are either using separate channels or interleaving at a level above the protocol.

SDO or PDO

Both move data between the same objects. The difference is what they are for.

SDOPDO
ModelClient/server, confirmedProducer/consumer, unconfirmed
AddressingIndex and sub-index in the frameImplicit, from the mapping
PayloadUnlimited, segmented≤ 8 bytes, single frame
Overhead4 bytes per frameNone
PriorityLow (580h/600h + node-ID)High (180h–500h + node-ID)
ErrorsAbort code returnedSilent
UseConfiguration, diagnostics, occasional readsCyclic process data

The practical rule: if a value is read once at startup or written once during commissioning, SDO. If it moves every cycle, map it into a PDO.

Polling a value over SDO in a fast loop is the classic mistake. It costs two frames per read where a PDO costs one, it runs at low priority so it loses arbitration to everything else on a busy bus, and it produces jitter that looks like a device problem. If you find yourself SDO-polling at 50 ms, the answer is a TPDO with an event timer.

The reverse mistake is rarer but worse: mapping configuration parameters into PDOs so they can be changed quickly. Now a corrupted or mistimed frame silently rewrites a machine parameter with no acknowledgment and no error path.

Timeouts and field failures

The standard does not fix an SDO timeout value — it is a client-side setting, and typical values run from 500 ms to a few seconds. Too short and slow devices produce spurious aborts, particularly ones that write to flash during the transaction. Too long and a dead node stalls a configuration sequence for seconds per object.

Object 101Bh, where implemented, holds the device’s own SDO protocol timeout.

The failure patterns that come up repeatedly:

No response at all. Not an SDO problem. Check the node-ID first — a request to 605h reaches nobody if the device is set to node 6 by DIP switch but node 5 in the project. Then check NMT state, since a stopped node ignores SDOs entirely.

First segment works, transfer stalls. Toggle bit handling on one side. This shows up with hand-written stacks and with some gateway devices that forward SDO traffic without tracking the toggle state.

Write returns success, value unchanged. The write landed in RAM. Store it with the save signature to 1010h, or the device is applying the value only after a reset.

Works with one tool, fails with another. Usually the size-indicated flag. A client that sends 22h and lets the server infer the length will behave differently from one that sends 2Bh and declares two bytes, on a device that is strict about data types.

Intermittent aborts on a loaded bus. SDO identifiers sit low in priority, so they lose arbitration to every PDO on the segment. On a bus running near capacity, configuration traffic is the first thing to suffer. Take the machine out of operational state before configuring it.

FAQ

What is the difference between SDO upload and download?

The names are written from the server’s point of view. Download means the client writes into the server’s object dictionary; upload means the client reads out of it. A master reading a slave parameter is performing an upload.

What is the maximum data size an SDO can transfer?

There is no fixed limit. Expedited transfer carries up to four bytes in a single frame, and segmented or block transfer handles anything larger by splitting it across frames. Firmware images of tens of kilobytes are moved this way.

Why does my SDO write return abort code 06010002h?

The object is read-only. Either it genuinely is — an identity or diagnostic object — or the device treats it as read-only in the current state. Communication parameters are commonly writable only when the associated PDO is disabled and the device is in pre-operational state.

What is the toggle bit for?

It detects lost or duplicated segments during segmented transfer. It starts at 0, alternates on each subsequent segment, and must match between request and response. Two consecutive segments with the same toggle value cause the second to be discarded.

Which COB-IDs do SDOs use?

By default, 600h + node-ID for client-to-server requests and 580h + node-ID for server-to-client responses. Additional SDO channels can be assigned other identifiers through the objects at 1200h and above.

Can I use SDOs instead of PDOs for process data?

You can, and it is usually a mistake. SDOs cost twice the frames, sit at low priority so they lose arbitration on a busy bus, and add variable latency. Anything transferred cyclically belongs in a PDO.

Is block transfer worth enabling?

Only for large objects, and only if both ends support it. For a few hundred bytes the saving is marginal. For firmware download it is significant. Support is optional and inconsistent, so most tools probe for it and fall back to segmented transfer.

Why does an SDO work in pre-operational but not in stopped state?

Stopped state halts all communication except NMT and heartbeat. That is by design — it is a way of isolating a device without powering it down. Return the node to pre-operational to configure it.

Author: Zakaria El Intissar

I've spent 13 years in power system automation, electrical protection, and SCADA communication, as an automation and industrial computing engineer. ScadaProtocols.com is where I turn what I've learned on site into plain guides and working tools — so other engineers can decode, analyze, and troubleshoot industrial communication protocols without the guesswork.