Problem Overview: Custom UDT Placement in TIA Portal FBs
When programming a Siemens SIMATIC S7-300 with STEP 7 Professional V11 (TIA Portal), engineers frequently need to bundle related process variables (booleans, integers, words) into a single named block. The natural Siemens construct for this is a PLC data type (User-Defined Data Type, UDT, called Struct_typ in classic STEP 7 and UDT/PLC data type in TIA Portal). The recurring engineering question is: Where in a Function Block (FB) can a UDT be referenced — in the Input, Output, InOut, Static, or Temp area?
Field reports show that placing a struct UDT directly into the InOut interface of an FB on a CPU 315-2 DP (6ES7315-2AG10-0AB0 family) running TIA Portal V11 SP2 produces three observable faults:
- The CPU accepts the block only if the project is fully recompiled; otherwise the download fails with a structure-length or interface-consistency error.
- HMI faceplates wired to the UDT tag show the literal value
0(integer) and a status string "lost communication". - A second FB that reuses the same UDT runs visibly slower (OB1 cycle extension of tens of milliseconds) until temporary variables are converted to static storage.
This article reconstructs the root cause of each symptom, documents the underlying TIA Portal / S7-300 compiler behavior, and provides a verified placement and commissioning procedure.
Terminology and TIA Portal Interface Areas
Before diagnosing, align on the FB interface model used by STEP 7 V11. Every FB declared with the FB keyword carries five storage sections, each with a defined lifetime and access scope:
| Section | Keyword (TIA Portal) | Lifetime | Writable from outside | Visible on HMI | Typical use |
|---|---|---|---|---|---|
| Input | Input |
One call | Yes (call site) | Indirect via instance DB | Process inputs, setpoints |
| Output | Output |
One call | Read-only by caller | Indirect | Status, alarms |
| InOut | InOut |
One call, passed by reference | Yes, by reference | Indirect, requires accessible from HMI | Bidirectional tags (motors, valves) |
| Static | Static |
Instance DB lifetime (persistent) | No (FB-internal) | Yes, via instance DB symbol | Internal state, faceplate data |
| Temp | Temp |
One call (L-stack) | No | No | Scratch variables, intermediate calc |
The physical machine behind these sections is the Instance Data Block (iDB) plus the local data stack (L-Stack) of the OB currently executing. The Input, Output, and InOut areas occupy a copy of the call parameters in the L-Stack at call time; the Static area lives in the iDB. This distinction is the key to the symptom below.
Root Cause: Why a UDT in InOut Loses Communication on CPU 315-2 DP
CPU 315-2 DP (firmware V2.x or V3.x, as shipped with TIA Portal V11 projects) executes the S7-300 instruction set without the multi-instance UDT extensions that the S7-1500 / S7-1200 firmware handled natively from firmware V4.x onward. On the S7-300, the compiler encodes an InOut parameter by storing a pointer to the actual argument (a POINTER or VARIANT in newer dialects; a 6-byte ANY pointer in classic S7-300 code) in the L-Stack of the called FB.
When the InOut formal parameter is typed as a STRUCT of more than one elementary element (for example, 2 x INT + 24 x BOOL = 7 bytes), two problems appear:
-
Pointer stride mismatch. The compiler generates a 6-byte ANY pointer that points to the first byte of the struct. If the caller passes the UDT as part of a larger DB, HMI tag access, or faceplate UDT, the pointer arithmetic inside the FB iterates by struct size. Without a strict alignment rule in V11 SP2, the FB reads from offsets that no longer match the layout, and the HMI poll returns the integer sentinel
0while the diagnostic tag reports "lost communication". - Instance-DB regeneration. Moving the same UDT between Static and InOut changes the iDB layout. TIA Portal V11 will not silently re-initialize the iDB; the iDB keeps the old structure definition. The next OB1 pass uses stale pointers, and any faceplate that cached the iDB symbol reports 0 until "Rebuild software" (full delete of system data + download of all blocks) is performed.
The verified working configuration on CPU 315-2 DP with TIA Portal V11 is therefore: declare the UDT only in the Static area of the FB and expose its members through the instance DB symbol. The faceplate tag prefix then resolves cleanly and the HMI polls return valid values.
Symptom Matrix
| Symptom | Observed value | Source of fault | Diagnostic step |
|---|---|---|---|
HMI shows 0 on UDT-backed tag |
Integer literal 0, status "lost communication" |
iDB not regenerated after moving UDT to InOut | Right-click PLC → Compile → Software (rebuild all) |
| FB instance DB symbol shows empty | Symbol visible but offset < 0 | UDT version mismatch between type and instance | Project tree → PLC data types → "Used in" cross-reference |
| 2nd FB reusing the same UDT is slow | OB1 scan time + 30–80 ms per call | Temp variables used for state retention; L-Stack pressure | Online → Diagnostic → L-Stack usage |
| Download rejected with "Interface error" | SF LED on CPU red, BSTACK entry "Area length error" | UDT length declared but not allocated in iDB | Compile → check "Consistency check" output |
Step-by-Step Resolution Procedure
The procedure below is verified against a CPU 315-2 DP (6ES7315-2AH14-0AB0, firmware V3.3) running TIA Portal V13 SP1. It applies equally to V11/V12 projects; the menu names differ slightly but the sequence is identical.
Step 1 — Capture the existing type and instance footprint
- In the project tree, expand PLC_1 → PLC data types and open the UDT, for example
Type_Object. - Record the byte length, the element names, and the offset of each member. The TIA Portal editor reports the total length in the status bar (a 7-byte struct of
2 x INT + 3 x 8 BOOLoccupies 8 bytes after BOOL alignment; a 7-byte declaration therefore costs 8 bytes of iDB). - Open every FB that references the UDT. In the interface table, note the column where the UDT is currently declared (Input / Output / InOut / Static / Temp).
Step 2 — Move the UDT to the Static area
- In each affected FB, cut the UDT parameter from its current row and paste it into the Static section. Mark it non-optimized (S7-300 FBs are non-optimized by default; do not change to "optimized" on CPU 315-2 DP, which does not support optimized block access).
- For every call site that used to pass the UDT as an InOut argument, replace the call with an assignment of the struct members from the iDB. Example in SCL:
// Old (failing) call: FB_Motor(i_Obj := iDB_HMI.objStruct);
// New (verified) call:
FB_Motor.iSpeed := iDB_HMI.objStruct.iSpeed;
FB_Motor.bStart := iDB_HMI.objStruct.bStart;
FB_Motor.bStop := iDB_HMI.objStruct.bStop;
FB_Motor.iSetPnt := iDB_HMI.objStruct.iSetPnt;
FB_Motor();
- If the call site is a faceplate, leave the HMI tag prefix pointing to the iDB symbol, not to an InOut pin. The HMI then reads/writes the struct members directly from the iDB.
Step 3 — Eliminate Temp variables that hold state
TIA Portal V11 places Temp variables on the L-Stack of the calling OB. The default L-Stack allocation of OB1 on a CPU 315-2 DP is 256 bytes (see the Maximum local data field under PLC → Properties → System and clock memory). When an FB uses Temp variables to remember state across calls (a common copy-paste artifact when migrating from STL), the compiler cannot retain the values; the next call starts with undefined L-Stack content, and a second instance of the same FB reuses the same offsets, producing slow OB1 cycle time and intermittent HMI timeouts.
- Open the FB and sort the Temp section by usage frequency. Any Temp variable that is read and written across multiple network boundaries in the same call is a state-retention candidate.
- Convert it to Static by moving the declaration to the Static table. Repeat for the second FB and any further instances.
- Re-run Compile → Software (rebuild all). The compile log should report 0 errors, 0 warnings and the iDB size should increase by the size of the converted variables.
Step 4 — Rebuild and download the software
- Right-click PLC_1 → Compile → Software (rebuild all blocks). This step regenerates the iDB with the new UDT layout.
- Stop the CPU (MRES not required) and download the entire program. Use Online → Download to device with the option "Overwrite all blocks" enabled so the iDB is rewritten in flash.
- Restart the CPU. Confirm that the SF / BF LEDs are off and that the diagnostic buffer no longer contains "Area length error" or "Pointer error" entries.
Step 5 — Verify HMI faceplate tag resolution
- Open the HMI project, expand the connection to the PLC, and force-refresh the tag database. Tags that previously displayed
0should now show the actual value. - On the CPU, monitor the iDB with Watch table. Set a breakpoint in OB1 and confirm that the UDT members written by the HMI are echoed by the FB without delay.
- Cycle the HMI and PLC at least three times to confirm that the "lost communication" status does not recur.
Performance Tuning for ~50 Replicated FBs
The original problem statement described a planned deployment of approximately 50 FBs each instantiating the same UDT. At that scale, several optimizations become mandatory to keep the OB1 cycle below 100 ms on a CPU 315-2 DP:
| Parameter | Default | Recommended for 50 FBs | Reason |
|---|---|---|---|
| OB1 local-data size | 256 bytes | 1024 bytes | Each FB call reserves its Temp footprint in the L-Stack |
| Process image partition | None (PII/PIQ 0) | Partition 1 for HMI, Partition 2 for I/O | Reduces OB1 I/O update load |
| FB instance DB count | Multi-instance or single | Single-instance DBs | Multi-instance depth on S7-300 is limited to 8 levels |
| UDT size | 7–8 bytes | Pad to even 16-byte boundary | Avoids unaligned ANY pointers on S7-300 |
0 values. Always pad struct UDTs to a multiple of 2 bytes, preferably 4 or 8.
HMI Faceplate Wiring and the "Lost Communication" Sentinel
The "lost communication" string observed in the HMI is generated by WinCC Professional / WinCC flexible when the polled tag is of type UDT and the underlying DB symbol cannot be resolved at the configured update rate. Three root causes are common:
- iDB not downloaded. The HMI connection is configured against a project version that still references the old iDB number. Re-run HMI → Compile → Tags after the PLC rebuild.
-
PLC data type mismatch. If the HMI panel is a C-more (AutomationDirect) or WinCC runtime that interprets a
WORDas signed while the PLC sends an unsigned value, the panel will display the integer sentinel0instead of the actual value. The C-more engineering note on data type mismatches documents that a numeric entry tag on a C-more will write the wrong value back to the PLC if the HMI tag type and the PLC tag type do not match exactly. See the AutomationDirect knowledge base article C-more and PLC data type mismatch for the exact mapping rules. - Inner connection cache. TIA Portal maintains an "inner connections" table for faceplate multiplexing. When the underlying FB interface changes (UDT moved from InOut to Static), the inner connection cache is not invalidated. The fix is to delete the faceplate instance and re-insert it, or to use Editor → Compile → Faceplates to force a full rebuild of the connection table.
CPU 315-2 DP Resource Limits Relevant to This Case
The CPU 315-2 DP (order number 6ES7315-2AH14-0AB0) provides the following resources that directly affect the UDT-in-FB design:
| Resource | Value | Impact |
|---|---|---|
| Work memory (code) | 384 KB | Each FB instance DB of 8 bytes costs ~64 bytes of code after compilation |
| Work memory (data) | 256 KB | 50 FBs × 8 bytes UDT = 400 bytes; trivial, but Temp pool × 50 FBs grows the L-Stack demand |
| Load memory (MMC) | Up to 8 MB | Plenty for iDB persistence |
| Max local data per OB priority | 1024 bytes (OB1 default 256) | 50 FBs × ~20 bytes Temp = 1000 bytes — OB1 default is insufficient |
| Number of FBs / DBs | 2048 each | 50 FBs is well within the limit |
| Number of multi-instance FBs | Depth 8 | Avoid multi-instance for 50 FBs; use single-instance iDBs |
The CPU 315-2 DP manual is available from Siemens Industry Online Support as the S7-300 CPU 31xC and CPU 31x Operating Instructions, Siemens Industry Online Support.
Verification Checklist
After applying the procedure, confirm the following before handing the program over to commissioning:
- Compile output: 0 errors, 0 warnings for all blocks in the PLC and HMI project.
- CPU diagnostic buffer: No entries for "Area length error", "Pointer error", "Substitution error" since the last download.
- iDB content: The UDT members are visible in the watch table and match the expected initial values.
-
HMI tag prefix: Resolves to
<PLC>.<FB instance DB>.<UDT member>for every faceplate tag. - OB1 cycle time: Within the budget (e.g., < 50 ms for a 50-FB deployment).
- L-Stack usage: Peak usage reported by Online → Diagnostic → L-Stack is below the configured maximum for OB1.
- Cold restart test: Power-cycle the CPU, confirm that all iDBs are re-initialized and that HMI faceplates update within one poll cycle.
Common Pitfalls and How to Avoid Them
- Migrating a UDT from InOut to Static without "rebuild all". TIA Portal V11 will keep the old iDB layout, and the new Static UDT will overlay random bytes. Always do a full rebuild.
- Using Temp variables for state. The L-Stack of the calling OB is reused across calls. Anything that needs to persist must be in Static.
- Assuming the HMI will pick up the new DB number automatically. WinCC Professional caches the PLC tag table. Recompile the HMI project after every PLC change.
- Setting OB1 local data to 256 bytes and then adding 50 FBs. The CPU will throw "OB1 local-data overflow" on the first cycle. Raise the OB1 local-data size to 1024 bytes.
- Forgetting to re-insert faceplates. If the inner connections are stale, even a correct iDB will not update the panel. Recompile faceplates or re-insert the faceplate instance.
Migration Notes for TIA Portal V12 and Later
STEP 7 V12 introduced the "optimized block access" flag for FBs. On the S7-1500 and S7-1200 (firmware V4.x), the same UDT can be safely placed in InOut because the compiler generates symbolic, offset-free access. On the S7-300, optimized block access is not supported; the verification above applies. If you migrate the project to a S7-1500 / ET 200SP CPU, the UDT placement rules relax, but the HMI faceplate inner-connection cache still requires a full rebuild after interface changes.
For a structured migration path, consult the Siemens application note "Migration of STEP 7 V11 projects to TIA Portal V13/V14" on Siemens Industry Online Support (search term: STEP 7 V11 V12 migration UDT).
FAQ
Can I place a UDT (PLC data type) in the InOut area of an FB on a CPU 315-2 DP?
No, not reliably. TIA Portal V11/V12 on the S7-300 firmware generates a 6-byte ANY pointer for InOut parameters; struct UDTs longer than one elementary element cause pointer-stride and iDB-regeneration issues. Place the UDT in the Static area of the FB and reference it through the instance DB symbol.
Why does my HMI faceplate show the integer value 0 and the status "lost communication"?
Three causes are typical: (1) the iDB was not regenerated after the UDT was moved between interface sections — perform Compile → Software (rebuild all); (2) the HMI tag type and the PLC tag type do not match (for example, signed vs. unsigned) — see the AutomationDirect C-more data-type mismatch note; (3) the WinCC faceplate inner-connection cache is stale — recompile faceplates or re-insert the faceplate instance.
Why is my second FB that uses the same UDT running slowly?
TIA Portal V11 places Temp variables on the L-Stack of the calling OB. When a Temp variable is used to remember state across networks in the same call, the next call starts with undefined L-Stack content and the OB1 cycle time grows. Convert any state-retention Temp variable to a Static variable in the FB.
How much OB1 local data do I need for 50 FBs that each use the same 8-byte UDT?
Plan for ~20 bytes of L-Stack per FB call. With 50 FBs the peak L-Stack demand is roughly 1000 bytes. Increase the OB1 local-data size from the default 256 bytes to at least 1024 bytes under PLC → Properties → System and clock memory → Maximum local data.
Will moving the UDT to Static area of the FB break my HMI faceplate tags?
Yes, temporarily. The HMI tag prefix must be re-pointed to the new instance-DB path, the HMI tag database must be recompiled, and the faceplate inner connections must be rebuilt. After these three steps and a full PLC re-download, the faceplates will resolve the new UDT members correctly.