Enhances Modbus documentation with detailed usage and configuration guidelines#89
Enhances Modbus documentation with detailed usage and configuration guidelines#89franz-hoepfinger-4diac wants to merge 10 commits intoeclipse-4diac:mainfrom
Conversation
Clarifies mandatory use cases for Slave ID in Modbus configurations. Introduces efficiency guidance for polling read addresses. Updates descriptions for flow control options in Modbus-RTU. Improves user understanding and configuration accuracy.
Expands the Modbus documentation to include a comprehensive explanation of function block configurations and data type mappings. Provides clear examples for various scenarios, improving user understanding of correct Modbus usage and embedding practices to avoid communication errors.
Updates documentation on the use of proper IEC data types to prevent communication errors in Modbus connections. Specifies mandatory use of exact byte-aligned types and explains potential issues with using types like BOOL due to compiler-specific implementations. Emphasizes accurate mapping between Modbus addresses and IEC data types for clarity in user configuration. Provides clarified configuration examples for common scenarios.
Adds explanation of triggering and cyclic behavior for Modbus function blocks, detailing rules for INIT and REQ events to ensure stable communication and optimal CPU load usage. Guides users on using pollFrequency for managing autonomous transactions and manual triggering requirements.
Clarifies autonomous polling behavior based on frequency value. Details behavior for reading and writing operations for clarity. Enhances understanding of Modbus configuration options. Implements improvements in documentation for better user guidance.
Clarifies the behavior of read operations with caching mechanism and emphasizes requirement of pollFrequency > 0 for receiving data. Explains independence of write operations from polling frequency to optimize performance. Relates to #doc
Includes cautionary note in documentation clarifying that setting pollFrequency to zero with readAddresses defined can cause high CPU load and network congestion. Advises keeping readAddresses empty to disable reading instead.
Documents upcoming functionality for 'single-shot' read behavior when pollFrequency is set to 0, improving clarity on expected future capabilities.
Introduces a code example demonstrating how to write outputs for an 8-output relay card using Modbus. Includes an illustrative image to aid understanding.
azoitl
left a comment
There was a problem hiding this comment.
Thanks for this great improvement. I found a few things that I think we should improve. Especially I think we should be more precise with the kind of client FBs and also that there should be some connections. As these are the classical starter problems.
One thing is if we should at right after the setup section that the modbus lib can only be used with client fbs. WDYT?
| *** A `REQ` event at the FB does **not** trigger a Modbus read; it only copies the current (cached) data to the outputs. | ||
| *** Therefore, to receive any data from the server, you **must** set a frequency > 0. | ||
| *** Successful updates from the server will automatically trigger a `CNF` event at the FB. | ||
| *** [CAUTION] **WARNING:** Do **not** set `pollFrequency` to `0` if you have `readAddresses` defined. Internally, a frequency of 0 is interpreted as "as fast as possible" (busy waiting). This will result in **100% CPU load** for the Modbus thread and flood your network/bus with requests. If you want to disable reading, leave `readAddresses` empty instead. |
There was a problem hiding this comment.
Asciidoc has the nice Admonition feature for this: https://docs.asciidoctor.org/asciidoc/latest/blocks/admonitions/
I would suggest to change to:
+
[WARNING]
====
Do **not** set `pollFrequency` to `0` if you have `readAddresses` defined. Internally, a frequency of 0 is interpreted as "as fast as possible" (busy waiting).
This will result in **100% CPU load** for the Modbus thread and flood your network/bus with requests.
If you want to disable reading, leave `readAddresses` empty instead.
====
+
[NOTE]
====
**Future Work:**
We are working on implementing a true "single-shot" read behavior for `pollFrequency = 0`, where a `REQ` event would trigger exactly one Modbus read.
This documentation will be updated once the feature is available.
====
| *** 'd' for discrete input (Read-only bits) | ||
| *** 'h' for holding register (Read/Write 16-bit words) | ||
| *** 'i' for input register (Read-only 16-bit words) | ||
| *** --> see below for a Detailed Table |
There was a problem hiding this comment.
| *** --> see below for a Detailed Table | |
| + | |
| -> see below for a Detailed Table | |
| + |
| ** **Requirement:** You **must** use 8-bit data types like **`BYTE`**, `SINT`, or `USINT`. | ||
| ** **Why not `BOOL`?** Internally, `libmodbus` represents each bit as a full `uint8_t` (1 byte). While `BOOL` might work on some systems, the C++ size of `bool` is implementation-defined. If your compiler uses 4 bytes for `bool`, the data pointer will misalign, and communication will fail. | ||
| ** **Mapping:** 1 Modbus Address = 1 IEC Byte. | ||
| ** **Example:** Reading `c0..7` (8 bits) requires a `CLIENT_8` FB with 8 pins of type **`BYTE`**. Each byte will contain either `0` or `1`. |
There was a problem hiding this comment.
I would change this to a CLIENT_0_8 and the pins are always any so I would suggest to write connected to input pins of type BYTE.
There was a problem hiding this comment.
yes for the Pins,
no for the FB, as written further down, we must mention 3 cases.
| ** **Multi-Register Types:** | ||
| *** **32-Bit Types:** `DWORD`, `DINT`, `REAL` map to **2 consecutive Registers**. | ||
| *** **64-Bit Types:** `LWORD`, `LINT`, `LREAL` map to **4 consecutive Registers**. | ||
| ** **Example:** Reading `h10..11` can be done with a `CLIENT_1` using type `REAL` (combines both registers into one float). |
There was a problem hiding this comment.
I think CLIENT_0_1 is cleaner here.
There was a problem hiding this comment.
same as below. 3 possibilites.
| * **INIT (Initialization)**: | ||
| ** **Rule:** Call `INIT` with `QI=TRUE` **exactly once** at application startup. | ||
| ** **Avoid cyclic calls:** Do NOT trigger `INIT` repeatedly. | ||
| ** **Auto-INIT:** If you leave the `INIT` pin of a Modbus client FB unconnected within a SubApplication, 4diac typically handles the initialization automatically (Auto-INIT feature). |
There was a problem hiding this comment.
I would remove the auto-init feature from here. the auto-init deserves an own page under a planned adavanced features section or?
There was a problem hiding this comment.
Auto init is a General Feature of "EInit" in 4diac.
but i see often Customers connecting INIT to a E_CYCLE.
i totally agree we need a Page therefore.
this one should be linked from here.
| #### Scenario C: Reading a Temperature (Float, 32-bit) | ||
| * **Hardware:** Sensor maps float value to Registers 10 and 11. | ||
| * **String:** `modbus[tcp:192.168.1.20:502::500:h10..11:]` | ||
| * **FB:** `CLIENT_1`. |
There was a problem hiding this comment.
CLIENT_0_1 and the pin problem
| * **FB:** `CLIENT_1`. | ||
| * **Configuration:** Set `RD_1` to type `REAL`. The FB automatically reads 2 registers (10 and 11) and combines them into one Float. | ||
|
|
||
| #### Scenario D: AkYtec (e.g. AkYtec МК210-301/311) / Bitmasks (Holding Register) |
There was a problem hiding this comment.
I don't know what an AkYtec is. Can we have a generic description of the function in Modbus terms?
There was a problem hiding this comment.
https://akytec.de/de/mk210-digitales-ein-und-ausgangsmodul.html
Can we have a generic description of the function in Modbus terms?
no. in Modbus Term, this Device is forbidden to exist. Coil is Coil.
but there are Devices out that optimize things, and this Device is one. Many Problems are coming when the user not aware of specialities of Devices ... i need to make another Chapter "Devices" ...
There was a problem hiding this comment.
Interesting, yes this should be explained more. Maybe in a section special devices
| #### Scenario D: AkYtec (e.g. AkYtec МК210-301/311) / Bitmasks (Holding Register) | ||
| * **Hardware:** Input states are packed into one 16-Bit Register (Bitmask) at Address 51. | ||
| * **String:** `modbus[tcp:192.168.1.99:502::500:h51:]` | ||
| * **FB:** `CLIENT_1`. |
| @@ -129,11 +205,10 @@ modbus[rtu:/dev/uart/1:9600:N:8:1::1:2000:c0..7:c0..7] | |||
| image:modbus/modbus_8Q.png[modbus with 8Q set] | |||
There was a problem hiding this comment.
should we update the image to a CLIENT_0_8 to better be aligned with my comments from above? and also have connections on the 8 outputs? as this seems to be the biggest problem for many users.
There was a problem hiding this comment.
no.
modbus[rtu:/dev/uart/1:9600:N:8:1::1:2000:c0..7:c0..7]
this is read 8 AND write 8.
it has to be a CLIENT_8. all other would be inconsistent.
we could add another Example with only Writing 8
and another one with only reading 8,
but this String needs a 8/8
and also have connections on the 8 outputs?
definitely.
| * **Hardware:** Input states are packed into one 16-Bit Register (Bitmask) at Address 51. | ||
| * **String:** `modbus[tcp:192.168.1.99:502::500:h51:]` | ||
| * **FB:** `CLIENT_1`. | ||
| * **Configuration:** Set `RD_1` to type `WORD`. You will receive an Integer (e.g., 5 means Input 1 and 3 are active). Use `WORD_TO_BOOL` conversion FBs to extract individual bits if needed. |
There was a problem hiding this comment.
I fear I can not follow here. But maybe because of this very special device
There was a problem hiding this comment.
Use WORD_TO_BOOL is JUST WRONG! we must use SPLIT_WORD_INTO_BOOLS ...
There was a problem hiding this comment.
the picture would definitely help. But I guess also a bit more text.


Updates the Modbus document to improve clarity and detail on configuration,
polling frequency, and data type requirements:
pollFrequencyis set to 0, and notes about a future single-shotreading feature.
read operations update.
configuration and describes the importance of matching data types to prevent
data corruption.
This ensures a comprehensive understanding of the Modbus functionality
and aids in correct implementation.