Communication
PLC PROFINET IO Configuration: GSDML Files, IO Devices & Structured Text Data Exchange
Configure PROFINET IO devices from scratch — understand GSDML files, slot/subslot mapping, IO data exchange, and diagnostic handling in Structured Text.
What PROFINET IO is
PROFINET IO is an Industrial Ethernet standard for real-time communication between PLCs and field devices, widely used on Siemens and multi-vendor systems. Classic PROFIBUS uses serial RS485. PROFINET runs on standard Ethernet hardware and adds the deterministic, real-time scheduling that regular TCP/IP cannot guarantee.
What PROFINET gives you
In IRT mode, cycle times go as low as 31.25 µs, which is fast enough for servo drives. For everything else it uses regular Ethernet switches, cables and connectors. A controller can run up to 256 IO devices and thousands of data points.
Diagnostics are built in down to channel level, so the device reports which channel has a fault, for example a broken wire. PROFINET and IT traffic (HTTP, OPC UA) can also share the same cable.
PROFINET compared with other Industrial Ethernet protocols
| Feature | PROFINET IO | EtherNet/IP | Modbus TCP | EtherCAT |
|---|---|---|---|---|
| Vendor | Siemens / PI | Rockwell / ODVA | Schneider | Beckhoff |
| Real-time | RT / IRT | CIP Sync | None | DC (Distributed Clocks) |
| Topology | Star, Line, Ring | Star, DLR Ring | Star | Line (daisy-chain) |
| Min cycle | 31.25 µs (IRT) | 1 ms | ~10 ms | 62.5 µs |
| Device file | GSDML (XML) | EDS | None | ESI (XML) |
| Diagnostics | Excellent | Good | Basic | Excellent |
What a GSDML file contains
Every PROFINET IO device ships with a GSDML file (General Station Description Markup Language). This XML file tells the PLC engineering tool what it needs to know about the device:
How a GSDML file is laid out
GSDML-V2.3x-VendorName-DeviceName-20240101.xml
│
├── ProfileHeader (standard version)
├── DeviceIdentity
│ ├── VendorID: 0x002A
│ └── DeviceID: 0x0001
├── DeviceAccessPointList
│ └── DeviceAccessPoint (the head module / coupler)
│ ├── ModuleList (pluggable modules)
│ │ ├── Module: 4DI (4 Digital Inputs)
│ │ ├── Module: 2AI (2 Analog Inputs)
│ │ └── Module: 4DO (4 Digital Outputs)
│ └── SubmoduleList
│ └── Submodule IO data definitions
└── ApplicationProcess
└── ParameterRecordData (device-specific config)
Slots, subslots, API and module ident numbers
Slots and subslots are the physical module positions. Slot 0 is always the coupler or head module, and slots 1 to N hold the IO modules. Each slot has subslots for individual channels.
The API (Application Process Identifier) groups related IO data. Most devices use API 0.
The module ident number is a unique ID for each module type within the GSDML.
Setting up a PROFINET IO device
Step 1: install the GSDML file
In TIA Portal, CODESYS or your engineering tool:
Options → Manage Device Descriptions → InstallStep 2: add the IO device to your project
io-station-01). PROFINET identifies devices by name, not by address.Step 3: configure the module slots
Map the physical modules to slots so the configuration matches your actual hardware:
Slot 0: Coupler / Head Module (auto-configured)
Slot 1: 8DI Module — 1 byte input
Slot 2: 8DO Module — 1 byte output
Slot 3: 4AI Module — 8 bytes input (4 × INT16)
Slot 4: 2AO Module — 4 bytes output (2 × INT16)
Step 4: map the IO addresses
Each module occupies a range in the PLC's IO address space. For the four modules above:
| Slot | Module | Direction | Start Address | Length |
|---|---|---|---|---|
| 1 | 8DI | Input | IB0 | 1 byte |
| 2 | 8DO | Output | QB0 | 1 byte |
| 3 | 4AI | Input | IW2 | 8 bytes |
| 4 | 2AO | Output | QW2 | 4 bytes |
Reading IO data in Structured Text
Once the hardware is configured, PROFINET IO data is ordinary memory-mapped I/O in Structured Text. You declare a variable AT the address from the table and use it like any other tag.
Digital inputs
PROGRAM ReadDigitalInputs
VAR
// PROFINET 8DI module at Slot 1
Sensor_Prox1 AT %IX0.0 : BOOL; // Channel 0
Sensor_Prox2 AT %IX0.1 : BOOL; // Channel 1
Sensor_Photo1 AT %IX0.2 : BOOL; // Channel 2
LimitSwitch_Fwd AT %IX0.3 : BOOL; // Channel 3
LimitSwitch_Rev AT %IX0.4 : BOOL; // Channel 4
EStop_Channel AT %IX0.5 : BOOL; // Channel 5
DoorSwitch AT %IX0.6 : BOOL; // Channel 6
Spare_DI AT %IX0.7 : BOOL; // Channel 7
ConveyorRunning : BOOL := FALSE;
END_VAR
// Use PROFINET inputs like any other I/O
IF Sensor_Prox1 AND NOT LimitSwitch_Fwd THEN
ConveyorRunning := TRUE;
END_IF;
IF EStop_Channel THEN
ConveyorRunning := FALSE;
END_IF;
END_PROGRAM
Analog inputs with scaling
The 4AI module delivers each 4–20 mA channel as a raw INT from 0 to 27648. Divide by 27648.0 and multiply by the span to get engineering units:
PROGRAM ReadAnalogInputs
VAR
// PROFINET 4AI module at Slot 3
AI_Raw_0 AT %IW2 : INT; // Channel 0 raw (0–27648)
AI_Raw_1 AT %IW4 : INT; // Channel 1 raw
AI_Raw_2 AT %IW6 : INT; // Channel 2 raw
AI_Raw_3 AT %IW8 : INT; // Channel 3 raw
// Scaled engineering values
Temperature : REAL; // °C
Pressure : REAL; // bar
FlowRate : REAL; // L/min
Level : REAL; // %
END_VAR
// Scale 4-20mA input (raw 0–27648) to engineering units
// Formula: EU = ((Raw - RawMin) / (RawMax - RawMin)) * (EUMax - EUMin) + EUMin
Temperature := (INT_TO_REAL(AI_Raw_0) / 27648.0) * 200.0; // 0–200°C
Pressure := (INT_TO_REAL(AI_Raw_1) / 27648.0) * 10.0; // 0–10 bar
FlowRate := (INT_TO_REAL(AI_Raw_2) / 27648.0) * 500.0; // 0–500 L/min
Level := (INT_TO_REAL(AI_Raw_3) / 27648.0) * 100.0; // 0–100%
END_PROGRAM
Writing digital and analog outputs
Outputs use the same scaling in reverse, from a 0–100% value back to the raw 0–27648 range:
PROGRAM WriteOutputs
VAR
// PROFINET 8DO module at Slot 2
Valve_Inlet AT %QX0.0 : BOOL;
Valve_Outlet AT %QX0.1 : BOOL;
Motor_Conveyor AT %QX0.2 : BOOL;
Alarm_Beacon AT %QX0.3 : BOOL;
// PROFINET 2AO module at Slot 4
AO_Speed_Cmd AT %QW2 : INT; // VFD speed reference
AO_Valve_Pos AT %QW4 : INT; // Control valve position
DesiredSpeed : REAL := 50.0; // 0–100%
ValveSetpoint : REAL := 75.0; // 0–100%
END_VAR
// Scale engineering units back to raw output
AO_Speed_Cmd := REAL_TO_INT(DesiredSpeed / 100.0 * 27648.0);
AO_Valve_Pos := REAL_TO_INT(ValveSetpoint / 100.0 * 27648.0);
// Digital outputs
IF DesiredSpeed > 0.0 THEN
Motor_Conveyor := TRUE;
END_IF;
END_PROGRAM
PROFINET diagnostics in Structured Text
PROFINET reports faults down to channel level, so your program can tell which module or channel has failed instead of only knowing that the station is down. The status word addresses depend on the platform:
Checking device status
PROGRAM ProfinetDiagnostics
VAR
// System status words (platform-dependent addresses)
IO_DeviceStatus : WORD; // Overall device status
IO_ModuleStatus : ARRAY[0..7] OF WORD; // Per-slot status
DeviceOnline : BOOL;
ModuleFault : ARRAY[0..7] OF BOOL;
DiagCount : INT := 0;
// Diagnostic message buffer
LastFaultSlot : INT := -1;
LastFaultChannel : INT := -1;
DeviceOK : BOOL := FALSE;
END_VAR
// Check if the entire IO device is communicating
DeviceOnline := (IO_DeviceStatus AND 16#0001) = 16#0001;
IF NOT DeviceOnline THEN
// Device lost — could be cable, switch, or power issue
LastFaultSlot := 0;
LastFaultChannel := -1; // Entire device
END_IF;
// Check individual module status
DiagCount := 0;
FOR i := 0 TO 7 DO
ModuleFault[i] := (IO_ModuleStatus[i] AND 16#0002) <> 0;
IF ModuleFault[i] THEN
LastFaultSlot := i;
DiagCount := DiagCount + 1;
END_IF;
END_FOR;
DeviceOK := DeviceOnline AND (DiagCount = 0);
END_PROGRAM
Device naming and discovery
PROFIBUS identifies a station by its address (1–126). PROFINET identifies a device by its device name, and the DCP (Discovery and Configuration Protocol) handles the naming and discovery.
Naming conventions
Pick names that say where the device is and what it does, and keep to lower case, digits and hyphens:
✅ Good naming:
io-conveyor-01
robot-cell-a-safety
vfd-pump-station-3
❌ Bad naming:
device1 (not descriptive)
My IO Device (spaces not allowed)
STATION.01 (dots not allowed in older firmware)
Choosing a network topology
Controller (PLC)
│
├── Managed Switch ─── io-filling-01 (Star topology)
│ ├──────────── io-filling-02
│ └──────────── io-filling-03
│
└── io-conveyor-01 ─── io-conveyor-02 ─── io-conveyor-03
(Line / daisy-chain topology)
A star gives the best reliability, because one cable fault affects only one device. A line saves cabling cost, but a fault there breaks every device downstream of it. A ring with MRP heals itself: it recovers from a single cable break in <200ms.
Real-time classes: RT and IRT
PROFINET has two performance levels.
RT (Real-Time), the common case
RT uses standard Ethernet switches, with cycle times of 1–10 ms typical. It suits sensors, valves, VFDs and most IO modules, and it is what most applications use.
IRT (Isochronous Real-Time) for motion
IRT requires IRT-capable switches (Siemens SCALANCE, or the switches integrated in the devices). It reaches cycle times down to 31.25 µs with jitter below 1 µs, which is what servo drives and synchronized multi-axis motion need. The price is careful topology planning.
Performance Comparison:
──────────────────────────────────────────
│ Standard TCP/IP │ ~10-100 ms │ HMI, SCADA │
│ PROFINET RT │ 1-10 ms │ IO, VFDs │
│ PROFINET IRT │ 0.25-1 ms │ Servo drives │
──────────────────────────────────────────
Common commissioning problems
1. "BF" (bus fault) LED flashing
The device name in the project does not match the name on the actual device. Use the PLC engineering tool to assign the correct device name via DCP:
Online → Accessible Devices → Assign Device Name
2. Module configuration mismatch
The GSDML module order in the project does not match the physical hardware. Check that every slot assignment matches the physical module position exactly.
3. IO data not updating
Either the IO address mapping is wrong or the module is not in the "Data Exchange" state. Check the module status: it should show "RUN" / "Data Exchange Active."
4. Intermittent communication loss
This is usually cabling, because PROFINET is sensitive to cable quality. Work through these:
A complete IO exchange program
This program uses the same four-module station, io-station-01. It reads the digital inputs as one byte and extracts the bits, scales two analog inputs, runs a pump with a pressure limit, and writes the outputs back:
PROGRAM ProfinetIOExchange
VAR
// === PROFINET IO Device: "io-station-01" ===
// Slot 1: 8DI Module (1 byte input)
DI_Byte AT %IB0 : BYTE;
// Slot 2: 8DO Module (1 byte output)
DO_Byte AT %QB0 : BYTE;
// Slot 3: 4AI Module (8 bytes input)
AI_Ch0 AT %IW2 : INT;
AI_Ch1 AT %IW4 : INT;
AI_Ch2 AT %IW6 : INT;
AI_Ch3 AT %IW8 : INT;
// Slot 4: 2AO Module (4 bytes output)
AO_Ch0 AT %QW2 : INT;
AO_Ch1 AT %QW4 : INT;
// Process variables
StartButton : BOOL;
StopButton : BOOL;
SensorActive : BOOL;
Temperature : REAL;
Pressure : REAL;
PumpRunning : BOOL := FALSE;
PumpSpeed : REAL := 0.0;
ValvePosition : REAL := 0.0;
HighTempAlarm : BOOL := FALSE;
END_VAR
// ── Read Digital Inputs (bit extraction from byte) ──
StartButton := (DI_Byte AND 16#01) <> 0; // Bit 0
StopButton := (DI_Byte AND 16#02) <> 0; // Bit 1
SensorActive := (DI_Byte AND 16#04) <> 0; // Bit 2
// ── Scale Analog Inputs ──
Temperature := (INT_TO_REAL(AI_Ch0) / 27648.0) * 150.0; // 0–150 °C
Pressure := (INT_TO_REAL(AI_Ch1) / 27648.0) * 16.0; // 0–16 bar
// ── Process Logic ──
IF StartButton AND NOT StopButton AND Pressure < 12.0 THEN
PumpRunning := TRUE;
PumpSpeed := 75.0; // 75% speed
END_IF;
IF StopButton OR Pressure >= 14.0 THEN
PumpRunning := FALSE;
PumpSpeed := 0.0;
END_IF;
HighTempAlarm := Temperature > 120.0;
IF HighTempAlarm THEN
ValvePosition := 100.0; // Full open cooling valve
ELSE
ValvePosition := 50.0; // Normal position
END_IF;
// ── Write Digital Outputs ──
IF PumpRunning THEN
DO_Byte := DO_Byte OR 16#01; // Set bit 0 (pump contactor)
ELSE
DO_Byte := DO_Byte AND 16#FE; // Clear bit 0
END_IF;
IF HighTempAlarm THEN
DO_Byte := DO_Byte OR 16#02; // Set bit 1 (alarm beacon)
ELSE
DO_Byte := DO_Byte AND 16#FD; // Clear bit 1
END_IF;
// ── Write Analog Outputs ──
AO_Ch0 := REAL_TO_INT(PumpSpeed / 100.0 * 27648.0); // VFD speed ref
AO_Ch1 := REAL_TO_INT(ValvePosition / 100.0 * 27648.0); // Valve position
END_PROGRAM
Commissioning checklist
AT those addresses.