Detecting Unconnected FB Parameters in TIA Portal S7-1500

David Krause15 min read
SiemensTIA PortalTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Detecting Unconnected FB Input Parameters in TIA Portal (S7-1200 / S7-1500)

1. Problem Statement and Engineering Context

In SIMATIC S7-1200 and S7-1500 programming with TIA Portal, an FB (Function Block) is a reusable code unit with its own instance DB. Each instance call site may wire the input parameters differently. A common engineering requirement is to write FB code that branches on whether a specific input terminal has been wired (connected to a real tag or literal) at the call site, or left open (left as the unconnected default placeholder). Classic use cases include:
  • Selector FBs that default to a different formula when an override input is absent.
  • Calibration routines that apply a correction only when the calibration tag is wired.
  • Optional interlocks that bypass a permissive check when its source is intentionally left open during commissioning.
  • Generic utility FBs (math, scaling, statistics) that want to behave differently when an operand is missing versus when the operand is legitimately zero.
The key engineering distinction is between unconnected (the input pin has no source assigned) and connected to a zero or empty value (the input pin is wired, but the value happens to be zero or the string is empty). The PLC cannot solve this distinction with ordinary typed input parameters (REAL, INT, BOOL) because the moment the FB is compiled the parameter has a data type and a default value, and the call site provides a value (or the default zero). The PLC does not expose a "connectedness" bit to SCL in the same way that some other PLCs do for inline coil parameters. The solution is to choose an FB input parameter data type that can represent an unconnected state. Three workable approaches exist for the S7-1200/1500 family:
  1. REF_TO <Type> – a typed reference, with NULL meaning "unconnected". Supported on S7-1500 (firmware V2.0 and later). Not supported on S7-1200.
  2. VARIANT – a typeless pointer whose TypeCode attribute can be inspected for the VOID type. Supported on S7-1500; on S7-1200 the VARIANT type is available but more limited.
  3. Sentinel default value – declare a default that the process is guaranteed never to produce (for example -1.0 for a process range of 0…100, or 16#7FFF_FFFF for an unsigned 16-bit field). Test the parameter against the sentinel. Universal across all S7 platforms.
This document walks through each method with working SCL code, platform/firmware constraints, and a verification procedure that proves the detection logic in the PLC online.

2. Prerequisites

Item Requirement Notes
Engineering tool STEP 7 (TIA Portal) V15.1 or later V17 / V18 recommended for current firmware. TIA Portal version overview
Controller (REF_TO method) S7-1500 CPU, FW V2.0 or later REF_TO is not available on S7-1200. S7-1500 system manual
Controller (VARIANT method) S7-1200 (any FW) or S7-1500 (FW V2.0+) S7-1200 supports VARIANT but limited to standard types and structures (not multi-instance). S7-1200 system manual
Language SCL (Structured Control Language) REF_TO and VARIANT dereference are only meaningful in SCL, not LAD/FBD
Online connection Online & diagnostics or watch table Needed to verify the bit pattern at runtime
Important: REF_TO is an S7-1500-only feature. If you are targeting an S7-1200 CPU, you must use VARIANT or the sentinel method. The sentinel method is the only fully portable solution and is the fallback for any project that must compile on both controller families.

3. Method 1 — REF_TO with NULL Check (S7-1500 only)

3.1 How REF_TO behaves

A REF_TO is a typed pointer to a data area. When the input pin is left unconnected on the call site, the FB sees a NULL pointer (16#0000_0000_0000_0000). When the pin is connected, the FB receives the address of the operand. Inside the FB you test the pointer against NULL before dereferencing; dereferencing a NULL pointer causes the CPU to enter STOP with an OB121 / OB122 area-length error.

3.2 FB declaration block

Open the FB in TIA Portal, switch to the SCL editor, and declare the interface as follows:
FUNCTION_BLOCK "FB_SumSelector_Ref"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      refA : REF_TO REAL;      // optional contribution A
      refB : REF_TO REAL;      // required contribution B
      refC : REF_TO REAL;      // required contribution C
   END_VAR

   VAR_OUTPUT
      sumResult : REAL;         // computed result
      bAConnected : BOOL;      // diagnostic: A wired?
      diagCode   : INT;         // 0=OK, 1=B missing, 2=C missing, 3=B+C missing
   END_VAR

   VAR
      rB : REAL;
      rC : REAL;
   END_VAR
   BEGIN
      // Guard required operands before dereference
      IF refB = NULL THEN
         rB := 0.0;
         diagCode := diagCode OR 1;
      ELSE
         rB := refB^;
      END_IF;

      IF refC = NULL THEN
         rC := 0.0;
         diagCode := diagCode OR 2;
      ELSE
         rC := refC^;
      END_IF;

      // Optional contribution A
      IF refA <> NULL THEN
         sumResult  := refA^ + rB + rC;
         bAConnected := TRUE;
      ELSE
         sumResult  := rB + rC * 2.0;
         bAConnected := FALSE;
      END_IF;
   END_VAR
END_FUNCTION_BLOCK

3.3 Call site example

In OB1 (or any cyclic OB), call the FB once with all inputs wired and once with refA left open:
// Instance 1 — A wired, B and C wired
"iDB_Sum1"(refA := "DB_Process".scalingA,
           refB := "DB_Process".scalingB,
           refC := "DB_Process".scalingC);

// Instance 2 — A left open, B and C wired
"iDB_Sum2"(// refA omitted intentionally
           refB := "DB_Calc".factorB,
           refC := "DB_Calc".factorC);

3.4 Diagnostics

Set up a watch table with the two instance DBs. Right-click → Monitor/Modify. The bAConnected tag in iDB_Sum1 reads TRUE and in iDB_Sum2 reads FALSE. The diagCode field indicates which required inputs were not supplied.

4. Method 2 — VARIANT Type Inspection (S7-1200 / S7-1500)

4.1 VARIANT semantics

A VARIANT can point to any elementary or structured data area, or to nothing. When the input pin is unconnected, the variant is initialised with TypeCode = 16#0000 (VOID) and the IS_NULL test returns TRUE. When wired, the TypeCode reflects the actual data type (e.g. 16#04 for INT, 16#05 for DINT, 16#08 for REAL). The VariantGet instruction is used to dereference and copy the actual value into a typed work variable.

4.2 FB declaration block

FUNCTION_BLOCK "FB_SumSelector_Var"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      pParA : VARIANT;          // optional contribution A
      pParB : VARIANT;          // required contribution B
      pParC : VARIANT;          // required contribution C
   END_VAR

   VAR_OUTPUT
      sumResult  : REAL;
      bAConnected : BOOL;
      typeA      : INT;         // TypeCode for A (diagnostic)
      typeB      : INT;         // TypeCode for B
      typeC      : INT;         // TypeCode for C
      bOk        : BOOL;        // overall validity
   END_VAR

   VAR_TEMP
      rA : REAL;
      rB : REAL;
      rC : REAL;
      wStatusA : WORD;
      wStatusB : WORD;
      wStatusC : WORD;
   END_VAR
   BEGIN
      bOk := TRUE;

      // ----- Optional A -----
      typeA := pParA.TypeCode;
      IF pParA.TypeCode = 16#0000 THEN
         bAConnected := FALSE;
      ELSE
         // Try to read the variant as REAL
         wStatusA := VariantGet(src := pParA, dst := rA);
         IF wStatusA = 0 THEN
            bAConnected := TRUE;
         ELSE
            // Connected but not REAL — degrade gracefully
            rA := 0.0;
            bAConnected := FALSE;
         END_IF;
      END_IF;

      // ----- Required B -----
      typeB := pParB.TypeCode;
      IF pParB.TypeCode = 16#0000 THEN
         rB := 0.0;
         bOk := FALSE;
      ELSE
         wStatusB := VariantGet(src := pParB, dst := rB);
         IF wStatusB <> 0 THEN
            rB := 0.0;
            bOk := FALSE;
         END_IF;
      END_IF;

      // ----- Required C -----
      typeC := pParC.TypeCode;
      IF pParC.TypeCode = 16#0000 THEN
         rC := 0.0;
         bOk := FALSE;
      ELSE
         wStatusC := VariantGet(src := pParC, dst := rC);
         IF wStatusC <> 0 THEN
            rC := 0.0;
            bOk := FALSE;
         END_IF;
      END_IF;

      // ----- Computation -----
      IF bAConnected THEN
         sumResult := rA + rB + rC;
      ELSE
         sumResult := rB + rC * 2.0;
      END_IF;
   END_VAR
END_FUNCTION_BLOCK

4.3 TypeCode reference table

TypeCode (hex) S7 data type Length (bytes)
16#0000 VOID (unconnected) 0
16#0001 BOOL 1
16#0002 BYTE 1
16#0003 CHAR 1
16#0004 WORD 2
16#0005 INT 2
16#0006 DWORD 4
16#0007 DINT 4
16#0008 REAL 4
16#0009 DATE 2
16#000A TOD (Time_of_Day) 4
16#000B TIME 4
16#000C S5TIME 2
16#000F DATE_AND_TIME (DT) 8
16#0010 STRING n+2
Caution: The TypeCode for an unconnected VARIANT is 16#0000 (VOID) only when the parameter is truly unconnected on the call site. If a literal or tag is connected — even one whose value is zero — the TypeCode will reflect the connected type. This is the correct semantic for "wired or not wired" detection.

4.4 Call site example

"iDB_SumVar"(pParA := "DB_Process".scalingA,   // wired
            pParB := "DB_Process".scalingB,   // wired
            pParC := "DB_Process".scalingC);  // wired

"iDB_SumVar_2"(// pParA omitted → TypeCode stays 16#0000
               pParB := "DB_Calc".factorB,
               pParC := "DB_Calc".factorC);

5. Method 3 — Sentinel Default Value (Universal)

5.1 Concept

Pick a value that the process can never produce and declare it as the input default. Inside the FB, compare the actual value against that sentinel. If equal, treat the parameter as unconnected. Common sentinel values:
Parameter type Recommended sentinel Process range
REAL (scaling, %) -1.0 (or -3.4E38 = -REAL#MIN) 0…100
REAL (temperature °C) -1000.0 -200…+1200
INT (count, index) -1 0…32767
DINT (encoder pulse) 16#7FFF_FFFF 0…2^31-1
WORD (bitmask) 16#FFFF 0…16#FFFE
TIME (duration) T#0ms (or no sentinel — use absent enable) process-specific

5.2 FB declaration block

FUNCTION_BLOCK "FB_SumSelector_Sentinel"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      rParA : REAL := -1.0;     // -1.0 = sentinel "not connected"
      rParB : REAL;             // required
      rParC : REAL;             // required
   END_VAR

   VAR_OUTPUT
      sumResult  : REAL;
      bAConnected : BOOL;
   END_VAR
   BEGIN
      IF rParA = -1.0 THEN
         bAConnected := FALSE;
         sumResult   := rParB + rParC * 2.0;
      ELSE
         bAConnected := TRUE;
         sumResult   := rParA + rParB + rParC;
      END_IF;
   END_VAR
END_FUNCTION_BLOCK

5.3 Why this works for every S7-1200 / S7-1500

Because the comparison is done on a normal typed value, the FB compiles for every CPU family and firmware revision, including older S7-300/400 retrofits in TIA Portal. There is no special instruction, no library, and no language restriction beyond basic SCL comparison.

5.4 Risks and mitigations

  • Process collision: if the real process can ever produce the sentinel value, the FB will mis-classify it as "unconnected". Mitigate by documenting the sentinel in the FB header comment and by checking the sentinel against the process engineering limits at design time.
  • Implicit zero on unconnected pin: if a user does not wire a parameter and the editor does not preserve the explicit default (some earlier TIA Portal versions reset to literal zero in the call site), the sentinel is lost. Mitigate by always wiring the default literal explicitly at the call site: rParA := -1.0.
  • Multiple defaults in one FB: use distinct sentinels for each optional input to avoid ambiguity (e.g. -1.0 for A, -2.0 for B).

6. Method Comparison Matrix

Attribute REF_TO VARIANT Sentinel
CPU support S7-1500 only S7-1200 + S7-1500 All SIMATIC S7
Firmware minimum V2.0 V4.0 (S7-1200), V2.0 (S7-1500) Any
Language SCL only SCL only SCL / LAD / FBD
Compile cost Low (typed pointer) Higher (variant handling) Lowest
Runtime cost NULL compare + deref TypeCode read + VariantGet Single equality compare
Distinguishes zero from unconnected Yes Yes No (only if zero ≠ sentinel)
Library required No Yes — "VariantGet" / "VariantPut" No
NULL deref risk High — STOP if unguarded Handled by ENO/Status None
Visible in LAD/FBD No (pin hidden) No (pin shown as ??) Yes
Best for High-performance S7-1500 libraries Generic utility FBs across families Cost-sensitive / cross-platform projects

7. Step-by-Step Implementation — VARIANT Method on TIA Portal V18

The walk-through uses the VARIANT method because it works on both S7-1200 and S7-1500.

Step 1 — Create the FB

  1. In the project tree, right-click Program blocks → Add new block → Function block.
  2. Name: FB_SumSelector_Var, language: SCL, number: auto. Click Add.
  3. Open the FB, switch the interface view if not already open, and enter the declarations from section 4.2.

Step 2 — Compile

  1. Press F7 or right-click → Compile.
  2. If a syntax error is shown for VariantGet, the "VariantGet" instruction must be resolved. Open the right-hand Instructions pane → Basic Instructions → Move operations → drag VARIANT_TO or the system block VariantGet into the editor. The compiler will then create the required F-system block automatically.
  3. Compile again until the status reads "0 errors, 0 warnings".

Step 3 — Call the FB twice from OB1

  1. Open OB1 (SCL) and add the call patterns from section 4.4.
  2. Create the data blocks DB_Process and DB_Calc if they do not exist, and declare the referenced REAL tags.
  3. Compile OB1.

Step 4 — Download and go online

  1. Right-click the S7-1500 device → Download to device → select PG/PC interface → search → load.
  2. Open Watch and force tables → add a new watch table. Drag both instance DBs into the table along with the two source data blocks.
  3. Click Monitor all (glasses icon).

Step 5 — Verify the detection

  1. For instance 1 (all wired), expect bAConnected = TRUE and sumResult = A+B+C.
  2. For instance 2 (A omitted), expect bAConnected = FALSE, typeA = 0 (VOID), and sumResult = B + 2·C.
  3. Modify DB_Process.scalingA online to confirm the path is re-evaluated on every cycle.

8. Edge Cases and Field-Proven Pitfalls

8.1 Unconnected parameter to a non-VARIANT FB

If the input is declared as a standard REAL and the pin is left unconnected at the call site, TIA Portal inserts the default value of the input. With the standard default 0.0 this means the FB cannot distinguish "user wired 0.0" from "user did not wire anything". The only remedy is to change the input type to REF_TO, VARIANT, or to give the input a non-zero default value explicitly at the FB declaration.

8.2 Connection via AT construct or POKE

Some legacy code wires an FB input via an AT overlay on a larger DB, or via POKE (S7-1500 only). These produce a valid connected address. REF_TO and VARIANT see the parameter as connected. If you need to detect the absence of a memory area, you must validate the contents, not the connection status.

8.3 Multi-instance FBs and parameters

When an FB is called as a multi-instance inside another FB, REF_TO and VARIANT work identically. There is no special handling. The REF_TO input must be assigned to an addressable tag — it cannot be assigned to a constant literal (LAD/FBD do not let you drag a constant to a REF_TO pin; SCL must be used for the assignment).

8.4 S7-1200 firmware limits on VARIANT

The S7-1200 supports VARIANT but the VariantGet instruction is implemented in the CPU firmware rather than as a system block. Some early firmware versions (V4.0) do not support VARIANT inside FBs called from cyclic OBs — check the S7-1200 system manual, section on data types for the exact firmware list. On S7-1500, all variants are supported as of FW V2.0.

8.5 Stop on NULL dereference (REF_TO)

Dereferencing a NULL REF_TO without the guard IF refX = NULL produces an area-length error. The CPU enters STOP and writes an OB121 / OB122 diagnostic entry. Always test for NULL before the ^ operator in production code. The diagnostic buffer entry for an unguarded NULL dereference is:
Event ID     : 16#2522 (OB not found for programming error)
Event ID     : 16#3582 (DB area length error)
Event ID     : 16#39xx (Area length error during read/write)
Priority OB  : OB 121 (Programming error)
Reaction     : CPU goes to STOP unless OB 121 is loaded

8.6 VariantGet returning non-zero status

If the variant points to a BOOL but the destination is a REAL, VariantGet returns a non-zero STATUS word. The snippet in section 4.2 captures the status into wStatusA/B/C and sets bOk := FALSE for the diagnostic. The TIA Portal help on VariantGet enumerates the STATUS codes — the most common are:
STATUS (hex) Meaning
16#0000 No error
16#0080 Type mismatch between source VARIANT and destination
16#8101 Pointer is NULL
16#8130 Source is a literal (no addressable source — FB parameters are addressable, but literals are handled differently)
16#8150 Source is a STRING longer than the destination

9. Diagnostics and Online Verification Procedure

9.1 Force table test

  1. Create a watch table containing the two instance DBs and the source data blocks.
  2. Set DB_Process.scalingA = 12.5, DB_Process.scalingB = 3.0, DB_Process.scalingC = 7.0.
  3. Confirm iDB_SumVar.sumResult = 22.5 (instance 1, A wired).
  4. Confirm iDB_SumVar_2.sumResult = 3.0 + 2*7.0 = 17.0 (instance 2, A not wired).
  5. Set DB_Process.scalingA = 0.0 and confirm the result is still 22.5 — proving that a wired zero is treated as "connected" and not as "absent".

9.2 Cross-check with the diagnostic buffer

  1. Online → Diagnostics → Diagnostic buffer.
  2. Confirm no Area length error events have been logged. If they have, the REF_TO guard in section 3.2 is missing or wrong.

9.3 LED and HMI confirmation

  1. Wire iDB_SumVar.bAConnected to an HMI tag named StatusA.
  2. Use a WinCC Unified / Comfort Panel symbol to display the boolean state. Operators can confirm visually that the A operand is active or bypassed.
  3. This is also the right way to expose the diagnostic in an alarm log: HMI Alarm → trigger on bAConnected = FALSE with the text "Optional A operand bypassed".

10. Frequently Asked Questions

Does REF_TO work on S7-1200?

No. REF_TO is only available on S7-1500 CPUs from firmware V2.0 onward. On S7-1200 you must use VARIANT (with the limits described in section 4.4) or the sentinel default value method.

Can I detect an unconnected parameter with a normal REAL or INT input?

No. A normal typed input always carries a value (the editor's default literal, typically 0). Only REF_TO, VARIANT, or a sentinel default value can preserve the distinction between "wired" and "unconnected".

What is the exact value of an unconnected VARIANT?

The TypeCode is 16#0000 (VOID), and the IS_NULL operator returns TRUE. You can also use the operator = to compare the variant against the literal NULL.

What happens if I dereference a NULL REF_TO inside the FB?

The CPU enters STOP with a programming error (OB 121) and a diagnostic-buffer entry such as 16#3582. Always check the REF_TO for NULL before using the ^ dereference operator.

Is the sentinel method reliable for safety-relevant code?

Use it with care. The process must be guaranteed never to produce the sentinel value, and the sentinel must be declared explicitly at every call site. For SIL-rated FBs prefer REF_TO on S7-1500 or VARIANT with explicit OK-state diagnostics, because they expose "absent" as a structural property rather than as a value that could collide with a process reading.

Back to blog