Modbus gives you two different commands for writing values into a device's holding registers, and choosing the wrong one is a common reason a write silently fails or a device rejects a request. Function code 6 writes a single register, and function code 16 writes a block of consecutive registers in one request. This guide explains the practical difference between the two, why some devices reject a block write for a single point while others insist on it, why 32-bit values usually force you to use function code 16, and how to pick the right one when configuring a Modbus poll.
Function Code 16 vs 6 in one line: Modbus function code 6, write single register, writes one holding register in a single request. Function code 16, write multiple registers, writes a block of consecutive holding registers in one request, applying them together. The key practical differences are that FC16 can update a multi-register value like a 32-bit float atomically in one message, while FC06 can only touch one register at a time - and some devices support only one of the two, so the right choice depends on the device and the value you are writing.
Function code 6, sometimes shown as 0x06 and called write single register or preset single register, does exactly one thing: it writes a single 16-bit value to a single holding register at one address. The request is compact - it carries the register address and the one value to write - and the device echoes the request back as its response to confirm. It is the simplest possible write, ideal when you need to change exactly one register: a setpoint, a mode selection, a command word. There is no ambiguity about scope because the scope is always a single register.
Function code 16, shown as 0x10 and called write multiple registers or preset multiple registers, writes a contiguous block of registers in a single request. The request carries a starting address, a count of how many registers to write, a byte count, and then the values for each register in sequence. The device applies them and responds with the starting address and the number of registers written. FC16 is the tool for updating several related registers at once, and it can write anything from a single register up to the block limit. The framing is heavier because the request has to describe how many registers it is writing and carry all their values, but that framing is what lets it act on a group of registers as one operation.
A single Modbus register is only 16 bits wide, but plenty of real values do not fit in 16 bits - a 32-bit floating-point number, a 32-bit integer, or a totalizer that has overflowed a single register. These are stored across two consecutive registers, and when you write them, the pair has to be updated together to be meaningful. Function code 16 is the natural fit because it writes both registers in a single request, so the device receives the complete 32-bit value at once and never sees a half-updated state. Writing the two halves as one atomic block is why FC16 is the standard choice for multi-register values.
Trying to write a 32-bit value with two separate function code 6 requests is where subtle bugs come from. Between the first single-register write and the second, the device momentarily holds a value that is half the new value and half the old - a nonsensical intermediate that the device may act on if it reads that register pair in that instant. For a setpoint or a command this transient can matter. Function code 16 avoids the problem entirely by delivering both registers together, which is why device documentation for flow computers, analyzers, and drives that expose 32-bit parameters so often specifies FC16 for writing them. Whenever a value spans more than one register, reach for function code 16 rather than stitching it together from single writes.
Not every device supports both codes, and the mismatches cause real-world head-scratching. Some simpler devices implement only function code 6 and will return an illegal function exception if you send them a function code 16 request, even for a single register. Others implement only function code 16 and expect all writes, including single-register writes, to come as a block write - so a function code 6 request is rejected. And some devices accept function code 16 only when the count is greater than one, rejecting a block write of a single register as malformed. The lesson is that neither code is universally correct; what a device supports is defined by its implementation and documented in its register map, and the write that works is the one the device was built to accept.
When you configure a write in a Modbus poll - whether in a traditional SCADA driver or in a cloud platform such as Merobix - the practical procedure is to match the function code to both the value and the device. For a single 16-bit parameter, function code 6 is the clean default unless the device documents that it wants block writes. For any value spanning two or more registers, function code 16 is almost always the right choice so the value updates atomically. And when a write is rejected with an illegal function exception, the fix is usually to switch to the other write code, because you have hit a device that supports only one of the two. Reading the vendor's register map to see which write functions each register accepts is what turns this from trial and error into a deliberate configuration choice.
Use function code 6 to write a single 16-bit holding register, such as a setpoint or a mode word, when the device supports single-register writes. Use function code 16 to write a block of consecutive registers in one request, or whenever the value spans more than one register, such as a 32-bit float or integer that occupies two registers. The value's size and the device's documented support determine the choice - some devices only accept one of the two codes.
A 32-bit float occupies two consecutive 16-bit registers, and both halves must be updated together to represent a valid value. Function code 16 writes both registers in a single atomic request, so the device never sees a half-updated, nonsensical value. Writing the two halves with two separate function code 6 requests leaves the device briefly holding a mix of old and new data between the two writes, which can cause it to act on a meaningless intermediate value.
Because Modbus support is defined by each device's implementation, and some devices only accept function code 16 when writing more than one register, treating a single-register block write as malformed. Others implement only function code 6 for single registers and reject function code 16 entirely, returning an illegal function exception. When a write is rejected this way, switching to the other write code usually resolves it - the device supports one but not the other, and the register map documents which.
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.
Last reviewed: July 27, 2026. Merobix is not affiliated with, endorsed by, or sponsored by these organizations; their names are used only to identify the standards and products discussed.
Merobix reads your field devices into a cloud SCADA - the real thing behind these terms, live in days from any browser.