Modbus FC04 (Read Input Registers)
Function code 04 reads input registers, the sixteen-bit read-only words that devices use for measured, computed, or sensed values you are meant to read but not change. When a datasheet documents a value in the 30001 range, FC04 is the code that reaches it. This reference explains what FC04 targets, its per-request limit, and the constant confusion with the holding-register read.
Modbus Function Code 04 Read Input Registers in one line: Modbus function code 04 reads input registers: the read-only sixteen-bit words holding measured or computed values a device reports, usually documented in the 30001 range. The request names a starting register and a quantity, and the device returns two bytes per register, high byte first, for up to 125 registers. There is no write code, because input registers are read-only by design.
What FC04 Reads and Why There Is No Write Code
Input registers are the read-only sixteen-bit words a device uses to report values it produces: a temperature from a sensor, a computed rate, a firmware-maintained counter. Function code 04 reads a contiguous block of them. The request carries a starting address and a quantity, and the reply is a byte count followed by two bytes per register, most significant byte first, exactly like a holding-register read. A single request can read up to 125 registers before hitting the protocol data unit limit.
Because input registers are read-only, Modbus provides no function code to write them, and any attempt to do so is by definition unsupported. That read-only status is the entire difference from holding registers on the wire, since the response format is identical. Where each table sits is described in the Modbus register types reference.
FC04 Versus FC03 and Address Ranges
The classic mistake is reading a 30001-range value with function code 03 or a 40001-range value with function code 04. FC04 reads only the input-register table and FC03 reads only the holding-register table, so a value read under the wrong code returns an exception or, worse, plausible garbage from a different table that happens to have the same offset. The FC4 input vs FC3 holding register read reference dissects exactly this trap.
Datasheet numbering compounds the problem. A register documented as 30005 is input register offset 4 on the wire, because the leading 3 signals the table and the numbering is one-based while the wire is zero-based. The Modbus register addressing reference explains how to translate the documented number into the offset FC04 actually carries. When in doubt, read a known value under both FC03 and FC04 and see which returns the expected number.
The FC04 Frame Field by Field
The protocol data unit is small enough to memorize, and knowing it cold makes packet captures readable at a glance.
| Field | Size | Notes |
|---|---|---|
| Function code (request) | 1 byte | 0x04 |
| Starting offset | 2 bytes | Zero-based wire address, high byte first |
| Quantity | 2 bytes | 1 to 125 registers |
| Function code (response) | 1 byte | 0x04 echoed, or 0x84 for an exception |
| Byte count (response) | 1 byte | Two bytes per register requested |
| Register data | 2 bytes each | Most significant byte first |
This PDU is identical whether the transport is serial or Ethernet; only the wrapper changes. Modbus RTU frames it with a station address and CRC, while Modbus TCP prefixes the MBAP header and drops the CRC in favor of TCP's own integrity checking. So a driver that builds a correct FC04 request for one transport builds a correct one for the other, and a capture tool decodes both the same way once the framing is stripped.
A Worked Read, in Symbols
Suppose a device datasheet documents a temperature as a 16-bit value at register 30011 and a totalizer as a 32-bit value occupying 30021 and 30022. For the temperature: strip the leading 3 that marks the table, subtract one for the one-based documentation convention, and the wire request is function 0x04, starting offset 10, quantity 1. The response carries one register, two bytes, high byte first, and the raw count still needs the scaling the register map specifies - if the device publishes tenths of a degree, dividing is your job, not the protocol's.
For the totalizer: starting offset 20, quantity 2, one request. The two returned words then have to be assembled in the word order the device uses, which is exactly the pairing problem described for a 32-bit float across two Modbus registers - the standard fixes byte order inside a register but not word order across the pair, so vendors differ. Read both halves in a single request rather than two separate polls: two polls can straddle a device update, splicing the high word of the old value onto the low word of the new one and producing a totalizer that appears to jump wildly.
Exceptions and Polling Strategy
Two exceptions dominate FC04 troubleshooting. Exception 02, illegal data address, means the starting offset plus quantity runs past what the device implements - often an off-by-one from the documentation convention, or a block read that strays one register beyond the map. Exception 01, illegal function, means the device does not implement the input-register table at all, which is common: plenty of devices put every value, measured or not, in holding registers and expect FC03 for everything. The full decode of what each code implies is in the Modbus exception codes reference table.
Polling strategy is a trade between efficiency and device quirks. Fewer, larger contiguous reads cost far less than many single-register requests on a slow serial link, so drivers naturally block adjacent registers together into one FC04 request. But some devices reject any read that spans an unimplemented gap between documented registers, returning exception 02 for the whole block. The fixes are to split requests around the gaps the register map shows, or to poll only documented contiguous runs - while always keeping each request at or under the 125-register protocol limit.
Frequently Asked Questions
Can you write an input register?
No. Input registers are read-only and Modbus defines no write function code for them. A value that needs to be set by the master, such as a setpoint, belongs in the holding-register table and is written with function code 06 or 16. FC04 only reads values the device reports.
What address range do input registers use?
Input registers are conventionally documented in the 30001 range, where the leading 3 identifies the table. On the wire that becomes a zero-based offset, so 30001 is offset 0. This is a documentation convention, not a wire field, so always confirm whether a datasheet number is one-based or the raw offset.
Why does the same offset return different values under FC03 and FC04?
Because they read different tables. Offset 5 in the input-register table and offset 5 in the holding-register table are unrelated memory. Reading a measured value with the wrong code can return a real number that belongs to another value entirely, which is why a plausible but wrong reading often traces to using FC03 where FC04 was needed, or the reverse.
Why does a device answer FC03 but reject FC04?
Because it implements only the holding-register table. Nothing obliges a vendor to populate input registers, and many devices expose all values - measured ones included - in the 40001 range read with FC03. An illegal-function exception in response to FC04 is the giveaway. Use whichever code the device's register map documents rather than assuming measured values live in the 30001 range.
How should a 32-bit value be read with FC04?
As two consecutive registers in one request, then combined according to the device's word order. Reading the halves in separate polls invites tearing: the device can update the value between the two reads, leaving you with the high word of one sample glued to the low word of another. One request, quantity two, assembled per the register map, avoids it entirely.
Sources and verification
This page references the protocol specifications published by the organizations below. Editions, product capabilities, and documentation change over time - confirm current requirements and specifications directly with the source.
- Modbus Application Protocol Specification - Modbus Organization
Merobix is not affiliated with, endorsed by, or sponsored by these organizations; their names are used only to identify the standards and products discussed.
Automation services
Need help turning this into a working system?
Merobix integrates SCADA, programs Allen-Bradley and Siemens PLCs, and designs and fabricates industrial control panels.
Meeting requests are reviewed before confirmation.