1. Problem Overview
A recurring failure mode on S7-1200 and S7-1500 controllers occurs when an SCL (Structured Control Language) function block declares analog process variables as REAL (IEEE-754 single-precision, 32-bit) but the peripheral input word (e.g., PIW752, PIW754, IW752) is read as a 16-bit INT. TIA Portal rejects the implicit assignment with a type-mismatch compile error, and downstream users may also encounter the runtime error "A structure without components is not allowed" if a User-Defined Type (UDT) is partially populated.
The typical symptom pattern is:
- SCL source compiles with red squigglies on
y := u1 + u2;whenu1,u2are bound toPIW752/PIW754. - Direct assignment of a peripheral word to a
REALinput raises "Incompatible types: cannot convert INT to REAL implicitly". - If the user inserts a
CONVblock but the surrounding UDT (e.g.,User_data_type_1) is empty, the download fails with "A structure without components is not allowed". - Switching all variables to
INTremoves the compile error but breaks any downstream floating-point math (filtering, scaling, PID, model integration).
This article documents the root cause, the correct conversion chain, and the verified workaround patterns for TIA Portal V16, V17, V18 and V19.
2. Root Cause Analysis
2.1 The PIW data type is INT, not REAL
The peripheral input area of an S7 CPU is always a 16-bit signed integer. The I/O address PIW752 occupies two bytes in the process-image input table (PII) and is logically a WORD at the bus level, but symbolically it is surfaced as INT. The same applies to PQW on the output side (INT) and to the symbolic I/O fields %IW / %QW in IEC 61131-3 view.
REAL is a 32-bit single-precision IEEE-754 floating-point value, occupying four consecutive bytes. S7-1200/1500 hardware does not support any native FLOAT I/O module; the 4-byte analog modules (e.g., AI 8xU/I/RTD/TC ST, 6ES7531-7KF00-0AB0) still deliver one 16-bit channel per word into the PII. The CPU cannot perform an implicit INT → REAL promotion in a peripheral assignment because the bit pattern would be re-interpreted, not scaled.
| Symbol | Type | Size (bytes) | Range | Bit layout |
|---|---|---|---|---|
| PIW / IW / %IW | INT | 2 | -32 768 … +32 767 | 16-bit two's complement |
| PQW / QW / %QW | INT | 2 | -32 768 … +32 767 | 16-bit two's complement |
| REAL (LREAL on 1500) | Floating-point | 4 (8 for LREAL) | ±3.402 823E+38 (REAL) | IEEE 754-2008 binary32 |
| DINT | Integer | 4 | -2 147 483 648 … +2 147 483 647 | 32-bit two's complement |
2.2 Why MATLAB Function-block code triggers the error
Code generated by Simulink PLC Coder or by hand-written MATLAB Function blocks typically targets a generic IEEE-754 environment, where the inputs u1, u2 are REAL by default. When the coder emits SCL, the SCL prototype keeps REAL declarations. Downstream the user is forced to feed PIW values into a REAL signature, which the strict TIA Portal type checker rejects:
FUNCTION_BLOCK MATLAB
VAR_INPUT
u1 : REAL; // declared REAL
u2 : REAL; // declared REAL
END_VAR
VAR_OUTPUT
y : REAL;
END_VAR
y := u1 + u2;
END_FUNCTION_BLOCK
Binding u1 := PIW752 at the call site fails because the implicit conversion INT → REAL is not allowed for I/O areas in STEP 7.
2.3 The "structure without components" error
The message "A structure without components is not allowed" (TIA Portal error code 0xFFD2 1A92 / 0xE7B3 depending on version) is raised during download when a STRUCT datatype is referenced but contains no members, or when a UDT has been declared but its data record was never edited. A typical scenario: the engineer adds a CONV instance, creates a new UDT to hold the converted value, and forgets to add a member to the UDT. The compiler treats the empty UDT as STRUCT END_STRUCT with no fields, which is invalid for download.
3. IEC 61131-3 Type Promotion Rules in TIA Portal
IEC 61131-3 (third edition, 2013) and its 2024 revision define the following implicit type promotions in textual languages:
-
BOOL → BYTE → WORD → DWORD → LWORD(bit-string widening) -
SINT → INT → DINT → LINT(integer widening, sign-preserving) -
USINT → UINT → UDINT → ULINT(unsigned integer widening) -
REAL → LREAL(floating widening)
There is no implicit promotion between the integer hierarchy and the real-number hierarchy. TIA Portal V16+ enforces this strictly at compile time for peripheral accesses, even though the CPU firmware could execute the conversion in one cycle. Therefore, the programmer must insert an explicit conversion.
4. Solution 1 — Direct INT → REAL with CONV
On S7-1200 firmware V4.0+ and S7-1500, the CONV (Convert) instruction directly accepts INT as the source and emits REAL at the output. The intermediate DINT step is not required for S7-1500, but it is still the recommended path on S7-1200 to avoid a deprecation warning in older TIA Portal versions.
4.1 LAD/FBD implementation
- Insert Basic Instructions → Conversion operations → CONV in the network.
- Set
INto the symbolic name of the analog input (e.g.,"AI_Channel_0"bound to%IW752). - Set
OUTto aREALtag (e.g.,"u1_REAL"). - Compile, then download.
4.2 SCL implementation
// Explicit INT to REAL conversion (TIA Portal V16+)
FUNCTION_BLOCK FB_MatlabSafe : FB_MatlabBase
VAR
u1_REAL : REAL;
u2_REAL : REAL;
END_VAR
BEGIN
u1_REAL := REAL#PIW752; // not legal, syntax error
// Correct:
u1_REAL := INT_TO_REAL("AI_Channel_0");
u2_REAL := INT_TO_REAL("AI_Channel_1");
y := u1_REAL + u2_REAL;
END_FUNCTION_BLOCK
The standard conversion operators in SCL are typed functions: INT_TO_REAL, DINT_TO_REAL, WORD_TO_REAL, BYTE_TO_REAL. Avoid the implicit REAL# cast on a peripheral word — the prefix REAL# performs a type literal interpretation of a constant, not a runtime conversion of a tag.
5. Solution 2 — INT → DINT → REAL (legacy-safe chain)
For TIA Portal V13/V14, or when the SCL editor generates a deprecation note on the direct INT_TO_REAL form, use the explicit two-step chain. This is also the path required if the source word is unsigned and the value can exceed 32 767 (e.g., a 0–10 V module set to unipolar 0–27 648, or a 4–20 mA loop read as 0–27 648).
// Two-step conversion chain
VAR
raw_DINT : DINT;
scaled_R : REAL;
END_VAR
BEGIN
raw_DINT := INT_TO_DINT(%IW752); // step 1: sign-extend
scaled_R := DINT_TO_REAL(raw_DINT); // step 2: bit-pattern to float
END_FUNCTION_BLOCK
The intermediate DINT prevents accidental truncation and keeps the editor's strict-type check satisfied on every TIA Portal version from V13 SP1 onward.
6. Solution 3 — Scale to engineering units with NORM_X and SCALE_X
For a real process value (temperature, pressure, flow), convert the raw 16-bit integer to a normalized 0.0–1.0 REAL with NORM_X, then to engineering units with SCALE_X. This is the Siemens-recommended pattern for AI modules; it is documented in the S7-1200 and S7-1500 system manuals (see Siemens Industry Online Support, entry ID 109755220 for S7-1200 and 109478121 for S7-1500).
6.1 Parameter block
| Block | Input | Meaning |
|---|---|---|
| NORM_X | VALUE | Raw peripheral word (INT) |
| MIN | Lower raw limit (e.g., 0) | |
| MAX | Upper raw limit (e.g., 27 648) | |
| RET_VAL | REAL in range 0.0 … 1.0 | |
| SCALE_X | VALUE | Output of NORM_X |
| MIN | Engineering low scale (e.g., 0.0 °C) | |
| MAX | Engineering high scale (e.g., 100.0 °C) | |
| RET_VAL | REAL in engineering units |
6.2 SCL call
// Scaling: 0–27648 raw -> 0.0–100.0 °C
VAR
rNorm : REAL;
rTempC : REAL;
END_VAR
BEGIN
rNorm := NORM_X(MIN := 0, VALUE := %IW752, MAX := 27648);
rTempC := SCALE_X(MIN := 0.0, VALUE := rNorm, MAX := 100.0);
END_FUNCTION_BLOCK
For bipolar inputs (±10 V, ±20 mA) the limits become -27648 to +27648. For 4–20 mA loops use 0 to 27648 only (4 mA → 0 counts is the Siemens convention with a 4-wire AI; for 2-wire modules check the module manual for the underrange/overrange threshold, typically 0 counts at < 3.6 mA).
7. Solution 4 — Eliminate the UDT "empty struct" error
The "A structure without components is not allowed" error is independent of the type conversion, but it surfaces in the same workflow. The fix is to populate the UDT body.
- Open PLC data types in the project tree.
- Select the UDT (e.g.,
User_data_type_1). - Inside the
STRUCTblock, add at least one member:
TYPE "User_data_type_1"
STRUCT
rValue : REAL; // engineering-unit value
bOverflow : BOOL; // optional flag
END_STRUCT;
END_TYPE
- Recompile the block that references the UDT.
- Re-download to the CPU.
If the UDT was used solely as a placeholder, either delete it from the block's VAR section or convert the placeholder tag to a simple REAL/DINT tag without a UDT wrapper.
8. Working SCL Code Templates
8.1 Safe wrapper for the MATLAB-style adder
FUNCTION_BLOCK "FB_SumReal"
{ S7_Optimized_Access := 'TRUE' }
VAR
u1_R : REAL;
u2_R : REAL;
y : REAL;
END_VAR
BEGIN
// Conversions happen at the I/O boundary, not inside the math
u1_R := INT_TO_REAL(%IW752);
u2_R := INT_TO_REAL(%IW754);
y := u1_R + u2_R;
END_FUNCTION_BLOCK
8.2 Variant with engineering-unit scaling
FUNCTION_BLOCK "FB_ScaledSum"
{ S7_Optimized_Access := 'TRUE' }
VAR
rTemp1 : REAL;
rTemp2 : REAL;
y : REAL;
END_VAR
BEGIN
rTemp1 := SCALE_X(MIN := 0.0, VALUE := NORM_X(MIN := 0, VALUE := %IW752, MAX := 27648), MAX := 100.0);
rTemp2 := SCALE_X(MIN := -50.0, VALUE := NORM_X(MIN := 0, VALUE := %IW754, MAX := 27648), MAX := 150.0);
y := rTemp1 + rTemp2;
END_FUNCTION_BLOCK
8.3 Graph block import pattern (Simulink PLC Coder)
If the FB is generated by Simulink PLC Coder, change the Inport block datatype from single (REAL) to int16, regenerate, then convert in the calling SCL program. This avoids the round-trip issue without modifying the generated code.
9. TIA Portal Version Compatibility Matrix
| TIA Portal | CPU firmware | INT_TO_REAL direct | NORM_X / SCALE_X | Empty-UDT error text |
|---|---|---|---|---|
| V13 SP1 | S7-1200 V4.0 | Limited (use chain) | Yes | "Structure without components is not allowed" |
| V14 SP1 | S7-1200 V4.2, S7-1500 V1.8 | Yes (V14+) | Yes | Same |
| V15.1 | S7-1500 V2.0 | Yes | Yes | Same |
| V16 | S7-1500 V2.6 | Yes (preferred) | Yes | Same |
| V17 | S7-1500 V2.9 | Yes | Yes | Same |
| V18 | S7-1500 V3.0 | Yes | Yes | Same |
| V19 | S7-1500 V3.1 | Yes | Yes | Same |
On S7-1200 firmware V4.0–V4.2, the compiler raises a warning if INT_TO_REAL is used directly without DINT; the runtime behaviour is correct. Update to firmware V4.4 (6ES721x-1xx40-0XB0) or later to remove the warning.
10. Verification Procedure
- Open the online block in TIA Portal with the CPU in RUN and force the AI channel to a known value (e.g., 0 V or 10 V from a calibrator).
- Open the Monitor & Force table; add the raw peripheral tag
%IW752and the converted tagu1_R. - Confirm that
u1_Requals the expectedREALvalue (e.g., 0.0 for 0 V on a 0–10 V module, 10.0 for 10 V). - Apply a step change (e.g., 5 V) and verify the value tracks within one OB1 cycle (~10 ms default on S7-1500, ~100 ms on S7-1200).
- For the scaled engineering value, cross-check with a calibrated reference instrument; tolerance is typically ±0.1 % of full scale at 25 °C for a 16-bit AI.
- Check the CPU diagnostic buffer for any overflow / wire-break events; overrange reads 32 767 or 32 511 depending on module family, and triggers a diagnostic interrupt if configured.
11. Error-Code Quick Reference
| Symptom | Likely cause | Fix |
|---|---|---|
| "Incompatible types INT to REAL" at PIW | Implicit conversion not allowed | Insert INT_TO_REAL or CONV block |
| "Structure without components is not allowed" | Empty UDT | Add member(s) to STRUCT, or remove UDT |
| Compile warning "Conversion may lose information" | 16-bit INT cast to 8-bit BYTE | Use DINT as intermediate step |
| Runtime value stuck at 0.0 | PIW address outside PII | Verify module slot and process-image partition (OB1 cycle must include the address) |
| Value reads as 32767 (overrange) | Input signal exceeds module range | Check wiring, scaling, and module configuration in device view |
| Negative real on unipolar 4–20 mA | Underrange bit set, INT value interpreted as signed | Use WORD_TO_REAL or mask the MSB with AND before conversion |
12. Common Pitfalls and Field Notes
-
Mixing optimized and non-optimized access. With Optimized block access enabled (default in V15+), symbolic peripheral tags are addressed via the symbol table, not the absolute
PIW. DirectPIW752in SCL still works if the symbolic name resolves to the same address. - Process-image partition mismatch. If the analog module is assigned to PIP 1 (e.g., for fast OB6x update) and the SCL FB runs in OB1, the value will be frozen at the OB1 update. Either move the FB to OB6x or assign the module to PIP 0.
-
Endianness in IEC 61131-3 vs. S7 convention. S7-1200/1500 stores
REALlittle-endian on the byte order shown in the monitor, matching the IEEE 754 binary32 layout. No byte-swap is required when converting from a 16-bit INT (only the lower 16 bits are used). -
LREAL on S7-1500. For high-precision math, use
LREAL(64-bit) andDINT_TO_LREAL.REALis 32-bit and loses precision beyond 7 significant digits. -
CONV block vs. type-conversion function. In SCL, prefer the typed function
INT_TO_REAL(...)over theCONVbox; the function form produces cleaner error messages and is supported in all language editors. -
MATLAB/Simulink-generated code. Always inspect the generated SCL for hidden
REALports. If the upstream model cannot be changed, add a Signal Specification block in Simulink forcing the Inport toint16, then regenerate.
13. Safety and Diagnostics
F_REAL_TO families) and the conversion must occur inside the F-runtime group. Generic CONV is not acceptable for SIL 2/3 paths.
For diagnostic monitoring, evaluate the SFC 51 / RD_SINFO (read system status) and the standard SFC 59 (RDREC) to obtain module diagnostics. Overrange and wire-break bits from the AI module's diagnostic record (record index 0) can be mapped to a BOOL tag and used in the same FB that performs the conversion.
14. Standards and References
- IEC 61131-3:2013, Programmable controllers — Part 3: Programming languages (data-type hierarchy, conversion rules).
- IEEE 754-2008, Standard for Floating-Point Arithmetic (REAL/LREAL binary layouts).
- Siemens S7-1200 Programmable Controller — System Manual, entry ID 109755220 on Siemens Industry Online Support (support.industry.siemens.com).
- Siemens S7-1500 / ET 200MP — System Manual, entry ID 109478121.
- Siemens STEP 7 SCL V16 — Programming and Operating Manual, entry ID 109751618.
Why does TIA Portal refuse to assign PIW752 directly to a REAL variable?
PIW is a 16-bit signed integer, while REAL is a 32-bit IEEE-754 float. The strict type checker in TIA Portal (per IEC 61131-3 promotion rules) does not allow an implicit INT-to-REAL promotion for peripheral I/O. Insert an explicit INT_TO_REAL function or a CONV block to perform the conversion.
Do I always need the INT → DINT → REAL chain, or is INT → REAL enough?
On S7-1500 CPUs and S7-1200 firmware V4.4 or later with TIA Portal V14+, INT_TO_REAL works directly and is the recommended form. Use the two-step INT → DINT → REAL chain on legacy S7-1200 firmware or when the compiler emits a precision/deprecation warning.
How do I scale a 0–27648 raw value to 0–100 °C engineering units?
Use NORM_X(MIN := 0, VALUE := %IW752, MAX := 27648) to obtain a normalized 0.0–1.0 REAL, then SCALE_X(MIN := 0.0, VALUE := <norm>, MAX := 100.0). The two blocks are documented in the S7-1200 and S7-1500 system manuals.
What causes the "A structure without components is not allowed" error?
The error is raised when a UDT (PLC data type) is declared with an empty STRUCT body. Add at least one member inside the STRUCT, or remove the UDT reference from your block's VAR section, then recompile and download.
Can I use a CONV block on a peripheral input that is configured for 4–20 mA?
Yes. Configure the AI module for 4–20 mA in device view (TIA Portal), then read the raw 0–27648 integer from the PII and convert with INT_TO_REAL. For underrange protection, mask the sign bit or use WORD_TO_REAL if your value never goes negative.