Modbus TCP 32 bit value

HI, I'm reading values from an SBC SAIA PLC. My problem is that some values are 32 bit. Now, using the modbus TCP nodes (I've tried several types) of course the node expects a 16 bit value for each register. If you have a 32 bit you should read 2 registers and manipulate the received data accordingly. But the register seems to be a 32 bit itself. I'm not familiar with the SAIA PLC so, maybe there is something I'm missing.
Here a screenshot from the PLC watching windows. The 3 registers R9008-9-10 are 3 completely different information and while the value I read from R9008 anf R9010 are obviously correct since they are in 16 bit, the R9009 value is completely wrong. As you can see from the watching windows, it is a 32 bit. What I can do? Where I'm wrong?

This is the PLC watching windows
And this is node-red

This isn't an error on any part of your system. MODBUS is a tricky protocol when using anything other than standard integers, enumeration or simple character values. Floats and doubles are especially tricky. There are things you'll need to know about your specicific and individual system such as is it a LSB (least significant bit) or MSB (most significant byte)? LE (little Endian) or BE (big Endian)? This makes a huge difference and varies by manufacturer AND how it's configured. MODBUS will read one byte per register and return it. You can see this in your return stream represented as a pair of hex values in the spot for the return data, if you were able to readout the return stream. Fortunately, the MODBUS nodes take care of this for you.

Here's the tricky part. Since you're trying to read a 32 bit (4 byte) register, you're going to need to readout four bytes. The MODBUS node will automatically read two for an individual register, either because the node itself just takes care of this or because your module sends back two bytes, I don't know. But you'll get half your value doing this. You've already compensated by requesting a quantity of 3 (number of registers including the requested register), which is getting you your full register set plus possibly another register you don't need (you should only need four hex values for a full 32bit return, you have six). Perhaps your controller needs the extra, I don't know. That aside, this is where the tricky comes in. In order to get the ACTUAL value in human form, you have to put together the buffer values in the right order. For instance, I have some MODBUS modules I get complex values from. The way my module returns the values is backwards from how they would normally be organized. Here's how I have to parse my data to read it in human form:

    var temp = Buffer.alloc(4);
    temp[0] = msg.payload.buffer[2];
    temp[1] = msg.payload.buffer[3];
    temp[2] = msg.payload.buffer[0];
    temp[3] = msg.payload.buffer[1];
    setTemp = temp.readFloatBE();

The steps are I have to allocate a four byte buffer, place each component of msg.buffer into the currect order in my temp variable, then convert the reorganized using a Big Endian float converter and store it in a normal variable. Now, this is old code and done during my less experienced years. There are most likely ways of cleaning this up or possibly doing it natively I just haven't researched yet. But it gives you the idea. Once you figure out what registers you need to read and what order they need to be in, simply reorganize the data and make it human readable. That's the last steps you're missing from what I can see.

node-red-contrib-buffer-parser makes all your data conversions simple and no-code

It can be a bit overwhelming due to the extensive capability but it has built-in examples (that you can access via ctrl-i) built-in help & tons of threads/success stories on the forum showing how data in a buffer can be manipulated into strings, booleans, 32-bit same floating point, unsigned 64 bit etc, etc etc.

Thanks @madhouse, the problem is a bit different.

No, I haven't compensate it. I just show it to better make understanding the result I got from the node compared with what I need, as directly read from the PLC. The problem is that the value is just stored into a single register, but it's bigger than 16 bit. While the node expects and treat each register returned as 16 bit. I cannot use 2 consecutive registers since they store different information. Practically R9008 is a metric, R9009 is a different metric, R9010 is another different metric

Thanks @Steve-Mcl, I had a look at node-red-contrib-buffer-parser documentation and examples, but It doesn't seem to help me for what I understand. As you can see from the debug screenshot, the register the modbus node pass forward is a 16 bit. LSB, MSB, LE or BE are the following step problem, butI have this info from the SAIA documentation, so actually I'm not that worry about it. The main problem now is that the modbus node seems to treat each register as a 16bit one by default, but they are bigger

Modbus register's are always 16bit.

I agree it looks odd. I can see the values of the registers above and below are as you expect.

It may be that the PLC in question simply allows a kind of "compatibility" means of modbus access to that particular memory bank but when it holds a 32bit value, it drops the first 16 bits. I don't know that PLC or its memory addressing. This is a question for the PLC technical support I guess.

Thanks, I'll follow your suggestion. I hope to be able to solve it and let you know the solution

Thanks for that Steve. That's what I was trying to explain but couldn't get it to come out right.

@Lupin_III, what Steve says it's right. Your controller is setup a certain way. I've seen other controllers do the same. It's called a relative address. Other manufacturers might call it something different, but it all means the same thing. Relative to the first addressable register, the one you want is X registers beyond that. Some manufacturers might number them by the item number, meaning each item is 1 higher than there last regardless of size. Other manufacturers might use byte position in the addressable register space. So each byte gets a register value regardless of if it is a complete value or a partial. In each case, there can be program memory or other non-addressable mixed in the middle. If you were to see the absolute addresses, you could see the mix of addressable and non-addressable memory. It looks like your manufacturer uses a relative system of each value gets one address space.

As Steve said, MODBUS the standard defines a register as 16 bits. That's the standard. If a controller has an eight bit value in it's register, it should be programmed to pad the other eight bits in the return. If you request a specific register and it uses more than 16 bits, you tell it there quantity so the controller returns the additional bits. This is how MODBUS the standard works. Most manufacturers generally have a manual specific to their implementation of the standard so you know how to handle it. I've had a few and while the implementation will be different in how you request and parse the return, the standard is always the same. That's where Steve's suggestion comes in of checking with tech support. See if they have a MODBUS specific manual for your PLC. That should help with most of your questions.

Yes, I wrote to technical support. Let's see what they say. Thanks so much

OK, I spoke with support and they explained to me that the registers are natively 32 bit. So I need a modbus client that support 32bit, not the 16bit as the standard ones. Now, do you have any idea if there is some node that can help me? I don't think I'm able to build a dedicated node for this stuff.
Thanks so much

Unless they have used a custom function, there is something not quite right about what they say.

The modbus specification is clear. Data access is 16 bit ..

This is fine and will not inhibit your MODBUS experience in any way. I work with several 32 bit registers in my stuff with no issue. The MODBUS will still work and do its job just fine. In fact, the only thing you could find to do 32 bit is a MODBUS software that includes the conversions you would need, which JavaScript can do. If every register is 32 bit, what will happen is that when you request a single register, you'll get a double return (array off four single byte buffers instead of two). This is not a problem and can be easily worked with.

But that still doesn't give you what you need. You'll need a list of the registers and how they are stored so you know what they look like. You also need to know how they're being returned (little Endian vs. big Endian, LSB, MSB etc.) so you know how to decode them. These small nuances can make it break a MODBUS setup. As you can see in your original example, you have 9008, 9009 and 9010. The values it comes up with mean nothing to me thinking of inverter parameters I would want to monitor. But if I rearrange the buffers and do a float conversion, 466b303c in big Endian comes out to 0.0107678, which could easily be a percentage value. But I don't know for sure because I don't have a definition.

Make sense? You're still getting all your data with your current setup. Nothing is lost. Now you just need to put the pieces together the right way. This setup will work for you. You just have to tell it how. Which requires you knowing how as well.

1 Like

Thanks so much guys for your support
@Steve-Mcl Even to me it seemed strange but they assure me that all register are 32 bit, no special function. I don't know what to say. It's an SBC SAIA - PCD2.M5540 model
@madhouse I don't understand what you mean, sorry. Looking at the example:
9008 is the address of a register
9009 is the address of another register
9010 is another one
and in each of them there is a value that I need. So, 3 different values in 3 consecutive registers. If you look at the debug, the buffer I get is a 16 bit for each register. When you put togheter the buffers, you put togheter the values of different registers:
9008 --> 466b
9009 --> 303c
9010 --> 86da
if you put together 466b303c you put together the registers 9008 and 9009 getting one value. But I need the 32bit value of 9008 and the 32 bit value of 9009

@madhouse I think you might be confusing matters.

As far as I can see, the PLC registers are 32 bit BUT the manufacture has permitted ModBus access to them in an address-for-address alignment. What I mean is...

PLC Reg PLC Value Modbus Reg Modbus Value Notes
R9008 18027 9008 18027 Address and value match :white_check_mark:
Both values are 16 bit :white_check_mark:
R9009 143420 9009 12348 value is truncated & the next byte is utilised by ModBos reg 9009
R9010 34522 9010 34522 Address and value match :white_check_mark:
Both values are 16 bit :white_check_mark:

To further prove the value returned for R9009 is truncated...

143420 == 100011000000111100

32bit: 0000 0000  0000 0010 0011 0000 0011 1100
16bit:                      0011 0000 0011 1100  (truncated)

0011 0000 0011 1100 === 12348



I would contact tech support again.

Yes @Steve-Mcl , it's exactly the test I made even on other registers. It works exactly as you have described. And I discussed with the support wiht these example. For them it's normal and correct: since modbus standard is 16 bit while they're registers are 32 bit, 16 bit are truncated. That's way they required a 32bit client. But I'm making reserch and I cannot find anything like this. Calling and writeing to the technical support I always speak with the same person, so there is no way to go further. My only hope I have is to find someone here that know this kind of PLC

This is nonsense. If you wireshark the network for an FC03 or FC04 ModBus function Req/Resp, you will see the format of data - it can NEVER hold 32 bit data. Never! Not without breaking the specification.

There is no flag or marker in the ModBus packet to request 32bit data!

From the official specification...


6.3 03 (0x03) Read Holding Registers

This function code is used to read the contents of a contiguous block of holding registers in a
remote device. The Request PDU specifies the starting register address and the number of
registers. In the PDU Registers are addressed starting at zero. Therefore registers numbered
1-16 are addressed as 0-15.
The register data in the response message are packed as two bytes per register, with the
binary contents right justified within each byte. For each register, the first byte contains the
high order bits and the second contains the low order bits

The important part being The register data in the response message are packed as two bytes per register

If they REALLY do support 32bit values they must do it via a custom hack or a custom FC function number.

Can tech support how tell you how to read the values using modbus? Some particular software that will do it for example?

Rewrite these 3 32 bit registers to another area of PLC memory as 6 16 bit, then Modbus will read them, and in Node-RED you will put them together in 32 bit value.

Probably. This isn't a very straightforward matter and it's not making sense in general. I know what I'm trying to say but it's probably not coming across the way I intended. Apologies for those who are getting confused.

But I stand by it.

And I think I've found what may break this case loose.

@Steve-Mcl, you and I have been right this whole time about MODBUS being 16 bit returns. The spec can't be broken and there isn't a way to get 32 bit values without requesting more registers.

@Lupin_III, you really need to get support to get you a list of MODBUS registers. What you have is not a list of MODBUS registers. You have a list of SAIA data registers. Registers, I might add, that are not intended for MODBUS to use. Let me explain.

I did a little more digging and found a post with the same/similar question here. The answer that came across pointed to a document that, while not specific to your particular module, should apply broadly to much of Saia's inventory as it will be somewhat their standard of implementation. In that document it specifies that the MODBUS registers are mapped to the Saia registers and are not one in the same. You will use the mapped MODBUS address to access the data in the Saia address. The MODBUS address are all setup as 16 bit register counts where one MODBUS address will map to half of a single Saia address, with two MODBUS addresses required to access the full Saia address.

This is how you get your full data.

If you can't get a list of mapped addresses or you somehow hit a dead end, I have another suggestion that came from Steve. Probably without him realizing it.

(emphasis added)

And I might add you should also see the requested MODBUS addresses being requested for your individual registers. You have the program Saia built to interface with their module. So someone has knowledge on those addresses so that they could build the program. There is one slight caveat...

The unit also communicates over open TCP, which might make it look like you're pulling MODBUS data, but in reality they're just accessing the Saia registers directly through TCP and pulling it, circumventing the MODBUS protocol entirely. At which point, a Wireshark capture will give you absolutely nothing.

Unless you use a TCP request node in Node-Red and bypass the MODBUS node. Which may prove easier than getting the MODBUS information you need.

In any case, you really need that list of MODBUS registers and how they're mapped in order to make this work. Because without it, I don't think you'll get anywhere with MODBUS at all.

1 Like

Thanks so much to all for your help. After several call and speaking with different guy at the technical support, even thanks to the document in the previous post, the problem is exactly this. The registers I'm tryig to read are "propetary" registers, mapped in their own standard, let's say.
So now, looking within the code, I have to understand how these registers are linked the "standard ones" that allow modbus protocol . I even have the source code, but I'm not expert on this PLC, so at this point I have to find someone that knows it and that can help me to find the correct registers to read.