Blog

FoE (File over EtherCAT) Firmware Update Explained

October 7, 2026

FoE (File over EtherCAT) Firmware Update Explained

A protocol-level look at packet structure, opcodes, and error handling

Most explanations of File over EtherCAT (FoE) stop at “the master sends the file, the slave acknowledges each packet.” That's true, but it skips the part that actually matters when you're implementing or debugging FoE at the byte level: the exact PDU structure, the opcode set, how reads differ from writes, and what the error codes actually mean when a transfer goes wrong. This guide goes into that protocol-level detail.

Where FoE Sits in the EtherCAT Stack

FoE is one of the mailbox protocols carried inside the EtherCAT mailbox mechanism, alongside CoE, EoE, SoE, and AoE. Mailbox communication runs over the same EtherCAT frame structure as process data but is logically separate — it's used for acyclic, one-off transfers like configuration access and file transfer, rather than the cyclic process data exchange that carries real-time control values. FoE was deliberately kept simple and TFTP-like precisely because firmware transfer doesn't need to be real-time; it needs to be reliable and simple enough to implement in a small bootloader footprint.

The FoE PDU Structure

Every FoE message is carried inside a standard EtherCAT mailbox header, followed by an FoE-specific header whose first byte identifies the opcode. The FoE-specific portion of the header looks like this:

Bytes Content
Byte 0 OpCode (1 byte)
Byte 1 Reserved (1 byte)
Bytes 2-5 Password / Packet Number / Error Code (4 bytes, meaning depends on OpCode)
Bytes 6+ File Name / Data / Error Text (variable length, depends on OpCode)

That 4-byte field at bytes 2-5 is the part that trips people up when reading a raw capture, because it means three different things depending on which opcode is in byte 0 — a password on a Read/Write Request, a packet number on Data, and an error code on an Error message.

The FoE Opcode Set

OpCode Name Direction Purpose
1 FoE Read Request (RRQ) Master → Slave Master requests to read (upload) a file from the slave
2 FoE Write Request (WRQ) Master → Slave Master requests to write (download) a file to the slave — this is the opcode used to start a firmware update
3 FoE Data (DATA) Both directions Carries a sequential chunk of file data, tagged with a packet number
4 FoE Acknowledgement (ACK) Both directions Acknowledges receipt of a Data packet or a Request, referencing the packet number being acknowledged
5 FoE Error (ERR) Both directions Reports a failure and aborts the transfer, carrying an error code and optional human-readable error text
6 FoE Busy (BUSY) Slave → Master Slave signals it needs more time before it can accept/process the next packet (e.g., while erasing flash) without aborting the session

The Write (Download) Sequence — How a Firmware Update Actually Flows

This is the sequence a firmware update over FoE follows, opcode by opcode:

  • Master sends WRQ (OpCode 2), with the target filename in the variable-length field and a password value (commonly used by slaves to gate which files can be written, or ignored/set to zero if unused).
  • Slave responds with ACK (OpCode 4), packet number 0, indicating it's ready to receive data. If the filename or password is rejected, the slave sends ERR instead and the transfer never starts.
  • Master sends DATA (OpCode 3), packet number 1, with a chunk of the firmware image sized to the mailbox's configured data length.
  • Slave writes/buffers that chunk and responds with ACK, packet number 1.
  • Steps 3-4 repeat, incrementing the packet number each time, until the final chunk — which is shorter than the full mailbox size (or exactly equal to it, followed by one final zero-length Data packet, depending on implementation) — signaling end of file.
  • Slave completes the write, validates the image, and sends a final ACK. From here the slave's bootloader takes over the actual flashing and reboot sequence — FoE's job (delivering the bytes) is done once the last ACK is sent.

The Read (Upload) Side — Often Skipped in Bootloader Discussions

FoE isn't only for pushing firmware down to a device — OpCode 1 (Read Request) lets a master pull a file off a slave, which is commonly used for reading back configuration files, log files, or a currently running firmware image for verification. The flow mirrors the write sequence with direction reversed:

  • Master sends RRQ (OpCode 1) with the filename it wants to read.
  • Slave responds immediately with the first DATA packet (OpCode 3), packet number 1 — there's no separate ACK step before data starts flowing, unlike the write sequence.
  • Master ACKs each Data packet, and the slave sends the next chunk in response to each ACK.
  • The transfer ends the same way as a write — a final short (or zero-length) Data packet signals end of file.

This asymmetry — write starts with an ACK before data flows, read starts with data immediately — is a common source of interoperability bugs when a master or slave stack implementation assumes both directions behave identically.

FoE Error Codes

When a transfer can't continue, either side sends an ERR (OpCode 5) with an error code in the 4-byte field and, optionally, human-readable error text in the variable-length field. The error code values are drawn from a shared range with other EtherCAT mailbox error codes; the ones specific to FoE-relevant failure conditions are the ones actually seen in practice:

Condition Typical Cause
Not found Requested filename doesn't exist on the slave (relevant to Read Request)
Access denied Password check failed, or the slave restricts writes to that filename in its current state
Disk full Slave's flash/storage region can't hold the incoming file
Illegal opcode Received an opcode the slave's FoE implementation doesn't support or expect in the current state
Packet number wrong Received Data packet number doesn't match the expected next sequence number — the classic “out of sync” failure
Already exists Write target conflicts with an existing file the slave won't overwrite without an explicit condition being met
No user No FoE session currently open, or session ownership conflict (e.g., two masters/tools attempting FoE simultaneously)
Program error Generic catch-all for a device-specific internal failure during the write (e.g., flash write failure)

A “Packet number wrong” error is worth calling out specifically: it's the single most common FoE error seen in real interoperability testing, and it almost always traces back to one side losing track of state — a retried Data packet reusing an old sequence number, or a master and slave disagreeing about whether packet numbering restarts at 0 or 1 for a given implementation quirk.

Handling BUSY: The Opcode Most Implementations Get Wrong

The BUSY opcode (6) exists because flash operations — especially sector erase — can take substantially longer than a normal mailbox round-trip, and the slave needs a way to say “not ready yet, but don't abort” rather than either blocking mailbox communication entirely or timing out the session. A slave sends BUSY (optionally with an estimated wait time) in place of the expected ACK, and a well-behaved master extends its timeout accordingly rather than treating the delay as a failure.

The common implementation mistake is on the master side: a master stack hard-coded to a fixed mailbox timeout with no BUSY handling will abort a perfectly healthy transfer the moment a slave pauses to erase a flash sector, producing an intermittent failure that only shows up on slower flash parts or larger erase block sizes — exactly the kind of bug that passes testing on a fast dev board and fails in the field on production hardware with slower flash.

Practical Notes for Implementers

  • Mailbox size, negotiated during EtherCAT slave configuration, directly determines how many Data packets a given firmware image requires — a smaller mailbox means more round trips and a slower overall transfer, which matters for time-sensitive field update windows.
  • Packet numbers should be validated strictly on receipt; silently accepting an out-of-order or repeated packet number to “be lenient” is exactly how corrupted images get flashed without either side noticing until the device fails to boot.
  • The password field in WRQ/RRQ is not a security mechanism on its own — it has no cryptographic strength and is visible in plaintext on the wire. Real access control needs to sit at the application layer (signed images, a proper authentication handshake) rather than relying on the FoE password field alone.
  • BUSY handling and a sensible retry/timeout policy should be treated as required, not optional — the naive fixed-timeout approach is one of the most common causes of field-only FoE failures.

FAQs

Yes — FoE itself is a generic file transfer mechanism. Whether a given Write Request is treated as a firmware image or a configuration file is determined by the slave's own interpretation of the filename and its internal handling, not by anything in the FoE protocol itself.

There's no built-in resume mechanism in the base FoE protocol — a dropped connection mid-transfer generally means starting the write over from packet 1. This is one of the reasons dual-bank flash designs matter: an interrupted transfer should leave the previous working firmware image untouched and bootable.

Not natively. Some vendor-specific bootloader implementations add resume logic on top of FoE by tracking last-confirmed packet numbers, but that's an implementation extension, not part of the base FoE specification.

This almost always means a mismatch in starting sequence number convention between master and slave implementations — check whether both sides agree the first Data packet after a Write Request's ACK is numbered 1 (the common convention) rather than 0.

It depends on the slave's implementation — some allow FoE access in Pre-Operational or Safe-Operational states without disrupting process data, while others require dropping into a dedicated Bootstrap state where only mailbox communication is active. This is a device-specific design decision, not a fixed protocol rule.

Simma Software builds real-time protocol stacks and flash bootloaders across CAN, LIN, UDS, J1939, CANopen, XCP, and EtherCAT, with robust FoE handling — including BUSY/timeout management and dual-bank fallback — built in. Contact us to talk through your FoE or EtherCAT bootloader implementation.