What are Modbus function codes?
A function code is the verb of a Modbus request: it says which of the four data lists you want and whether you are reading or writing. You only need eight of them in practice. Function code 3 reads holding registers and is the one you will use most; 4 reads input registers; 1 and 2 read on/off values; 6 and 16 write registers; 5 and 15 write on/off values. Everything else in the specification is rarely seen in building equipment.
The eight that matter
| Code | Name | In plain English |
|---|---|---|
| 1 | Read Coils | Read on/off values you are allowed to change |
| 2 | Read Discrete Inputs | Read on/off values you cannot change — statuses, alarms |
| 3 | Read Holding Registers | Read numbers. The workhorse; most maps live here |
| 4 | Read Input Registers | Read numbers you cannot change — usually live measurements |
| 5 | Write Single Coil | Switch one on/off value |
| 6 | Write Single Register | Set one number |
| 15 | Write Multiple Coils | Switch several on/off values at once |
| 16 | Write Multiple Registers | Set several numbers at once — needed for anything wider than 16 bits |
Two notes that save time. Function code 3 versus 4 is a real distinction and not interchangeable: a value in the holding registers cannot be read with code 4, and plenty of devices put their measurements in holding registers anyway, so the map has to tell you which. Code 16 is required for 32-bit values, because writing the two halves with two separate code 6 requests leaves the device holding half of the old value and half of the new one for a moment, which on a setpoint can be a very large number indeed.
One more worth knowing about
Function code 43, sub-function 14 — Read Device Identification — asks the device who it is, and can return a vendor name, product code, model and firmware revision. It is the nearest thing Modbus has to self-description. It is also optional, and most equipment does not implement it, so a refusal here means nothing at all about whether the device is healthy.
When the device says no: exception codes
An exception reply means the device received the request, understood it, and declined. That is useful information: the device is alive and reachable.
| Code | Name | What to do |
|---|---|---|
| 1 | Illegal function | This device does not support that function code. Try 3 instead of 4, or vice versa. |
| 2 | Illegal data address | That register does not exist. Your address is wrong, or off by one. The device itself is fine. |
| 3 | Illegal data value | The value or the quantity is out of range. Often means you asked for too many registers at once, or wrote a value the device will not accept. |
| 4 | Device failure | Something went wrong inside the device while handling the request. |
| 5 | Acknowledge | Accepted, but it needs more time. Rare. |
| 6 | Device busy | Try again shortly. |
| 10 | Gateway path unavailable | The gateway has no route to that unit ID. |
| 11 | Gateway target device failed to respond | The gateway is fine; nothing answered at that unit ID on the serial side. Wrong unit ID, or a wiring problem. |
How many registers in one request?
The specification allows 125 registers or 2000 bits per request. A lot of real equipment, especially cheap gateways, falls over well before that — truncating the reply, returning exception 3, or simply hanging. If reads work one at a time but fail in blocks, lower the block size to 32 or even 16 and try again.
It is still worth reading in blocks rather than one register at a time. On a serial chain each request costs tens of milliseconds of wire time, so forty separate reads is a visible wait, and forty chances to collide with whatever else is polling that chain.