Modbus Values Slightly Off

Hi folks

I’m reading and writing two 16-bit holding registers as floats in a Schneider PLC. The problem is that whenever I write to certain values it writes a slightly different value in the register.

Few examples:
6.24 evaluates to 6.22
6.28 evaluates to 6.25
6.29 evaluates to 6.28

A further complication is that this doesn’t occur with every register. For example: HRF620 I can write to perfectly, but not HRF622. I’ve ruled out any interference by the PLC.

Has anyone else had any experience of this?

Could you turn WriteMultipleRegistersRequest and ReadHoldingRegistersRequest loggers to TRACE in the gateway logs area and then write one of these values and then export and upload the logs?

system_logs_07Sep2017-17-04-42.zip (2.5 MB)

Sorry, that log is quite heavy since I have a lot of read requests going on. I labelled it .zip but it’s actually .7z.

That should be a record of me writing 6.965 to test1 (HRF620) with a successful result and then writing 6.965 to test2 (HRF622) with an unsuccessful result (evaluates to 6.938).

Try setting the “Span Gaps” advanced setting on this Modbus device to false.

The correct value is being written, but an incorrect value is being returned by the device. This often happens when reading bigger blocks of registers from devices with crappy Modbus implementations…

No luck I’m afraid! Still off by ~0.02.

I am seeing this incorrect value in my PLC code also. Do you mean that Ignition is writing the correct value and the PLC is simply interpreting and storing that value incorrectly?

It’s a Schneider M241. It wouldn’t exactly fix the problem but it would make me feel better if I thought the PLC was to blame.

Yes, Ignition is writing the correct value, but when read back the PLC returns 0x40DEE148 (6.965) for the first and 0x40DE0000 (6.9375) for the second. In fact, all the remaining register values being read in that block are 0, which is what makes me think the PLC is screwing up the request. Did you try changing that setting?

Yeah, I changed span gaps to false in the driver and tried the same operation as above with the same result.

I haven’t noticed a write operation affecting any registers other than the one it was supposed to. For instance: HRF622 writes incorrectly but has no effect on the adjacent registers HRF16, HRF18, HRF20 or HRF640 (all setpoints with values in them). I assume these would be in the same block but they’re showing their correct values, not zero.

That’s too big for one request. The limit is 125 registers. The request in question here is from address 525 for 124 registers. The value in the response returned is:

00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
42 48 00 00 42 20 00 00 
42 0C 00 00 42 20 00 00 
42 34 00 00 42 20 00 00 
41 C8 00 00 41 A0 00 00 
42 0C 00 00 41 F0 00 00 
42 50 00 00 41 C8 00 00 
42 60 00 00 42 20 00 00 
41 A0 00 00 41 F0 00 00 
42 70 00 00 41 A0 3E 94 
41 D6 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
42 48 00 00 41 C8 3F CB 
40 DE 00 00 3F 80 00 00 
44 42 40 00 40 DE E1 48 <-
40 DE 00 00 00 00 00 00 <-
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00

You can see where the first 40 DE E1 48 occurs (HRF620) and then the following 40 DE 00 00 (HRF622).

Sorry, I mis-typed. I meant 616, 618, 620, 622, 640. Those empty registers seem correct. My analogs are distributed over a range between 400-700 with plenty of gaps (not sure why, possibly Schneider reasons).

I’ve seen similar translation issues before when I’ve had word/byte swapping or offsets (0 vs 1-base) incorrectly configured on MB configurations (for floating point numbers). One resource that I wanted to share here was this IEEE754 conversion site, which can be pretty handy for parsing some of the data (and exploring how byte/word swapping can affect the result).

IEEE-754 Floating-Point Conversion From 32-bit Hexadecimal Representation
To Decimal Floating-Point

Hope this helps at least as a resource…

It takes something with a 7 bit mantissa to make that difference.
I did the calculation, assuming an IEEE754 representation with 7 bits mantissa, I get exactly your values, rounded to the cent. 6.2188, 6.25 and 6.2813.

7 bits of mantissa is what fits the first register on a 32 bits float. Somehow, you’re loosing or overwriting the second register.

I don’t know how to read that log. Can you get a dump of the communication?

First thing that comes to my mind, maybe you’re writing with function 6, single register.