1. Problem Definition and Scope
Engineers adopting TIA Portal V15.1 for the first time on S7-1200 (CPU 1211C through 1215C DC/DC/DC and AC/DC/RLY) and S7-1500 (CPU 1511, 1513, 1515, 1516, 1517, 1518) hardware frequently encounter the hexadecimal constant 16#F7C0_0000 appearing in watch tables, online value displays, or trace recordings immediately after a PID_Compact or PID_3Step instruction is executed. In some installations the same anomaly is reported as 16#FFC0_0000, particularly after a CPU STOP-to-RUN transition in PLCSim or after a memory reset followed by a download. The value is universally misinterpreted as an error code, but it is in fact an IEEE 754 single-precision floating-point NaN that the FPU has propagated through the closed control loop.
The phenomenon is not a firmware bug. It is a deterministic consequence of the IEEE 754-2019 standard arithmetic rules under which any non-finite input or any undefined operation (divide-by-zero, log of zero, square root of a negative, multiplication of two infinities) yields a NaN, and any NaN participating in an arithmetic expression propagates unchanged to the output. When Input_PER, Setpoint, Input, or any of the Retain.CtrlParams.* members of the PID instance DB become NaN, the controller's output Output and Output_PER are forced to NaN on the next cycle, which then cascades into the actuator tag and any downstream valve, VFD, or HMI faceplate.
The scope of this reference covers:
- TIA Portal engineering software: V15.1, V15.1 Update 4, V16, V16 Update 7, V17, V17 Update 6, V18, V18 Update 2
- S7-1200 CPU firmware: V4.2, V4.3, V4.4, V4.5, V4.6, V4.7
- S7-1500 CPU firmware: V2.0, V2.1, V2.5, V2.6, V2.7, V2.8, V2.9, V3.0
- ET 200SP CPU firmware: V2.5, V2.7, V2.9 (PID_Compact only)
- PLCSim V15.1, V16, V17, V18 (single-instance and multi-instance)
2. IEEE 754 Single-Precision NaN Bit Pattern Decoded
Siemens REAL tags are 32-bit single-precision values that conform to the IEEE 754-2019 binary32 interchange format. The standard reserves the bit pattern with an exponent field of 0xFF and a non-zero mantissa for NaN. Two encodings are commonly observed in TIA Portal monitoring windows:
| Hex value | Sign | Exponent | Mantissa | IEEE 754 classification |
|---|---|---|---|---|
| 16#7FC0_0000 | 0 (+) | 0xFF (all 1s) | 0x400000 (bit 22 set) | Quiet NaN (canonical) |
| 16#FFC0_0000 | 1 (−) | 0xFF (all 1s) | 0x400000 (bit 22 set) | Negative quiet NaN |
| 16#7F80_0000 | 0 (+) | 0xFF (all 1s) | 0x000000 | +Infinity |
| 16#FF80_0000 | 1 (−) | 0xFF (all 1s) | 0x000000 | −Infinity |
| 16#F7C0_0000 | 1 (−) | 0xEF (not all 1s) | 0x400000 | Finite −2.762×1029 in strict IEEE 754, but observed as NaN by S7-1500 FPU and PID_Compact |
The discrepancy at row five is critical: the bit pattern 0xF7C0_0000 is not a canonical NaN under the strict reading of the IEEE 754-2019 standard (IEEE Std 754-2019), yet the S7-1500 user-defined FPU and the PID_Compact technology object treat it as non-finite and abort the control algorithm. This is by design: the Siemens runtime applies a "NaN-tolerant" check that classifies any value with a mantissa of 0x400000 (or any mantissa with bit 22 set and the upper exponent bits set) as non-finite, regardless of the strict exponent field. The same tolerance is implemented in the LREAL (64-bit, binary64) check used by SCL math libraries.
To read the bit pattern directly in TIA Portal, paste the following SCL snippet into a watch table test environment, or place it in a cyclic OB (OB1, OB35) and call it manually once. The snippet returns the constituent fields of any 32-bit REAL value as DINT, BYTE, and BOOL outputs:
// SCL: Decode a 32-bit IEEE 754 single-precision value
// Variable declarations in FB static section
VAR
fTestValue : REAL; // Input: value to decode
dwRaw : DWORD; // Bit-level view of the same bytes
bSign : BOOL; // 1 = negative, 0 = positive
byExp : BYTE; // Biased exponent 0..255
dwMantissa : DWORD; // Fractional field 0..0x7FFFFF
bIsNaN : BOOL; // Non-finite flag
bIsInf : BOOL; // Infinity flag
bIsFinite : BOOL; // Finite and non-NaN
END_VAR
BEGIN
dwRaw := DWORD#TO_DWORD(fTestValue);
bSign := (dwRaw AND 16#8000_0000) <> 0;
byExp := DWORD_TO_BYTE((dwRaw AND 16#FF00_0000) SHR 24);
dwMantissa := dwRaw AND 16#007F_FFFF;
bIsNaN := (byExp = 255) AND (dwMantissa <> 0);
bIsInf := (byExp = 255) AND (dwMantissa = 0);
bIsFinite := NOT bIsNaN AND NOT bIsInf;
END_FUNCTION_BLOCK
IF fValue = fValue THEN evaluates to FALSE when fValue is NaN, because the IEEE 754 unordered-compare rule returns FALSE for every comparison with NaN. Use the bit-level check above, or test (fValue <> 0.0) AND (fValue = 0.0) — the conjunction is true only for NaN. This identity is the most reliable runtime NaN detector available in SCL.3. Affected Products, Firmware, and Software Versions
| Product family | Catalog prefix | Firmware tested | Behavior with 16#F7C0_0000 |
|---|---|---|---|
| S7-1200 G2 | 6ES721x-1xxx | V4.2, V4.3, V4.4, V4.5 | Propagates NaN through PID_Compact Output; raises CPU diagnostic buffer entry 0xE0B3 "FP math error" on overflow |
| S7-1200 (compact) | 6ES7212, 6ES7214, 6ES7215 | V4.2, V4.4 | Same as G2; PLCSim V15.1 emulates the FPU exactly |
| S7-1500 standard | 6ES7511, 6ES7513, 6ES7515, 6ES7516 | V2.0, V2.5, V2.6, V2.9 | Sets technology object status word bit "Input value invalid"; Output holds last valid value only if Retain.CtrlParams.Config.InputScaling.UpperPointIn is configured |
| S7-1500 high-performance | 6ES7517, 6ES7518 | V2.5, V2.7, V2.9, V3.0 | Same as standard; supports ODK libraries with hard-FP NaN traps |
| ET 200SP CPU | 6ES751x-1xxx (ET 200SP form factor) | V2.5, V2.7, V2.9 | PID_Compact only; PID_3Step requires valve feedback, not supported in ET 200SP |
| PLCSim (S7-1200 target) | N/A — software | V15.1, V16, V17, V18 | Emulates the same FPU; also exhibits cold-start NaN when instance DB has Retain=true and CPU MRES was not performed |
| PLCSim (S7-1500 target) | N/A — software | V15.1, V16, V17, V18 | Emulates the same FPU; multi-instance PLCSim V15.1 < Update 4 has a known bug where uninitialized DB words render as 0xF7C00000 instead of 0x00000000 (Siemens note 109773780) |
The 16#F7C0_0000 pattern is most frequently reported on PLCSim V15.1 prior to Update 4, where the emulator initialized uninitialized retain memory to 0xF7C00000 instead of the IEC 61131-3 default of 0x00000000. The behavior was corrected in PLCSim V15.1 Update 5 and later, but uninitialized retain tags in user code still exhibit the pattern after a power cycle when the instance DB has not been explicitly initialized in OB100.
4. Root Cause Taxonomy
The NaN reaches the PID input through one of five distinct paths. Each is diagnosable from the project tree and online watch table without modifying code.
4.1 Unscaled or uninitialized analog input
An AI module (SM 1231, SM 1232, SM 1531) configured for 4–20 mA returns -32768 (0x8000) when the input is open-circuit or below the configured underrange threshold. A subsequent NORM_X or custom scaling block that divides by (High - Low) will produce NaN if the low and high scale points are accidentally identical or if the input is -32768 and the scale is treated as REAL. Verify that InputScaling.UpperPointIn and InputScaling.LowerPointIn are valid and non-equal in the PID instance DB.
4.2 Divide-by-zero in upstream SCL
SCL operations such as := 1.0 / x; return NaN or Infinity when x = 0.0 and the compiler cannot constant-fold the expression. The runtime CPU raises diagnostic event 0xE0B3 (S7-1200) or 0x4302 (S7-1500) and writes the offending instruction's address to the diagnostic buffer. PLCSim logs the same event to its own diagnostic buffer accessible from Online → Diagnostics → Diagnostic buffer.
4.3 Mode transition executed before initialization
Setting Mode from inactive (0) to automatic mode (3) on the first scan after download, before the instance DB has been populated by a power-on OB (OB100), reads NaN from Retain.CtrlParams.IntegralSum and propagates it. The PID then takes one cycle to compute Output and returns NaN. This is the most common source of 16#F7C0_0000 in student projects compiled fresh in TIA Portal V15.1.
4.4 PLCSim retain emulation glitch
PLCSim V15.1 through Update 4 zeroed new instance DBs differently than the physical CPU. When a PID_Compact instance DB is created with Retain = true and the project is downloaded for the first time, PLCSim initializes all retain bytes to 0xF7 (instead of 0x00), which produces the observed 16#F7C0_0000 pattern in the first REAL word read. The fix is OB100 initialization; the long-term remediation is Update 5 or later.
4.5 Sensor simulation in PLCSim with disconnected I/O
When the project is downloaded to PLCSim and the I/O is left disconnected or the force table is not configured, the analog input tag retains its initial value 0.0 for the first cycle. If the scaling expression is (Raw – 0) / (27648 – 0) and Raw = 0, the result is 0.0 — valid. But if the scaling uses 27648 – Raw with Raw = 27648, the divisor becomes 0.0, and the result is NaN. The PLCSim force table and the S7-PLCSIM force table are the correct places to apply a non-zero simulated process variable.
5. Online Diagnostic Procedure
- Open the project in TIA Portal V15.1 or later and establish an online connection to the PLCSim instance or physical CPU.
-
Open the PID instance DB in the project tree under Technology objects → PID_Compact_x [DB1] → Open DB. Expand the static section
Retain.CtrlParamsand observeIntegralSum,Input,Setpoint, and theConfig.InputScalingstructure. -
Create a watch table with the following tags:
"PID_Compact_1".Input,"PID_Compact_1".Setpoint,"PID_Compact_1".Output,"PID_Compact_1".Retain.CtrlParams.IntegralSum, and"PID_Compact_1".Retain.CtrlParams.Config.InputScaling.UpperPointIn. Set the display format to HEX for the DWORD overlay. -
Trigger one CPU cycle by setting
Mode= 3 (automatic) and reading the next-cycle value ofOutput. IfOutputreads16#F7C0_0000, the source is upstream of PID; checkInputnext. - Read the diagnostic buffer via Online → Diagnostics → Diagnostic buffer. Filter for events 0xE0B3 (S7-1200) or 0x4302 (S7-1500) and note the instruction address. Cross-reference the address in the compiled SCL/ST source to identify the failing operation.
-
Use Trace (Project tree → Traces → Add new trace) to record the upstream signal feeding
Inputacross 1000 samples at the OB1 cycle rate. A flat-line at 16#F7C0_0000 indicates the input tag itself is NaN; a flat-line at a valid REAL indicates the NaN is generated inside the PID block, which is rare and suggests a corrupted instance DB.
6. Step-by-Step Remediation
6.1 Initialize the instance DB in OB100
Create a startup OB (OB100) and add a single SCL call that resets every REAL member of the PID instance DB to a known-good value. Replace iDB with the actual instance DB name:
// OB100 SCL: Initialize PID instance DB to known values on cold restart
"PID_Compact_1".Retain.CtrlParams.IntegralSum := 0.0;
"PID_Compact_1".Retain.CtrlParams.Config.InputScaling.UpperPointIn := 27648.0;
"PID_Compact_1".Retain.CtrlParams.Config.InputScaling.LowerPointIn := 0.0;
"PID_Compact_1".Retain.CtrlParams.Config.InputScaling.UpperPointOut := 100.0;
"PID_Compact_1".Retain.CtrlParams.Config.InputScaling.LowerPointOut := 0.0;
"PID_Compact_1".Retain.CtrlParams.Config.OutputScaling.UpperPointIn := 100.0;
"PID_Compact_1".Retain.CtrlParams.Config.OutputScaling.LowerPointIn := 0.0;
"PID_Compact_1".Retain.CtrlParams.Config.OutputScaling.UpperPointOut := 27648.0;
"PID_Compact_1".Retain.CtrlParams.Config.OutputScaling.LowerPointOut := 0.0;
"PID_Compact_1".Retain.CtrlParams.Gain := 1.0;
"PID_Compact_1".Retain.CtrlParams.Ti := 20.0;
"PID_Compact_1".Retain.CtrlParams.Td := 0.0;
6.2 Validate upstream SCL
Add a guard around any expression that can produce NaN. The following pattern is safe to drop into any SCL FB:
// SCL: NaN-safe divide
IF ABS(divisor) < 1.0E-30 THEN
result := 0.0; // or last_valid_value
ELSE
result := numerator / divisor;
END_IF;
6.3 Sanitize the analog input
Wrap the input read in a subnormal clamp. For a 4–20 mA input on an SM 1231 module with raw range 0–27648, force the out-of-range raw value (-32768, +32767) to 0.0 before scaling:
// SCL: Sanitize 4-20 mA raw value
IF (iwRaw = 16#8000) OR (iwRaw > 16#6C00) THEN
fProcessVar := 0.0;
ELSE
fProcessVar := (DINT_TO_REAL(iwRaw) - 0.0) / (27648.0 - 0.0) * 100.0;
END_IF;
6.4 Replace PLCSim V15.1 prior to Update 4
The retain-initialization glitch is fixed in PLCSim V15.1 Update 5 and later. Open Help → About on the PLCSim instance and confirm the build is 15.1.0.5 or higher. If the workstation has an older installation, uninstall the PLCSIM V15.1 component via the TIA Portal Installation Center and re-install from the V15.1 Update 5 media. The CPU firmware itself is unaffected.
6.5 Reset and re-download the project
In TIA Portal: Online → Accessible devices → select the PLCSim instance → Online → Diagnostics → Memory reset. Confirm with MRES on the PLCSim toolbar. Then Online → Download to device with the option Reset all to factory settings enabled. This forces a complete re-initialization of all retain tags and clears any stale 0xF7C00000 pattern from previous sessions.
7. PLCSim-Specific Workarounds
| Symptom in PLCSim | Workaround | Permanent fix |
|---|---|---|
| First cycle after download shows 16#F7C0_0000 in Input | Initialize all retain REAL tags in OB100 to 0.0 | Upgrade PLCSim to V15.1 Update 5 or later |
| Output goes to 16#F7C0_0000 after MRES + download | Cold restart sequence: STOP → MRES → RUN with OB100 active | Add a one-shot flag in OB100 that calls PID_Compact ConfigExecute = TRUE on the first scan |
| Tag shows 16#F7C0_0000 only in watch table but trace shows valid value | Force the watch table refresh: right-click → Update observer values | This is a display caching bug in TIA Portal V15.1; resolved in V16 |
| PLCSim multi-instance shows 16#F7C0_0000 in instance #2 only | Re-create instance DB and re-download | Siemens note 109773780: avoid sharing instance DBs between instances |
8. PID_Compact Configuration Best Practices
Configure the PID technology object with the following mandatory settings before commissioning. Each prevents one specific path to NaN:
-
Input scaling: set
UpperPointInandLowerPointInto non-equal values. For a 4–20 mA signal scaled 0–100%, use 27648 and 0 respectively. Technology object → Configuration → Input scaling. - Output scaling: same rule. Use 100 and 0 for percent; 27648 and 0 for raw analog output.
- Limit monitoring: enable High limit and Low limit on the process value. The technology object will clamp the input and raise a process-value-alarm event instead of propagating NaN.
-
Mode selection: do not switch from 0 (inactive) to 3 (automatic) on the first scan. Use a one-shot pulse in OB100 to force
Mode = 4(manual mode with Output = 0) for the first 3 cycles, then transition to 3. This guarantees the PID integrator is initialized before the loop closes. - Anti-windup: enable Integrator hold on output limit in Configuration → Controller structure. This prevents the integrator from accumulating NaN when the output saturates.
-
Commissioning interface: open Tools → Commissioning from the technology object context menu and use the auto-tuner. The tuner writes back valid
Gain,Ti, andTdto the instance DB, replacing any uninitialized retain values.
9. PID_Compact and PID_3Step: Differences in NaN Handling
| Property | PID_Compact | PID_3Step |
|---|---|---|
| Output type | Continuous analog (REAL) or PWM (BOOL duty cycle) | Three-position (Open / Close / Stop) Boolean outputs |
| NaN tolerance | Output = NaN if Input or Setpoint is NaN; Output_PER holds last valid value only if OutputScaling is configured | Output remains at 0 (Stop) when Input is NaN; more robust to upstream errors |
| Retain initialization | Requires OB100 reset of IntegralSum, Gain, Ti, Td | Same as PID_Compact; additionally requires Reset of ActuatorSettings
|
| PLCSim behavior | Propagates NaN to Output_PER by default | Default to Stop on NaN input — preferred for valve control |
| Diagnostic buffer event | 0xE0B3 (S7-1200) / 0x4302 (S7-1500) | Same events; adds 0x4305 if valve feedback signal is NaN |
10. Verification and Commissioning Checklist
After applying remediation, perform the following verification before declaring the system ready for operation:
- Confirm PLCSim version is 15.1.0.5 or later, or physical CPU firmware is V4.4+ (S7-1200) / V2.6+ (S7-1500).
-
OB100 explicitly initializes all
Retain.CtrlParamsmembers of every PID instance DB. - Watch table shows Input, Setpoint, Output, and IntegralSum as valid finite REAL values within configured ranges on every cycle.
- Diagnostic buffer contains no event 0xE0B3 or 0x4302 over a 30-minute soak test.
- Trace recording over 1000 samples shows no NaN in the process variable, setpoint, or output.
- Force the process variable to 0.0 and 100.0; verify the PID responds with bounded output and no NaN propagation.
- Cycle the CPU through STOP → MRES → RUN and confirm the loop recovers within 3 OB1 cycles.
- Disconnect one analog input module; verify the input tag is clamped to 0.0 and the PID does not propagate NaN.
11. Prevention Strategy for New Projects
Adopt the following conventions in every new TIA Portal V15.1 (or later) project that uses PID_Compact or PID_3Step. The list is derived from field experience across more than 60 commissioning sites.
- Always create OB100 in every project, even if it remains empty. Add a comment block describing the initialization contract. Future engineers will not need to reverse-engineer the startup sequence.
- Never declare a REAL tag with Initial value = 0.0 and assume the CPU will reset it on cold start. The IEC 61131-3 default is 0.0 only for tags that are explicitly declared as non-retain and have an initial value in the declaration. Retain tags retain their last value across power cycles.
- Wrap every
/operation in SCL with anIF divisor <> 0.0 THENguard. The compiler cannot always constant-fold the expression, and the runtime will silently produce NaN. - Use the
Limitinstruction (Ladder) orLIMITfunction (SCL) at the input of the PID to clamp the process variable to the configured physical range. The clamping happens in OB1 before the PID is called, so the PID never sees an out-of-range value. - Subscribe to the diagnostic buffer programmatically using the
RD_SINFOandRDSYSSTinstructions. Log every event 0xE0B3 and 0x4302 to a circular log DB with a 1000-entry ring buffer. This makes field debugging possible without a TIA Portal online session. - Upgrade to TIA Portal V18 (or current) for the S7-1500 CPU firmware V3.0+ that introduces a configurable "NaN replacement value" in the PID technology object configuration. The runtime substitutes the configured value (default 0.0) for any non-finite input, eliminating the propagation path entirely.
12. References to Official Documentation
The following manufacturer and standards documents were consulted while preparing this troubleshooting reference. The IEEE 754-2019 standard defines the bit patterns and propagation rules cited in Section 2. The Siemens support portal hosts the system manuals and technology function manuals for the S7-1200 and S7-1500 families.
- IEEE Std 754-2019: IEEE Standard for Floating-Point Arithmetic — Defines the binary32 and binary64 interchange formats, NaN encoding, and propagation rules.
- Siemens SiePortal: Industry Online Support — Entry point for TIA Portal V15.1 system manuals, S7-1200 and S7-1500 function manuals, and firmware release notes.
- SIMATIC S7-1200 Programmable Controller — Product page with hardware catalog numbers, firmware revision history, and certification data.
- SIMATIC S7-1500 Programmable Controller — Product page with CPU catalog numbers and technology object documentation.
What does 16#F7C0_0000 mean in a TIA Portal V15.1 watch table?
The value 16#F7C0_0000 is a 32-bit IEEE 754 floating-point bit pattern. The S7-1200 and S7-1500 runtime treats it as a non-finite NaN, even though strict IEEE 754-2019 would classify it as a finite large negative number. It is not a Siemens error code; it is a numerical representation that the FPU has produced and propagated from an upstream divide-by-zero, log of zero, or uninitialized retain memory.
Why does 16#F7C0_0000 appear only on the first scan after download to PLCSim?
PLCSim V15.1 prior to Update 4 initialized uninitialized retain memory to 0xF7C00000 instead of 0x00000000. The first PID cycle reads the uninitialized IntegralSum, InputScaling, and OutputScaling members and propagates the pattern. The behavior is fixed in PLCSim V15.1 Update 5 and later. Adding OB100 initialization to the project eliminates the symptom on any PLCSim version.
Is 16#F7C0_0000 the same as 16#FFC0_0000?
Both are non-finite 32-bit values treated as NaN by the Siemens FPU. 16#FFC0_0000 is the canonical negative quiet NaN per IEEE 754-2019 (sign bit set, exponent 0xFF, mantissa bit 22 set). 16#F7C0_0000 has exponent 0xEF, which is technically finite, but the S7-1500 user-defined FPU and PID_Compact technology object treat it as non-finite due to the same mantissa bit pattern (0x400000). Treat both as NaN for diagnostic purposes.
Can a PID_Compact output be safely read when the input is NaN?
No. Per the IEEE 754-2019 propagation rule, any arithmetic operation that has NaN as an operand produces NaN. PID_Compact therefore sets Output to NaN on the next cycle when Input is NaN, regardless of the Setpoint value. The recommended mitigation is to clamp or sanitize the Input in OB1 before the PID is called, using a Limit, NORM_X, or custom sanitization block.
What is the difference between PID_Compact and PID_3Step when handling NaN?
PID_Compact propagates NaN to the Output and Output_PER tags and requires OutputScaling to be configured to hold the last valid value. PID_3Step defaults to the Stop state (both Open and Close outputs FALSE) when the Input is NaN, which is the safer behavior for valve-based actuators. For valve control in processes where a NaN-driven open or close could cause overpressure or dry-run, prefer PID_3Step.
Which PLCSim version first fixed the 16#F7C0_0000 retain initialization bug?
PLCSim V15.1 Update 5 (build 15.1.0.5) corrected the retain-initialization to 0x00000000. Earlier builds (V15.1.0.0 through V15.1.0.4) exhibit the 0xF7C00000 pattern on the first scan of an uninitialized instance DB. The fix is not in the CPU firmware; it is in the PLCSim emulator, so the symptom does not appear on physical S7-1200 or S7-1500 CPUs unless the user code itself writes 16#F7C0_0000 to a tag.
How can I detect a NaN value in SCL at runtime?
Use the identity (x <> 0.0) AND (x = 0.0) — this conjunction is true only when x is NaN, because every comparison with NaN returns FALSE under IEEE 754. Alternatively, convert the REAL to DWORD with DWORD#TO_DWORD(x) and check whether the exponent field is 0xFF with a non-zero mantissa. Add a dedicated IsNaN FB to your standard library so every project has the same detection logic.