Siemens S7-300/400 Real to DInt Conversion: Fix 4.29B Overflow

David Krause11 min read
SiemensTIA PortalTroubleshooting
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

Overview

The STEP 7 v5.5 standard instruction TRUNC returns an unexpected value of 1,333,788,671 when a programmer attempts to convert the REAL constant 4,294,967,295.3 to a DINT. The result is not arithmetic garbage; it is a deterministic consequence of two coupled limits: the 32-bit DINT signed range, and the 24-bit mantissa precision of the 32-bit IEEE-754 REAL. The 4,294,967,295.3 value is outside the DINT range, and the value 4,294,967,295 cannot even be represented exactly as a 32-bit REAL.

This article dissects the bit-level encoding of the result, clarifies the difference between DINT, UDINT, DWORD, and LREAL on the S7-300/400 and S7-1200/1500 platforms, and documents every field-proven workaround for handling 32-bit unsigned integers and 64-bit floating-point values in legacy STEP 7 v5.5 projects.

Problem Description

Symptom: A ladder or FBD network using TRUNC (or ROUND) returns 1333788671 when the REAL input is set to 4,294,967,295.3.

Expected: 4,294,967,295 (the integer part of the constant).

Actual online value of MD / OUT: DW#16#4F7FFFFF interpreted by the PLC as signed DINT = +1,333,788,671.

Trigger values: Any REAL whose magnitude is > 2,147,483,647.0 (the positive DINT limit) or whose integer part is > 16,777,216 (the 24-bit mantissa boundary where single-precision REAL begins to lose 1-LSB accuracy).

Root Cause Analysis

Two independent constraints collide. Either one is sufficient to corrupt the result; the value 4,294,967,295.3 violates both.

Constraint 1: DINT Is a Signed 32-Bit Integer

Per the IEC 61131-3 data-type specification used by Siemens, DINT occupies 32 bits and is two's-complement signed. The mathematical range is:

DINT range: -2,147,483,648 ... 0 ... +2,147,483,647

The constant 4,294,967,295 is exactly 2^32 - 1 and lies outside the DINT positive range. When the runtime coerces the bit pattern 16#4F7FFFFF into a DINT, bit 31 is interpreted as a sign bit, producing a negative interpretation in the high range or a positive wrap to 1,333,788,671 in the user's example.

Constraint 2: 32-Bit REAL Cannot Represent 4,294,967,295 Exactly

IEEE-754 single precision uses 1 sign bit, 8 exponent bits, and a 23-bit mantissa (24 bits of precision with the implicit leading 1). The largest integer that can be represented exactly is 2^24 = 16,777,216. Values above this boundary are quantized to multiples of 2:

Hex Pattern REAL Value Notes
16#4F7FFFFF 4,294,967,040.0 Largest REAL < 2^32 (mantissa all-ones)
16#4F800000 4,294,967,296.0 First REAL ≥ 2^32 (mantissa = 0, exponent incremented)
16#4F800001 4,294,967,296.0 + 256.0 Next representable REAL above 2^32

The runtime cannot store the literal 4,294,967,295.3 in a 32-bit REAL. It rounds to the nearest representable value, which is 4,294,967,040.0 with the hex bit pattern 16#4F7FFFFF. The TRUNC instruction then performs the bit-level conversion and the user observes 1,333,788,671 at MD.

Data Type Comparison on S7-300/400 vs S7-1200/1500

Keyword Bits Signed? Range STEP 7 v5.5 (S7-300/400) TIA Portal (S7-1200/1500)
INT 16 Yes -32,768 to +32,767 Yes Yes
DINT 32 Yes -2,147,483,648 to +2,147,483,647 Yes Yes
UINT 16 No 0 to 65,535 No (use WORD + cast) Yes (V14+)
UDINT 32 No 0 to 4,294,967,295 No native type Yes (V14+)
DWORD 32 N/A Bit pattern 16#00000000 to 16#FFFFFFFF Yes Yes
REAL 32 Yes ±3.402823e+38 (≈ 7 decimal digits) Yes (IEEE-754 single) Yes
LREAL 64 Yes ±1.797693e+308 (≈ 15 decimal digits) No Yes (S7-1500 only)
LWORD 64 N/A Bit pattern No Yes (S7-1500 only)

Engineering note: STEP 7 v5.5 has no native UDINT or LREAL. The only legal 32-bit unsigned container is DWORD, which the editor treats as a bit-string without a numeric interpretation. Conversion math must be implemented explicitly in STL/SCL if the project must remain on S7-300/400 firmware.

Bit-Level Walkthrough: Why TRUNC Returns 1,333,788,671

  1. Compiler loads constant 4,294,967,295.3 into the REAL tag (MD100). The value is quantized to the nearest IEEE-754 single: 16#4F7FFFFF = 4,294,967,040.0.
  2. TRUNC instruction is called with IN = MD100 and OUT = MD104 (DINT). The instruction copies the 32 bits of the source verbatim into the destination register; the runtime does not re-interpret sign.
  3. Online monitor on MD104 displays the value as signed DINT. Bit 31 of 16#4F7FFFFF is 0 (positive), so the displayed integer is the lower 31 bits: 0x4F7FFFFF = 1,333,788,671.
  4. If the value had been rounded up to 16#4F800000, bit 31 would be 1, and the displayed DINT would be -2,147,483,648 — an apparent negative result that alarms most operators.

Both outcomes are correct bit-copy operations but incorrect integer conversions because DINT is the wrong destination type for any value > 2,147,483,647.

Solution Path Selection

Choose a path based on controller generation and the magnitude of the data being processed.

If your project runs on And the value is Use this fix
S7-300/400 (STEP 7 v5.5) ≤ 2,147,483,647 Validate input range; TRUNC/ROUND work correctly
S7-300/400 (STEP 7 v5.5) ≤ 4,294,967,295 (unsigned 32-bit) Move to DWORD; perform unsigned compare in STL
S7-300/400 (STEP 7 v5.5) > 16,777,216 (REAL precision loss) Scale input to engineering units first; or use 64-bit FB library
S7-1200/1500 (TIA Portal) ≤ 4,294,967,295 (unsigned 32-bit) Declare tag as UDINT; use REAL_TO_UDINT
S7-1500 (TIA Portal) > 4,294,967,295 (64-bit float) Use LREAL; REAL_LREAL_TO_UDINT from extended instructions

Solution 1: Range Validation (S7-300/400, all platforms)

Before calling TRUNC or ROUND, test whether the REAL input exceeds the DINT positive boundary. The pattern is implemented in STL below; the same logic can be built in LAD/FBD with two comparators.

// STL example - validate REAL input range
A     "input_real"          // REAL tag, e.g. MD100
L     2.147483648e+09       // DINT positive max as REAL
>R                              // input_real > max?
JC    OVER                   // jump if overflow
// input is safe; proceed
TRUNC                          // out = DINT
T     "output_dint"
JU    CONT
oVER: L     0
T     "output_dint"            // clamp to 0, or set error flag
SET
S     "overflow_flag"          // raise diagnostic bit
CONT: NOP 0

Add an underflow test against -2.147483648e+09 to fully cover the negative half. This pattern alone resolves 80% of field complaints when the underlying process value legitimately fits in 31 bits.

Solution 2: Use DWORD as a 32-Bit Unsigned Container (S7-300/400)

STEP 7 v5.5 has no UDINT, but a DWORD receives the bit pattern of any REAL with full 32-bit fidelity. After moving the REAL to a DWORD, use unsigned STL operations.

// Copy REAL to DWORD, then compare as unsigned
L     "input_real"         // MD100 - REAL
T     "temp_dword"         // MD104 - DWORD (same bit pattern)

// Unsigned test against 16#80000000 boundary
L     "temp_dword"
L     W#16#8000_0000       // 2^31 = 2,147,483,648
>D                              // unsigned compare
JC    NEG_VAL              // bit 31 set = value > 2,147,483,647

// Value is in 0..2,147,483,647 - safe to TRUNC
TRUNC
T     "output_dint"
JU    DONE

NEG_VAL: // Treat as DWORD-only; no DINT math
      L     "temp_dword"
      T     "output_dword"     // display as 16#... in HMI
DONE: NOP 0

Caution: A DWORD displayed in WinCC flexible / TIA HMI as a decimal number will appear with the signed interpretation. Configure the HMI tag as Hex or use a manual scaling factor (e.g., subtract 2^32 in the HMI script) to recover the unsigned value.

Solution 3: Native UDINT and LREAL on S7-1200/1500 (TIA Portal)

The S7-1200 (firmware V4.0+) and S7-1500 add full unsigned-integer and 64-bit-float support. Declare the target tag as UDInt or LReal and the compiler selects the correct conversion instruction.

Source Destination Instruction in TIA Portal Behavior on overflow
REAL DINT REAL_TO_DINT / TRUNC Returns DINT min; sets ENO = 0
REAL UDINT REAL_TO_UDINT (Extended instructions) Returns 0; sets ENO = 0
LREAL DINT LREAL_TO_DINT Returns DINT min; sets ENO = 0
LREAL UDINT LREAL_TO_UDINT Returns 0; sets ENO = 0
LREAL LINT LREAL_TO_LINT Returns LINT min; sets ENO = 0

The official TIA Portal V20 reference for DINT conversion options is published at Explicit conversion of DINT (S7-1500). Use the ENO output to drive an overflow diagnostic in the same network — a faulted conversion with ENO = 0 is the cleanest way to surface the problem to WinCC Unified or HMI tags.

Solution 4: 64-Bit REAL Library for S7-300/400

For legacy CPUs that must continue in service but handle values > 2^24 with full precision, install a user-defined 64-bit floating-point FB. The reference implementation by Piotr M. is published on the Siemens support portal and includes source SCL for:

  • FB_DoubleFloat_Add — LREAL addition on two 32-bit halves
  • FB_DoubleFloat_Sub — LREAL subtraction
  • FB_DoubleFloat_Mul — LREAL multiplication (Karatsuba)
  • FB_DoubleFloat_Div — LREAL division with Newton-Raphson reciprocal
  • FC_DoubleFloat_Trunc — 64-bit REAL → DINT (with overflow flag)

Each function manipulates two DWORDs (high and low halves) and tracks sign, exponent, and 52-bit mantissa independently. The library is the only viable path on an S7-315-2 PN/DP or S7-417H that cannot be replaced.

Step-by-Step Fix (S7-300/400, SCL Example)

The following SCL block is a drop-in replacement for the failing TRUNC network. It performs range validation, returns a DWORD (bit pattern) for the unsigned half, and raises an overflow flag.

FUNCTION_BLOCK FB_RealToUnsigned32
VAR_INPUT
  rValue  : REAL;          // input real
END_VAR
VAR_OUTPUT
  dwOut   : DWORD;         // unsigned 32-bit result
  bError  : BOOL;          // TRUE on overflow / NaN
END_VAR
VAR
  dTest   : DINT;
END_VAR
BEGIN
  bError := FALSE;
  // NaN / Inf guard
  IF (rValue <> rValue) OR (rValue = 1.0e+38) OR (rValue = -1.0e+38) THEN
    dwOut := 16#00000000;
    bError := TRUE;
    RETURN;
  END_IF;
  // In-range & positive path
  IF rValue >= 0.0 AND rValue <= 4.294967295e+09 THEN
    dwOut := REAL_TO_DWORD(rValue);
  ELSE
    dwOut := 16#00000000;
    bError := TRUE;
  END_IF;
END_FUNCTION_BLOCK

Compile the source into the S7 program (SCL compiler V5.3+), call the FB in OB1 or OB35, and route bError to a retentive marker for HMIs.

Verification

  1. Online watch table: Force the input REAL tag to 4.294967040e+09 and confirm the DWORD output reads DW#16#4F7FFFFF. Display in HEX mode in the watch table to avoid signed interpretation.
  2. Boundary tests: Force 2,147,483,647.0 (max DINT) and 4,294,967,295.0 (max UDINT). Both must return the correct hex pattern and an unambiguous overflow flag.
  3. HMI round-trip: Display the DWORD tag in WinCC flexible / TIA HMI configured as Hexadecimal 32-bit. Verify the operator sees 0x4F7FFFFF, not 1,333,788,671.
  4. Cross-check with calculator: Convert 4,294,967,295 decimal to hex — result is 0xFFFFFFFF. Any block returning a different pattern under any input indicates a misconfigured data type or a sign-extended move.
  5. Regression test: Capture the original fault scenario (REAL = 4,294,967,295.3) and confirm the FB returns dwOut = 0x4F7FFFFF and bError = TRUE.

Troubleshooting Matrix

Observed Result Likely Cause Corrective Action
1,333,788,671 TRUNC on REAL ≈ 4.29e9, signed DINT view Switch destination to DWORD, or scale input
-2,147,483,648 Bit 31 set in source REAL (≥ 2^31) Use DWORD, validate range upstream
0 with ENO = 0 in TIA Overflow detected by REAL_TO_UDINT Inspect input source; widen to LREAL if needed
HMI shows -1 instead of 4,294,967,295 DWORD tag displayed as signed DINT Change HMI tag format to Hex or unsigned Decimal 32
Step7 rejects UDINT declaration STEP 7 v5.5 does not support UDINT Use DWORD; convert to unsigned math manually
REAL drifts after 16,777,216 24-bit mantissa limit of single precision Scale value to engineering units (÷1000) before conversion

Engineering Best Practices

  • Document the implicit assumption. If a tag holds a value > 2^24, mark it in the symbol table with the suffix _L (large) and route it through LREAL or the 64-bit library.
  • Always wire ENO. On S7-1200/1500, the explicit conversion instructions report overflow through ENO. Ignoring ENO hides every range bug that this article describes.
  • Standardize HMI formats. Configure every DWORD tag in WinCC Unified / flexible with the Hexadecimal or Decimal unsigned 32-bit representation. The signed-decimal default is the root of the most common operator complaints.
  • Validate in OB100 / startup. Run range and NaN checks once on first scan and latch a CFG_ERR bit. A misconfigured REAL constant at load time is otherwise silent until the first conversion fires.
  • Prefer LREAL on new S7-1500 projects. Even when 32-bit range is sufficient today, a future sensor or counter change can push the value past 2^24. Starting in LREAL is cheaper than retrofitting a fleet.

FAQ

Why does TRUNC return 1,333,788,671 when I pass 4,294,967,295.3?

The 32-bit REAL cannot store 4,294,967,295.3 exactly; it rounds to 4,294,967,040.0 with the bit pattern 16#4F7FFFFF. TRUNC copies those 32 bits into a DINT, and the PLC's signed interpretation yields +1,333,788,671. The value 4,294,967,295 is also outside the DINT range (-2,147,483,648 to +2,147,483,647), so DINT is the wrong destination type.

Does Siemens S7-300/400 support UDINT in STEP 7 v5.5?

No. STEP 7 v5.5 has no native UDINT. Use DWORD as a 32-bit unsigned container and perform any unsigned math in STL with the >D, <D, and unsigned-move primitives. UDINT and UINT are introduced for S7-1200/1500 in TIA Portal V14+.

What is the difference between DINT, UDINT, and DWORD?

DINT is a 32-bit signed integer (-2,147,483,648 to +2,147,483,647). UDINT is a 32-bit unsigned integer (0 to 4,294,967,295). DWORD is a 32-bit bit string with no numeric interpretation. Bits 0-31 of any DINT or UDINT can be re-interpreted as a DWORD without losing information.

Can I represent 4,294,967,295 exactly in a 32-bit REAL?

No. The nearest 32-bit REALs are 4,294,967,040.0 (16#4F7FFFFF) and 4,294,967,296.0 (16#4F800000). To represent values above 2^24 = 16,777,216 without precision loss, use 64-bit LREAL on S7-1500 or the 64-bit FP library on S7-300/400.

How do I detect an overflow in TIA Portal explicit conversion?

Every explicit conversion instruction in TIA Portal (REAL_TO_DINT, REAL_TO_UDINT, LREAL_TO_LINT, etc.) sets ENO = 0 on overflow, NaN, or out-of-range input. Wire ENO to a diagnostic flag and the conversion result to a safe default; see the Siemens TIA Portal V20 reference for DINT conversion for the full instruction list.

Back to blog