Author Topic: Modbus RTU familiarisation  (Read 6693 times)

0 Members and 1 Guest are viewing this topic.

Offline 741Topic starter

  • Frequent Contributor
  • **
  • Posts: 386
  • Country: gb
    • Circuit & PCB Design (small PCB quantities OK)
Modbus RTU familiarisation
« on: December 13, 2022, 10:41:01 am »
I'm trying to re-familiarise myself with modbus RTU. I came across this site (https://ipc2u.com/articles/knowledge-base/modbus-rtu-made-simple-with-detailed-descriptions-and-examples/) which seems a nicely presented learning resource. However I'm almost immediately unsure of various points from the first example.
 
They say
   The following is an example of a Modbus RTU request for obtaining the AI value of the holding registers from registers # 40108 to 40110 with the address of the device 17
To me, AI means/suggests "Analog Input", which is at odds with the 4x addresses.
 
The example request is 11 03 006B 0003 7687, and it is shown that
    006B   The address of the first register (40108-40001 = 107 = 6B hex)

By "first register" I assume that means "first register in this request". What really bothers me is this, in the response analysis we have lines such as this -
    AE   The value of the upper register bit (AE hex)   Register value Hi (AO0)
   
I don't get the description "upper register bit" (should that be "byte" ?).

Also I fail to see the "Register value Hi (AO0)" part. I can accept that the first holding register actually implemented might lie at an offset of 0x6B from 40001. I can believe (but I am not sure) that in this case, offset 0x6B is associated with the first "AO" (Analog out) register. In that case (?) maybe we'd say that logically "AO0" <--> offset 0x6B.

However they have only just stated
   the first register of AO Holding Register has the number 40001, but its address is 0000
a few lines above.
« Last Edit: December 13, 2022, 10:43:59 am by 741 »
 

Online peter-h

  • Super Contributor
  • ***
  • Posts: 3728
  • Country: gb
  • Doing electronics since the 1960s...
Re: Modbus RTU familiarisation
« Reply #1 on: December 15, 2022, 11:35:02 am »
The reason you aren't getting any responses is because anybody doing Modbus work is getting paid by his employer and is not allowed to post about work stuff :)

I have done a fair bit of Modbus code over the years but not recently, so I can't help you much, but I do know that there are few conventions on data representation using Modbus. You can basically choose what you want and which registers to store it in. Then there are representations for integers, floats, binary or textual data, etc.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4235
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: Modbus RTU familiarisation
« Reply #2 on: December 15, 2022, 11:57:08 am »
I get paid to do Modbus, but there's really no reason I'd touch it otherwise. I dislike it for various reasons, some ideological, others practical.

Register addressing is just one of those reasons. The number described as a "register address" in the range 4xxxx (for example) never actually appears on the wire at all, it's a totally unnecessary, confusing misnomer, designed to arbitrarily inflate the amount of time required to implement a Modbus interface by introducing off-by-one errors at every possible opportunity.

If you want to read a register in that range, then what you actually do is read from address (n - 40001) using function code 3, which means "read a register in the 4xxxx range". So, for example, to read "register address" 40003, the address on the wire is actually 0002, and the offset of 40001 is simply implied by using the correct function code.


Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8185
  • Country: fi
Re: Modbus RTU familiarisation
« Reply #3 on: December 15, 2022, 12:33:16 pm »
Modbus is an extremely simple and sensible thing in essence.

It's just arbitrarily made a mess by stupid conventions like having TWO different addressing systems which are off-by-one, having shitload of weird legacy message types, and also by all the gazillion devices which do things a bit differently.

I have never been able to write anything modbus related by reading standards or documentation. They give you a starting point, but real work is done by having the devices physically and reverse-engineering what they do.

That said, in 90% of cases you can't even get documentation, just black boxes with manufacturers refusing to support their shit, so you have to reverse-engineer anyway. Not that it matters, it's probably better that way, less time spent reading crappy documents.

It's a pity given there is no rocket science involved and the underlying protocol is fine. Documentation should fit on one page.

Just extremely stupid and nasty people, with legacy of toxicly stupid engineering culture.

And beware, many devices you would expect to be MODBUS RTU devices - sometimes even incorrectly called MODBUS by manufacturer's marketing team, are actually just any random NIH RS485 protocol. Sometimes much better, sometimes much worse than MODBUS RTU.
« Last Edit: December 15, 2022, 12:37:08 pm by Siwastaja »
 

Online peter-h

  • Super Contributor
  • ***
  • Posts: 3728
  • Country: gb
  • Doing electronics since the 1960s...
Re: Modbus RTU familiarisation
« Reply #4 on: December 15, 2022, 02:55:21 pm »
Modbus is standard because every Scada system has a script language for parsing the registers values and converting them to whatever format you want. People in industrial control are pretty well used to this. They don't need to get involved with the bytes in the packet.

It is probably better than a thousand proprietary protocols, some ASCII, some binary...

At work we do lots of custom Modbus-whatever converters and we always have to borrow an item of the customer's equipment to test it with because it is normally impossible to write it from a spec. But that's actually true for most protocols... there is usually some ambiguity.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8185
  • Country: fi
Re: Modbus RTU familiarisation
« Reply #5 on: December 15, 2022, 04:01:05 pm »
Modbus is standard because every Scada system has a script language for parsing the registers values and converting them to whatever format you want. People in industrial control are pretty well used to this. They don't need to get involved with the bytes in the packet.

Of course, but most of the protocol weirdness "leaks" to the higher levels.

This is why every automation electrician knows how to configure any automation device to output some test value in different test register address, using different endianness options, so that other automation electrician can check with the other device if communication fails or not. And they still need to configure data types, register addresses, and the same off-by-one confusion exists. They still have to deal with MODBUS return codes when things fail.

The bit-level mapping is just a tiny detail and quite obvious.

It is probably better than a thousand proprietary protocols, some ASCII, some binary...

Usually yes, if at all possible. Despite the shortcomings, the benefit of Modbus over custom RS485 communication is simple: multiple devices can live on the same bus and happily ignore each other. It so happens that we are ramping up production on a design which communicates with existing RS485 devices in household and light industrial applications. My example case has four RS485 devices: solar inverter, EV charging station, air-to-water heat pump, heat recovery air ventilator. Only one of them is Modbus RTU (the ventilator), others are all custom NIH RS485, and while they have similar master-slave communication to Modbus RTU, with some kind of addressing and polling, no one knows (or can prove) if they are able to ignore the messages produced by the different devices; they are designed to operate with the manufacturer's own "master box". This is also why I designed this otherwise quite small and low-cost device with two RS485 buses, despite the fact that significant % of customers never use either. So blame me for stockpiling all your RS485 transceivers!
« Last Edit: December 15, 2022, 04:03:54 pm by Siwastaja »
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4235
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: Modbus RTU familiarisation
« Reply #6 on: December 15, 2022, 05:17:46 pm »
Part of the problem with Modbus is that it doesn't specify nearly enough.

The gap between messages must be at least 3.5 character times. This is a well defined, unambiguous feature that all devices on the bus can agree on, even if it's a pain to implement because it requires both a UART and a timer, and a device driver that coordinates the two in a coherent way. It's OK. Difficult is OK if it means the end product is more reliable and easier to use.

But, the spec also recommends that devices use even parity as a default. WTF? What's wrong with prescribing that every device must use even parity? Why allow the ambiguity?

Registers are defined to always be 16 bits wide. That's OK. But how on earth can a specification worthy of the name then NOT prescribe whether it's LSB first or MSB first?

It allows for registers to be combined into 32 bit ints or floats... fine. But again, it fails to specify which byte is which, so there's at least 4 different vaguely sensible ways to transfer a simple 32 bit value from one device to another, with probing and random byte swapping being the only real way to make both master and slave agree on one of them. Why?

My other major gripe is that replies from a slave have the exact same data format as requests from a master, so it's impossible to tell the difference just by looking at the message. At the very least, couldn't the response have the top bit of the function code set to indicate "this is a response to..."? Why doesn't the master have a unique ID of its own?

And who thought it was a good idea for replies not to include any kind of context? The master always has to remember the last request issued, because responses from slave devices are just a string of numbers - there's no way to know what those numbers mean without looking back to see what the last request was. Even a unique sequence number - one byte! - would at least allow the master to confirm that the numbers being sent do actually relate to a specific numbered request. (Imagine a scenario... "M: What's our altitude?" ... <long delay> ... "M: What's our fuel level?" ... "S:<7E 29 00 01>")

 
The following users thanked this post: Siwastaja

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8185
  • Country: fi
Re: Modbus RTU familiarisation
« Reply #7 on: December 15, 2022, 07:14:45 pm »
The gap between messages must be at least 3.5 character times. This is a well defined, unambiguous feature that all devices on the bus can agree on, even if it's a pain to implement because it requires both a UART and a timer, and a device driver that coordinates the two in a coherent way. It's OK. Difficult is OK if it means the end product is more reliable and easier to use.

This causes colossal pain when trying to interface modbus devices through general purpose operating systems and UART adapters.

When actually designing a MODBUS device (master or slave), with a microcontroller for example, this is all trivial and IMHO a very good strategy. In 1979, they probably did not think about how bloated all OS abstractions will be 40 years later, and how difficult it will be to do a few even approximately timed IO operations.

Quote
It allows for registers to be combined into 32 bit ints or floats... fine. But again, it fails to specify which byte is which, so there's at least 4 different vaguely sensible ways to transfer a simple 32 bit value from one device to another, with probing and random byte swapping being the only real way to make both master and slave agree on one of them. Why?

It is indeed hilarious how automation electricians who normally install wiring and so on, have to configure these test registers and probe for the correct byte order without being any kind of computer scientists/engineers at all, I have witnessed this happening. Talk about low level leaking into higher abstractions!

Quote
And who thought it was a good idea for replies not to include any kind of context? The master always has to remember the last request issued, because responses from slave devices are just a string of numbers - there's no way to know what those numbers mean without looking back to see what the last request was. Even a unique sequence number - one byte! - would at least allow the master to confirm that the numbers being sent do actually relate to a specific numbered request. (Imagine a scenario... "M: What's our altitude?" ... <long delay> ... "M: What's our fuel level?" ... "S:<7E 29 00 01>")

Modbus is an ancient protocol, implemented on ancient devices, so the idea was probably: reply is a simple register read and comes immediately after the poll, otherwise master times out, and slave will not reply after a certain time, so mixup can't happen. The problem is, this idea, or timeout value was not specified. When given maximum turn-around time (time until slave activates the RS485 TXEN and sends start bit) like 1 millisecond, no such problem would exist, and then everything would be simple, no need to add the context id and compare it. But as you say, they did not feel like specifying pretty much anything.

I can totally see engineers at Schneider or whoever it was trying to write a proper specification and then manager types going like... "no, that is too verbose, remove that, no, don't say that, that doesn't sound cool!"
 
The following users thanked this post: AndyC_772

Online peter-h

  • Super Contributor
  • ***
  • Posts: 3728
  • Country: gb
  • Doing electronics since the 1960s...
Re: Modbus RTU familiarisation
« Reply #8 on: December 16, 2022, 04:55:39 pm »
Quote
The gap between messages must be at least 3.5 character times

I am told this is unimplemented (disregarded) in most of today's instruments.

Don't know if it is true, but would for sure make Modbus over TCP much easier. Currently, a proper implementation needs to have timeouts to detect the end of data (or parse the protocol) and pack a Modbus packet into one MTU. Or if it doesn't fit, reassemble them at the far end (and there is a spec for that, IIRC).
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3385
  • Country: nl
Re: Modbus RTU familiarisation
« Reply #9 on: December 17, 2022, 12:01:29 am »
If the mandatory gap between messages is ignored by both nodes, it may still be subject to hardware. For example, in RS485 repeaters it is quite common to create the "Driver Enable" signal from the incoming data and extend it with a simple RC combination with an extra diode over the resistor.

See for example the implementation below, which I found somewhere in the internet. That schematic is not for a repeater, but for a uC which does not handle the driver enable signal actively.
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1329
Re: Modbus RTU familiarisation
« Reply #10 on: December 17, 2022, 01:46:19 am »
I wrote some code for MODBUS RTU on a PIC Micro several years ago, I did both ends (Master and Slave) was interesting.... I had been given a large PDF document with protocol information in, included MODBUS TCP which I don't recall being too different to RTU, and a couple of simulators (some professional MODBUS suite written by a German company IIRC), a week of experimenting and then wrote the final code, it was fairly straight forward from what I can remember (not a lot these days!)
 

Offline Perkele

  • Regular Contributor
  • *
  • Posts: 52
  • Country: ie
Re: Modbus RTU familiarisation
« Reply #11 on: December 17, 2022, 08:18:58 pm »
Modbus is just a simple master/slave protocol.
That tutorial is a bit messy, their example looks like a MODICON device.
https://www.modbus.org/docs/PI_MBUS_300.pdf
Ignore it and find a better learning resource.

Go here:
https://en.wikipedia.org/wiki/Modbus#Modbus_object_types
The part that will probably be of interest to you is:
"Under the current standard the address can be 0 - 65535 with the object type identified by the command used to read or write the coil or register."
Read the rest of that page from beginning to the end.
Then download the official specification and read it thoroughly.
https://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf

Go here:
https://www.simplymodbus.ca/FAQ.htm
On the left side there are "fc" links. Go through all of them.

If you need some kind of tool to quickly communicate with a slave, most of tools on Modbus website are obsolete, limited or non-free.
https://modbus.org/tech.php
Ignore them.
Download something like QModbus (or any other free tool) and start playing with it.
https://github.com/ed-chemnitz/qmodbus/releases/tag/v0.3.0
It has a couple of glitches with huge messages because you can't set the timeouts without modifying the source and recompiling the application. But I'm seeing those issues when reading/writing more than 120 registers in one request.

Good luck.
 
The following users thanked this post: 741

Online H.O

  • Frequent Contributor
  • **
  • Posts: 821
  • Country: se
Re: Modbus RTU familiarisation
« Reply #12 on: December 20, 2022, 12:08:28 pm »
...
Registers are defined to always be 16 bits wide. That's OK. But how on earth can a specification worthy of the name then NOT prescribe whether it's LSB first or MSB first?
...


In the MODBUS Application Protocol v1.1 dated 2006 one can read:
Quote
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.

I don't know if that sentence dates back to the original specification from '79 or if it has been added later but at least it IS there now.

What bit me when I implemented MODBUS RTU is that the CRC field, unlike data, is sent low byte first...
I have since then used that same code interfacing to devices where I've had to again swap this so I know for a fact that I'm not alone in making that mistake.

Standards... :-)
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8185
  • Country: fi
Re: Modbus RTU familiarisation
« Reply #13 on: December 20, 2022, 12:49:22 pm »
Quote
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.

I don't know if that sentence dates back to the original specification from '79 or if it has been added later but at least it IS there now.

Read more carefully. The quoted part does not specify whether bits are sent on the wire MSbit or LSbit first. Both are viable options.

But at least they specified half of the 16->8 encoding, so there are only two options. With multi-register values (like floats, uint32 etc.), this becomes four different possibilities. Without the text you quoted, that would be 8!
 

Online H.O

  • Frequent Contributor
  • **
  • Posts: 821
  • Country: se
Re: Modbus RTU familiarisation
« Reply #14 on: December 20, 2022, 01:17:05 pm »
Quote
Read more carefully. The quoted part does not specify whether bits are sent on the wire MSbit or LSbit first. Both are viable options.

Fair enough.
Modbus Serial Line Protocol and Implementation Guide V1.02:

Quote
2.5.1 RTU Transmission Mode
When devices communicate on a MODBUS serial line using the RTU (Remote Terminal Unit) mode, each 8–bit byte in a message
contains two 4–bit hexadecimal characters. The main advantage of this mode is that its greater character density allows better data
throughput than ASCII mode for the same baud rate. Each message must be transmitted in a continuous stream of characters.
The format ( 11 bits ) for each byte in RTU mode is :
Coding System: 8–bit binary
Bits per Byte: 1 start bit
8 data bits, least significant bit sent first
1 bit for parity completion
1 stop bit
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21732
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: Modbus RTU familiarisation
« Reply #15 on: December 20, 2022, 01:45:39 pm »
I went through this semi-recently.  I used:
FreeModbus: https://github.com/T3sl4co1l/freemodbus (this branch runs on AVR-DA and easily adapts to other AVRs; check under /demo/AVR)
Local testing: generic isolated RS485 USB adapter (FTDI based); pyModbus https://pymodbus.readthedocs.io/en/v2.5.3/source/library/modules.html
Client interface: RTU to TCP gateway e.g. https://www.pusr.com/support/downloads/usr-dr302-user-manual

I think there is some confusion about "what's on the wire".  The standard is here:
https://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf
What's transmitted is simply what goes into the packet.  What you put into it, and what a device reads that as, is implementation defined -- free to choose as you like.

This is most obvious in this source -- a low level implementation which basically returns the packet contents to your callback functions.  I mean not that there's a lot to it anyway, it's a very simple protocol.

From what I've seen, there are, or have been, implementations, or maybe just traditions, of putting addresses for certain functions in certain ranges.  This isn't required by the standard, you can use independent address spaces per function code if you like.  Likewise the off-by-one is optional, you either get the address verbatim or add or subtract one (as the case may be) if you like.

The addresses match between what's in my code (e.g. 40001) and what's in the .py script (40001), and as far as I know, my client didn't have any problems with it (they didn't mention if there was an off-by-one on their end).

If you need better familiarity or certainty, maybe look up some other devices and see how they do it, get a feel for the ecosystem.  At worst, call up an industry expert (ask the org?) and get some industrial-grade review/certification done?

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Online woody

  • Frequent Contributor
  • **
  • Posts: 293
  • Country: nl
Re: Modbus RTU familiarisation
« Reply #16 on: December 20, 2022, 02:21:07 pm »
I found that

https://www.modbustools.com/modbus.html

helped me a lot in understanding Modbus. On this site they sell tools that simulate Modbus master / slave devices.

I started out using https://sourceforge.net/projects/qmodmaster/ which is free and quite nice, but in the end I also got Modbus Poll which offered features like the ability to load/save workspaces that came in handy.

I have no connection to either sw supplier but I had a nice support experience with Witte Software.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8185
  • Country: fi
Re: Modbus RTU familiarisation
« Reply #17 on: December 20, 2022, 02:23:47 pm »
Quote
2.5.1 RTU Transmission Mode
When devices communicate on a MODBUS serial line using the RTU (Remote Terminal Unit) mode, each 8–bit byte in a message
contains two 4–bit hexadecimal characters. The main advantage of this mode is that its greater character density allows better data
throughput than ASCII mode for the same baud rate.

What the actual ****. Who writes bullshit specifications like this?

What an unbelievably convoluted way to call a bog standard 8-bit binary number "containing two 4-bit hexadecimal characters". Characters?

This screams some manager having written the spec, instead of engineers; a manager who does not understand the normal binary communication at all, but remembers seeing hexadecimal representation of it on the screen. When a normal sane engineer reads this, no wonder they get confused.

But you are right - the order is specified there. Maybe AndyC remembers wrong, or maybe the standard has been modified. I don't know, but I do know that different bit orders are a thing, so if it was in the standard all along, then people implementing it have failed to follow the standard. Possibly because the standard is filled up with nonsense like "hexadecimal characters".
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4235
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: Modbus RTU familiarisation
« Reply #18 on: December 20, 2022, 02:43:35 pm »
Maybe AndyC remembers wrong

Never!!

(Well, almost...  :'( )

I've been using a development tool (master device emulator) by Simply Modbus, which has buttons in the UI to swap the byte order in various ways. I was rather hoping that the standard itself would have been prescriptive enough to make these buttons unnecessary, and indeed, downright hazardous for someone trying to develop a compliant device.

Then again, I often find myself hoping for things that turn out not to happen.

Offline gmb42

  • Frequent Contributor
  • **
  • Posts: 294
  • Country: gb
Re: Modbus RTU familiarisation
« Reply #19 on: December 21, 2022, 11:54:48 am »
After writing Modbus software for nearly 30 years I'm never surprised at how many ways folks find to ignore the protocol specification (which isn't great to begin with) and use all sorts of byte and bit orders along with many variants of combining registers to handle fixed\floating point or string values.

The general approach (from the master side) is to have sufficient parameters to handle whatever comes out of the PLC as its usually seen as easier to modify master code than PLC code.

Even more fun when using the more complicated SCADA protocols such as DNP3, IEC 60870-5 and OPC UA and major PLC manufacturers refuse to accept their implementation fails to meet the (voluminous) specifications (MicroLogix ML1400 with DNP3 I'm looking at you) and you have that discussion with the system operator that they need to either replace their PLC's with protocol compliant ones or pay you to modify your code to work around non-compliant devices.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf