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

FeaturePROFINET IOEtherNet/IPModbus TCPEtherCAT
VendorSiemens / PIRockwell / ODVASchneiderBeckhoff
Real-timeRT / IRTCIP SyncNoneDC (Distributed Clocks)
TopologyStar, Line, RingStar, DLR RingStarLine (daisy-chain)
Min cycle31.25 µs (IRT)1 ms~10 ms62.5 µs
Device fileGSDML (XML)EDSNoneESI (XML)
DiagnosticsExcellentGoodBasicExcellent

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:

  • device identity (vendor, model, hardware/firmware revision)
  • the available modules and submodules
  • IO data lengths (input bytes, output bytes)
  • supported parameters and their ranges
  • diagnostic capabilities
  • 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:

  • Download the GSDML file from the device manufacturer's website.
  • Import it: Options → Manage Device Descriptions → Install
  • The device now appears in the hardware catalog.
  • Step 2: add the IO device to your project

  • Open the network/hardware view.
  • Drag the IO device from the catalog onto the PROFINET network.
  • Assign a device name (e.g., io-station-01). PROFINET identifies devices by name, not by address.
  • Configure the IP address, or let DHCP/DCP assign it.
  • 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:

    SlotModuleDirectionStart AddressLength
    18DIInputIB01 byte
    28DOOutputQB01 byte
    34AIInputIW28 bytes
    42AOOutputQW24 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:

  • Use industrial-rated Cat5e or Cat6 cables.
  • Check the cable length (max 100m per segment).
  • Verify the connector pin crimping with a cable tester.
  • 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

  • Install the device's GSDML file so it appears in the hardware catalog.
  • Configure the slots to match the physical modules exactly, with the coupler in slot 0.
  • Give each device a device name and assign it via DCP; a name mismatch shows as a flashing BF LED.
  • Note the IO addresses of each module and declare your ST variables AT those addresses.
  • Read the device and module status in your program, so the logic knows when a station is lost or a module reports a fault.
  • If communication drops out intermittently, check the cable quality, the crimping and the 100m segment limit first.