A request for registers declares data bytes but carries 20 data bytes before its final CRC. Treat it as a malformed Modbus Function 0x10 request. A CRC calculated across the transmitted bytes does not repair the internal length contradiction.
Stop trying the usual quick fixes
| Quick fix | Why it fails | What to do instead |
|---|---|---|
| Recalculate the CRC over all 20 data bytes | The request still says five registers and 10 data bytes. CRC integrity and request-field validity are separate checks. | Correct the quantity, byte count, and payload together, then calculate the CRC last. |
| Expect the slave to ignore the second half | The extra bytes occupy the position where a length-driven parser expects the CRC. They can cause a CRC failure or corrupt parsing of the next frame. | Transmit exactly the number of data bytes declared in the request. |
| Call every rejection exception | A slave normally cannot return a Modbus exception for a frame it rejects at the transport-integrity stage. CRC failures are commonly discarded without a response. | Determine whether the slave accepted the frame boundary and CRC before interpreting the result as an exception. |
| Add delays between parts of the malformed request | A gap cannot reconcile contradictory quantity and byte-count fields. On serial links, a sufficiently large gap can split one bad request into multiple bad frames. | Send one internally consistent request with the required frame spacing. |
Identify the real cause
Function 0x10 writes multiple holding registers. Each register contributes two data bytes, so the request fields must satisfy:
Byte Count = 2 × Number of Points
With , the required byte count is:
The request is valid only when exactly those 10 data bytes follow the byte-count field before the CRC. Sending 20 data bytes creates two conflicting descriptions: the fields describe five registers, while the physical payload contains enough bytes for 10 registers.
“Correct CRC” must also be tied to a precise byte range. If the sender calculates the CRC over the entire malformed request, the checksum may be mathematically correct for that byte sequence. It still does not make the function payload valid. If the receiver derives the expected end of the request from , it can interpret the next two payload bytes as the CRC; that comparison will normally fail because the sender placed its CRC after all 20 payload bytes.
The order of checks determines the observed symptom. A serial receiver first has to recognize a frame and validate its CRC. Only then can the function handler validate quantity, byte count, address range, and values.
| Receiver result | Likely wire behavior | Meaning |
|---|---|---|
| Expected length comes from | No response; trailing bytes may produce another invalid frame | The parser reaches the supposed CRC before the sender’s actual CRC and rejects the request. |
| Entire transmission is treated as one frame and its CRC passes | Exception response may be returned | The function handler detects that the declared quantity and supplied data length disagree. |
| Entire transmission is treated as one frame but its CRC fails | No response | The frame fails integrity checking and never reaches function validation. |
| Device accepts only the first 10 data bytes | Five registers might be written, followed by communication errors | This is implementation-specific behavior, not a safe operating contract. |
Exception , Illegal Data Value, is a reasonable function-level response when the receiver has accepted a complete frame and then rejects the inconsistent request fields. It is not a substitute for CRC rejection. A device that detects the frame as corrupt can remain silent instead.
Rebuild the request from the register count
- Choose the intended write size. Decide whether the transaction must write five registers or 10 registers.
- For five registers, set
Number of Pointsto , setByte Countto , and append exactly 10 register-data bytes. - For 10 registers, set
Number of Pointsto , setByte Countto , and append exactly 20 register-data bytes. - Keep each register in the protocol’s two-byte register order. Do not solve a byte-count problem by removing one byte from each register.
- Calculate the CRC only after the address, function, starting address, quantity, byte count, and complete data field have been finalized.
- Append the CRC at the actual end of the request and transmit the request as one frame.
Do not reuse the CRC from either version after changing the quantity or byte count. Both fields participate in the checksum calculation, so even an unchanged data payload requires a new CRC when either field changes.
Verify the repair on the wire
- Capture the transmitted bytes at the master interface or with an independent serial monitor. Application logs may show the intended buffer rather than the bytes that reached the line.
- Locate function
0x10, then decode the starting address, quantity, byte count, data, and CRC in sequence. - Count the actual data bytes. Confirm
actual data bytes = Byte Count = 2 × Number of Points. - Recalculate the CRC across every request byte before the CRC field. Compare both transmitted CRC bytes in their on-wire order.
- Check the response. A successful
0x10response echoes the function, starting address, and written quantity; it does not echo the complete write payload. - Read back the target registers when the process permits it. Confirm both the written values and that adjacent registers remained unchanged.
If the corrected request still receives no response, check serial settings, slave address, frame spacing, wiring, and whether the requested register range is writable. If it returns an exception, decode the exception separately from CRC diagnostics; communication integrity has progressed far enough for the slave to answer.
Avoid the recurring parser traps
Validate the request before it enters the transmit queue. Generate Byte Count from the serialized register-data array instead of maintaining it as an independent constant. Generate Number of Points from the register count, then reject the buffer locally when the relationship fails.
Clear or resynchronize the receive buffer after a malformed serial request. The unused payload and final CRC can remain as trailing bytes, and the next valid request may appear to fail if the parser joins old and new data. Preserve one clean capture containing the request, the inter-frame gap, and any response; it distinguishes a function exception from silence caused by framing or CRC rejection.
Do not repeat malformed writes against live outputs while diagnosing parser behavior. A permissive slave might write the first five registers even though another device would reject the same byte stream.
FAQ
No. declares 10 data bytes. Use 10 bytes for five registers, or change the quantity to and byte count to for 10 registers.
Does a correct CRC make a mismatched Function 0x10 request valid?
No. CRC proves integrity only for the bytes included in its calculation. The quantity, byte count, and actual payload length must also agree.
Yes, if the device accepts the complete frame and detects the mismatch during function validation; otherwise it may discard the frame silently as a CRC or framing failure. Stop here if a corrected, captured request has matching lengths and a verified CRC but the device still rejects it or writes unexpected registers. Record the byte capture, serial settings, device identification, and response, then escalate through the manufacturer’s official support channel.