Skip to content

I/O Binding

Address Examples: %IX0.0, %QX0.0, %IW0, %QW0

Use %IX0.0 when you need a concrete boolean input example, %QX0.0 for a boolean output example, %IW0 for a word input example, and %QW0 for a word output example. This page covers those address forms and how symbolic variables bind to physical I/O channels.

Guide

truST PLC I/O Binding Guide

This guide explains how to map hardware I/O to Structured Text variables using the Web UI or io.toml and IEC addresses (%IX, %QX, %MX).

Tip: The Web UI supports driver selection, GPIO pin mapping, Modbus/TCP settings, and safe‑state outputs under I/O → I/O configuration (no manual file editing needed).

1) Addressing Basics

Use IEC-style addresses in ST:

VAR_GLOBAL
  InSignal AT %IX0.0 : BOOL;
  OutSignal AT %QX0.0 : BOOL;
END_VAR

  • %I = input, %Q = output, %M = memory
  • X = bit address (use for GPIO and discrete I/O)

Marker (%M) address variants: - %MX<byte>.<bit> (bit, BOOL), example: %MX0.7 - %MB<byte> (byte), example: %MB12 - %MW<byte> (word), example: %MW50 - %MD<byte> (double word), example: %MD200 - %ML<byte> (long word), example: %ML8 - %M* (wildcard, resolved by VAR_CONFIG)

Runtime cycle semantics for %M bindings: - Cycle start: %M process image is read into bound variables. - Cycle end: bound variable values are written back to %M process image.

2) io.toml Structure (v1)

Single-driver form (legacy + still supported):

[io]
driver = "simulated"
params = {}

Multi-driver form (composed drivers, executed in order):

[io]
drivers = [
  { name = "modbus-tcp", params = { address = "192.168.0.10:502", unit_id = 1, input_start = 0, output_start = 0, timeout_ms = 500, on_error = "fault" } },
  { name = "mqtt", params = { broker = "192.168.0.20:1883", topic_in = "line/in", topic_out = "line/out", reconnect_ms = 500, keep_alive_s = 5, allow_insecure_remote = true } }
]

Rule: - Use either io.driver + io.params or io.drivers (do not mix both in one file).

Optional safe state outputs:

[[io.safe_state]]
address = "%QX0.0"
value = "FALSE"

If io.toml is missing, the runtime uses system IO config: - Linux/macOS: /etc/trust/io.toml - Windows: C:\\ProgramData\\truST\\io.toml

3) GPIO Example (Raspberry Pi)

[io]
driver = "gpio"

[io.params]
backend = "sysfs"
inputs = [
  { address = "%IX0.0", line = 17, debounce_ms = 5 }
]
outputs = [
  { address = "%QX0.0", line = 27, initial = false }
]

[[io.safe_state]]
address = "%QX0.0"
value = "FALSE"

4) Loopback (Local Testing)

[io]
driver = "loopback"
params = {}

This copies outputs to inputs for local testing without hardware.

5) Modbus/TCP Example

[io]
driver = "modbus-tcp"

[io.params]
address = "192.168.0.10:502"
unit_id = 1
input_start = 0
output_start = 0
timeout_ms = 500
on_error = "fault"

6) MQTT Example

[io]
driver = "mqtt"

[io.params]
broker = "192.168.0.20:1883"
topic_in = "line/in"
topic_out = "line/out"
reconnect_ms = 500
keep_alive_s = 5
allow_insecure_remote = true

7) Transport Gating Notes (Critical)

EtherCAT hardware transport (non-mock adapter):

  • requires build feature ethercat-wire
  • supported on unix targets only in this build
  • adapter = "mock" remains valid for deterministic local/CI validation

OPC UA wire server:

  • requires build feature opcua-wire
  • if [runtime.opcua].enabled = true without opcua-wire, runtime startup fails with a feature-disabled error
  • when enabled, configure either:
  • allow_anonymous = true (local commissioning only), or
  • allow_anonymous = false plus both username and password

Communication examples with step-by-step commissioning flow:

  • examples/communication/modbus_tcp/README.md
  • examples/communication/mqtt/README.md
  • examples/communication/opcua/README.md
  • examples/communication/ethercat/README.md
  • examples/communication/ethercat_field_validated_es/README.md
  • examples/communication/gpio/README.md
  • examples/communication/multi_driver/README.md

8) Validate + Inspect

EtherCAT backend details (module chain profile, diagnostics, and hardware setup): docs/guides/ETHERCAT_BACKEND_V1.md.

Validate a project folder:

trust-runtime validate --project <project-folder>

Read current I/O snapshot:

trust-runtime ctl --project <project-folder> io-read

Write output (for testing):

trust-runtime ctl --project <project-folder> io-write %QX0.0 TRUE