Codesys Modbus RTU I/O driver + WAGO CC100 - TX→RX turnaround time

Hi everyone,

I am working with a WAGO CC100 as a Modbus RTU Master, using the standard Codesys Modbus RTU I/O driver to poll up to 15 slaves.

Current setup:

  • Slaves: Testing with 7 slaves (simulated via USB–RS485 adapters on an Ubuntu server).
  • Polling: The sequence runs every 1 second.
  • Performance: Communicating with all 7 slaves takes ~400 ms.
  • Execution edge: I am aware the driver executes on the FALSE→TRUE transition (rising edge) of xExecute.(by Application control)

Problem: I am facing intermittent timeouts where the driver itself reports an error (fbChannel.xError = TRUE). This is not my external watchdog; the error originates from the driver. I reuse a single FB instance and switch slaves by changing the input pointer:

iec-st code: fbModbusCOM1(escravo := Global.pInversores100[InvIndexCOM1], canal := 0);

State machine (simplified):

  • INIT: assign new Slave pointer and set xExecute := FALSE
  • WAIT/TRIGGER: set xExecute := TRUE (rising edge), check xDone/xError

Timing constraints:

  • Modbus RTU requires 3.5 character times of silence; at 9600 bps this is ~4 ms.
  • My PLC cycle time is 5 ms. Moving from INIT to WAIT costs at least one PLC cycle (and possibly more if xBusy is TRUE).
  • Because I need to poll up to 15 slaves within 750 ms (50 ms / slave), adding fixed delays like 20 ms per slave is not acceptable.

Questions on driver behavior and TX→RX turnaround:

  1. When frequently switching the Slave input on the same FB instance, is one PLC cycle with xExecute := FALSE after assigning the new Slave pointer enough to ensure the driver is fully updated before the next rising edge?
  2. Does the CC100 have a specific hardware/driver TX→RX turnaround time on RS485 (DE/RE control) after the last byte is transmitted? In other words, is there a minimum guard time required on CC100 for the Master to be reliably ready to receive the slave’s response?
  3. If such a guard time exists, what is the recommended minimum for CC100 at 9600 bps, and is it already handled internally by the Codesys Modbus RTU I/O driver, or should we insert a single PLC-cycle “setup” state (xExecute := FALSE) before triggering the next request?
  4. With the call pattern fbModbusCOM1(escravo := Global.pInversores100[InvIndexCOM1], canal := 0), is there any special care or short delay recommended when changing slaves frequently to avoid race conditions between parameter update and the rising edge?
  5. Are there driver parameters (e.g., response timeout, inter-frame gap, or turnaround settings) on CC100 that we should tune for this multiplexing scenario?

Additional context:

  • The simulation uses USB hubs and USB–RS485 adapters on Ubuntu, which may introduce non-deterministic latencies. However, we aim to confirm whether CC100’s TX→RX turnaround characteristics or driver setup timing could be the root cause on the master side.
  • Our goal is to keep overhead to a single PLC cycle (≈5 ms) per slave between transactions, which should fit within the 750 ms budget for 15 slaves.

Thanks in advance for any guidance on the optimal minimum guard time and best practices for rapid slave switching on CC100 with the Codesys Modbus RTU I/O driver.

Hi, @HANIBAL ,

I am not familiar with the Codesys I/O Driver für Modbus.

Basically this is working for CC100.

In your example something is missing?
where is the ModbusRequest for the specific Function Code you want to send to the Slave?

These function blocks from IODrvModbus will be used in the Background by adding elements in the Device Tree.

maybe you can have a look at the FB ModbusRequest2, that should be enough to switch through different slaves by changing the SlaveAddress in your statemachine.

But i never tried it that way.

Small hint:
WagoAppPlcModbus will work for you also.

you can find a example inside the library documentation.
You only need to define different Querys where the UnitID for every desired Slave is defined.
Then you can use a state machine like in your existing Code.

Dear Alexander_Landfried,

Thank you for your contribution. I am using the Modbus Codesys I/O driver entirely.
I do not issue requests directly by calling a function like ModbusRequest.
I interact with the driver through the Function Block: ModbusChannel.
I control the variables mapped at the application level.
This is easier than building everything by hand, but you lose control over some process details.

My issue is related to the master’s TX→RX turnaround, the slave’s preparation/processing time, and physical-layer latencies (cabling/USB in the simulation).
Since in the final setup I will not have the physical-layer latency introduced by the USB converter, I am trying to isolate the effects to understand how each of these timings impacts performance.

I saw that your code example includes a 20 ms delay. I am currently needing to use more than 10 ms. My goal is to use slightly less so that the total read cycle stays below 50 ms (request, slave processing, answer).

Thank you very much for the tip—I’ll analyze it.