Modbus holding and input registers differentiation

Hello,

I am learning about the MODBUS registers mapping and then how can I read the data out of them. Attached is a communication protocol of an energy meter. What I learned is that holding registers are R/W registers and function code 3 is used to read and 6 is used to write the registers.

Input registers are read-only and function code 4 is used to read them.

So, on page number 21 of the communcation protocol, the registers 253-254 contains the low and high byte of the active power of phase A. And the registers description is marked as RO. So, if it is read-only then it means it should be the input register and not the holding register. However, I can read the power value out of them using the code:

float readPower_L1() {
  float watt = 0;
  if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x00FD, 2)) {           // make the call to the register
    Serial.print("failed to read power! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    int16_t word1 = ModbusRTUClient.read();                                         // read data from the buffer
    int16_t word2 = ModbusRTUClient.read();
    int32_t WATT = word1 << 16 | word2;                                             // bit math
    watt = WATT;
  }
  return watt;
}

Where the code says to request the data from the holding registers, mean using function code 3. So, if the registers are RO (that means Input Registers) then how come the function HOLDING_REGISTERS works? I think it should have been INPUT_REGISTERS instead. Or if I am misunderstanding it? Can the Holding Registers also be made as RO? Looking forward to kind assistance.

Thank you

The standard doesn't say that a holding register must not be read only. It defines that an input register must be read only as it doesn't have a function code to read these registers.
If the manufacturer implemented Modbus correctly it should have allowed a write to this register although it might have absolutely no effect. I'm not aware of a device that actually uses the input register concept, usually all integer registers are holding registers, no matter if a write to them makes sense or not.

Did you mean to say that Input registers don't have a function code to WRITE these registers?

Ok, so what I understood is that even those registers that I mentioned are the Holding Registers but they need to be read-only and not write. But what would happen if I try to write these RO registers? Will I get an exception code?

Secondly, when Holding registers can manage read and write then why do we need the input registers in the first place? And what I don't understand that if Input Registers can't be written, then how and who can write them? How can they hold values?

Yes.

That depends on the interpretation of the standard by the manufacturer of your device. I would expect it to accept the write but that write is a NOP. But your device's manufacturer may have decided otherwise.

You can ask that question for all register types. Theoretically the holding registers would be enough. I guess the original developer of the protocol had a specific type of devices in mind and these had to handle stuff differently. The protocol was developed in a time when many devices didn't have a general MCU for this.

The device itself. Just because you cannot write them by Modbus doesn't mean that their value must be constant.

Thank you for simple explanations.

Regarding the input register, you mentioned that device itself can write them although they can't be written via Modbus. In terms of Arduino, can you please give me an example that how could Arduino MCU write these registers? That's the only thing that I need to learn and understand that how can input registers and input coils are written.

Think of a switch connected to an input pin. The modbus device needs to determine the state of the switch (open or closed), and then write that value to the register for you to read later. You can't write to the register as that makes no sense - i.e. you can't alter the switch position via software.

Yes, thank you. So, let's say I take a digital pin on Arduino and a switch is connected to it. It will be either open or closed. So, how can be this written to a register? I mean what would be syntex in the software? And if another device communicates, can only read it and can't write it, I understood that.

I wonder if there may be a bit of confusion over who/what is doing the "writing".

In the case of, say, an Arduino UNO with the ATMEGA328P micro, then without going into too much detail, there isn't any writing as such. When your code wants to check the status (open/closed) of the switch, you call the digitalRead() function. The code behind that function goes off and reads the contents of the appropriate PIN register inside the 328p.

I am currently learning and implementing the Modbus so therefore, I have some of these confusions.
As an example, I have an Arduino MKR Zero with Ethernet shield and then I am working on this sketch:

#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoRS485.h>                                                 // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>


// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network.
byte mac[] = {0xAA, 0x01, 0x22, 0xA1, 0xB1, 0x06};
IPAddress ip(192, 168, 178, 92);

EthernetServer server(502);
ModbusTCPServer modbusTCPServer;
int i = 0;

void setup() {
  // You can use Ethernet.init(pin) to configure the CS pin
  Ethernet.init(5);   // MKR ETH shield
  pinMode(LED, OUTPUT);
  
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);

  Ethernet.begin(mac, ip);                                                    // initialize the ethernet device

  Serial.begin(9600);
  //while (!Serial) { }

  if (Ethernet.hardwareStatus() == EthernetNoHardware) {                  // Check for Ethernet hardware present
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
  }

  while (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  server.begin();                                                         // start listening for clients

  Serial.print("Modbus server address: ");
  Serial.println(Ethernet.localIP());

  if (!modbusTCPServer.begin()) {                                         // start the Modbus TCP server
    Serial.println("Failed to start Modbus TCP Server!");
  }

  // configure a single coil at address 0x00 and 10 registers from address 0x00
  modbusTCPServer.configureCoils(0x00, 1);
  modbusTCPServer.configureHoldingRegisters(0x00, 10);

}

void loop() {

  EthernetClient client = server.available();                              // wait for a new client
  if (client) {
    Serial.println("new client");                             // a new client connected
    modbusTCPServer.accept(client);     
    
    // let the Modbus TCP accept the connection
    if (client.connected()) {
      modbusTCPServer.poll();                                              // poll for Modbus TCP requests, while client connected
      measurement();                                                            // update the measured current
    }
    Serial.println("client disconnected");
  }

void measurement() {

  modbusTCPServer.holdingRegisterWrite(0, i);
  i++;
  delay(100);
}

And then on my PC, I using a software QModMaster to read this value. So, it starts with 0 and then go on. So, here I understand like I have taken a holding register and then using the syntex modbusTCPServer.holdingRegisterWrite(0, i); I am writing the incremented value of i on register 0. And like wise I can read the stored value on this register using another Arduino (Master) or a software on PC. Similarly, I can read a stored value on the input register say 1000. But actually how this value (1000) got stored there.

And the holding register 0, is it the same as 40001?

I don't know if I could explain my question in an understandable way or not. But I thank you for your understanding and patience.

This bit I can tell you about since initially it made no sense to me when I first discovered Modbus. I think a company called Modicon came up with the Modbus protocol. When you see addresses like 40001, that's an address written using the "Modicon convention".

I found this which may explain a bit more:

Register types and reference ranges recognized with Modicon notation are as follows:
0x = Coil = 00001-09999
1x = Discrete Input = 10001-19999
3x = Input Register = 30001-39999
4x = Holding Register = 40001-49999

Looking at the above, you can see that holding register 0 = address 40001, and holding register 1 = address 40002 etc. So if you saw address 30004 for example, you would know that it was referring to input register 3.

If your PC is reading from your MKR Zero board, then either your MKR Zero board code wrote 1000 to the register or the 1000 is maybe a default value or a random value because the register hasn't been initialised yet.

If you have a read only register on your MKR Zero, then I would suspect that it is read only from the point of view of the remote PC. Your MKR Zero obviously has to be able to write to the register in order to put a value in it.

By calling the inputRegisterWrite() method.

You must differentiate between the two Modbus roles: master and slave (RTU) or client and server (TCP). Your original question was for a master implementation, later you seamlessly changed to questions for a slave implementation without mentioning that.

Also doing anything by using the Modbus protocol and using a library that implements the Modbus protocol is not the same. Of course a library implementing the Modbus protocol slave must implement a way to write to an input register but even that write might be completely virtual as the value can be read from some hardware during the Modbus request without even storing that to a memory register actually. That doesn't work with the ArduinoModbus library you're using but other implementation might support this.

That depends on the interpretation of the addressing convention of the manufacturer of your Modbus device. The original convention just stated that some address ranges should be used for some register types only but the standard doesn't enforce that. So you can have a holding register and an input register both with address 14 and both having different values at the same time (at least the standard allows that).
Many implementations of the Modbus protocol especially by PLC manufacturers interpreted the convention so that holding register 0 has address 40001, so that if you ask for register 40001 the controller will send a request for holding register 0. This is wrong in my interpretation of the standard and the convention but what you experience in real life.

Thanks for the brief answer.

Ok, so the inputRegisterWrite() method actually works. I thought I would get an error, as writing the input registers is not allowed.

I am currently working on both RTU and TCP/IP simultaneously. And I think the read and write methods of registers is identical on both.

In the above sketch, I started with a holding register 0, and I stored a value there using the holdingRegisterWrite method. And then I read the value by the software on my PC QModMaster. To read the value from the Arduino, I did the settings on the QModMaster as: I gave the IP address of Arduino with port 502, then selected the option Reading Holding register 0x03, then the start address 1 (it only started with 1 and not 0), then the number of registers to read 1.

So, the software was able to read the data. Then I thought, if register 0 is 40001, the software could be able to read the data if I set the start address on the QModMaster software as 40001 but I got the error that address is illegal. Hence, the address 0 and address 40001 are not the same.

Thanks Mark,

No, the value of 1000 on input register was just an example.

What I meant there that if there is a value of 1000 on an input register, then where does the value 1000 on input register coming from as the input register are supposed to be read only and not written.

If a register is supposed to be read only, then I assume that is what the Modbus interface document for the device is saying. However, the device itself can write to the register - it has to in order to put the information into the register in the first place.

"Read only" is usually a description of a register when viewed/accessed from outside the chip or device.

Understood. Thank you.

The two addresses are never the same on the same device but you may experience that some manufacturers did it that or the other way.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.