Resolving Siemens S7 BCD Conversion Error in Counter Operations

David Krause12 min read
HMI ProgrammingSiemensTroubleshooting
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

BCD conversion errors are a class of programming fault specific to SIMATIC S7-300 and S7-400 CPUs running STEP 7 (TIA Portal or classic). They occur whenever the CPU attempts to load, transfer, or process a value that is not valid Binary-Coded Decimal (BCD) using an instruction that requires BCD format. The most common trigger is the S5 counter interface, where the preset value (PV) and the current count word are both encoded in BCD. The CPU raises the error either as a programming error that sends the CPU to STOP (event W:16#2520 / 35xx in the diagnostic buffer) or, on S7-300/400 with OB121 configured, as a recoverable event that leaves the CPU in RUN with the SF LED lit and a buffered diagnostic entry.

This reference consolidates field-proven diagnosis and remediation procedures for the message "BCD conversion error" (German: BCD-Wandlungsfehler), covering the S5 counter area (C0–C255), the SIMATIC time area (T0–T255), the ITB / BTI / DTB / BTD conversion primitives, and the IEC counter / timer function blocks that bypass BCD entirely.

BCD Number Format in S7

SIMATIC BCD is a 16-bit word where each 4-bit nibble represents a decimal digit, supporting values 0–9 per nibble. Three nibbles encode the value, the most-significant nibble encodes the sign:

  • Valid decimal range: −999 to +999
  • Encoding (unsigned nibble): 16#0 = 0 … 16#9 = 9
  • Sign nibble: 16#0 = positive, 16#F = negative
  • Invalid nibble (BCD violation): 16#A–16#E (10–14) in any value or sign position

Example: decimal 123 = 16#0123 (BCD). The same binary pattern 16#0123 interpreted as an integer is 291, so a direct word load is not equivalent to a BCD load.

Table 1 — S7 Conversion Instructions That Touch BCD
STL Function Source Target Error Trigger
ITB Integer to BCD ACCU1-L (INT) ACCU1-L (WORD BCD) INT > 999 or < −999
BTI BCD to Integer ACCU1-L (WORD BCD) ACCU1-L (INT) Invalid nibble (A–F in value or sign)
DTB Double Integer to BCD ACCU1 (DINT) ACCU1 (DWORD BCD) DINT > 9999999 or < −9999999
BTD BCD to Double Integer ACCU1 (DWORD BCD) ACCU1 (DINT) Invalid nibble
L C#<value> Load counter preset (BCD) Constant ACCU1 (BCD) Invalid constant BCD
L T#<time> Load time value (BCD) Constant ACCU1 (BCD) Invalid constant BCD
Note: On S7-1200/1500, BCD primitives ITB, BTI, DTB, BTD are retained for legacy compatibility, but new applications should use the IEC counter/timer (CTU, CTD, CTUD, TP, TON, TOF) which store LWORD integers and never raise a BCD conversion error.

Common Causes in S7 PLCs

The diagnostic message "BCD conversion error" almost always resolves to one of the following root causes. Identify which applies before attempting any code change so that the fix matches the fault.

2.1 Counter PV loaded from an integer source

An S5 counter requires the preset to be in BCD. A common pattern is:

L "MyDB".Preset_Int     // LAD FBD INT, e.g. 250
L C#0
>I
SPB ERR
// missing ITB -- CPU tries to load INT 250 as BCD
L "MyDB".Preset_Int
ITB                      // required: convert INT to BCD
S C 10                   // counter preset = BCD value

Without the ITB, the pattern 16#00FA (decimal 250 as binary integer) contains the invalid nibble A in the low byte and triggers the error the moment the counter is set.

2.2 Time value loaded from a non-BCD source

Using SP Tnb (start timer) with a value not encoded in BCD, or loading T# constants with L from a word that was previously overwritten by an integer operation, produces the same error. The remediation is identical: ITB the integer duration before SP.

2.3 Dynamic counter / time initialization

The OP and HMI frequently write PVs to data words such as DB93.DBW2. If the HMI uses an INT field and the PLC program does L DB93.DW2 then S C x without ITB, the error only occurs when the operator enters a value that produces an invalid nibble. The simulation in the source thread confirmed that the failure reproduces under controlled conditions once an invalid BCD pattern is forced into the PV.

2.4 Corrupted or misaligned data block

If a BCD source word is misaligned (overlaps two BCD values) or is overwritten by a different instruction between load and use, the CPU detects the BCD violation at the moment the BTI / S Cx / SP Tx instruction reads ACCU1.

Diagnostic Methods

When the CPU is configured to call OB121, the fault becomes non-fatal. If OB121 is missing or the user has chosen Stop on programming error, the CPU goes to STOP and the SF LED illuminates. In either case the same triage procedure applies.

3.1 Read the diagnostic buffer

  1. Open the project in STEP 7 (or TIA Portal > Online & diagnostics).
  2. Right-click the CPU > Online & Diagnostics > Diagnostic buffer.
  3. Find the most recent BCD conversion error entry. It records the priority class, OB number (typically OB 1), and the block stack (B stack) showing the exact network and instruction pointer where the BCD operand was consumed.
  4. Double-click the B-stack entry to jump to the offending STL network.

3.2 Force CPU to STOP if it stays in RUN

If OB121 masks the fault, temporarily change the CPU properties (Startup > Report programming errors → Stop) or insert an STP at the suspected location to force a STOP and freeze the diagnostic buffer. Always restore the original configuration once the offending network is found.

3.3 Manual search via cross-reference

  1. In SIMATIC Manager, right-click the program > Reference data > Display > Cross-references.
  2. Filter for S C, R C, CU C, CD C, SP T, SE T, SD T, SF T, SS T, R T.
  3. For each match, inspect the preceding load; the most common pattern is L <memory> directly above an S C or SP T without an ITB between them.

3.4 Use program status with breakpoints

  1. Open the suspected FB / FC in online view.
  2. Set a breakpoint just before the S C / SP T instruction.
  3. Watch ACCU1 in hex — if any nibble reads A, B, C, D, E, or F in a position that should be decimal, the input is the fault.

3.5 Use the SFC17 / SFC18 to capture non-fatal events

For S7-300/400 CPUs, SFC17 "DPSYC_FR" and SFC18 "DP_PRAL" are not directly relevant, but SFC13 "DPNRM_DG" plus the diagnostic buffer via SFC51 "RDSTWDR" or the standard SFB52 "RDREC" can stream error records to a data block for trend analysis. Pair this with OB82 / OB85 / OB121 local variables to capture the failing block and instruction offset at the moment of the error.

Resolution Steps

4.1 Apply the ITB conversion

The minimal, safe fix is to ensure every value loaded into a counter PV or timer duration is converted to BCD at the moment of use.

// Before
L "Recipe".CycleCount      // INT from HMI
S C 17                     // CPU rejects if nibble > 9

// After
L "Recipe".CycleCount      // INT from HMI
ITB                        // INT -> BCD, raises range error if > 999
S C 17
Caution: ITB raises its own range error (W:16#2521) if the source integer exceeds ±999 for word counters and ±9999999 for double-word times. Validate the input range, or saturate using L 999; <I; SPB OK; T "Recipe".CycleCount; OK: NOP 0; before the ITB.

4.2 Use a BCD constant for fixed values

For non-dynamic PVs, the C# and T# constants are encoded as BCD by the compiler. L C#250 and L T#5s are always valid; the source pattern SP T5 with a constant uses the literal BCD and is therefore safe.

4.3 Convert legacy S5 counters to IEC counters

Function blocks FB1 CTU, FB2 CTD, FB3 CTUD from the STEP 7 standard library ("Standard Library → IEC Function Blocks") use INT / DINT storage and never generate BCD errors. They are the recommended migration target for S7-300/400 and are the default on S7-1200/1500. If performance is a concern, leave fast bit counters in place but route the PV through a DINT latch and convert only on the load.

4.4 Fix the HMI / recipe data type

If the HMI writes the counter PV, change the HMI tag data type to match the PLC: Word (BCD) on classic WinCC flexible, or use a 16-bit unsigned Word on TIA Portal HMI with a manual ITB in the PLC before the S C instruction. The cleanest solution is to make the HMI tag a 16-bit unsigned integer and the PLC perform the conversion explicitly.

4.5 Realign data blocks

For arrays of BCD values in a DB, use even byte offsets and pack each BCD word into a WORD field. Mixing BYTE and WORD fields at the same offset causes the loader to interpret the bit pattern differently and may reintroduce a BCD violation at a later read.

Verification

  1. Clear the CPU diagnostic buffer (online > Clear diagnostic buffer).
  2. Trigger the same operator action or recipe load that produced the original error.
  3. Confirm the diagnostic buffer remains free of BCD conversion error entries after a full production cycle.
  4. In the program status view, step through the modified network: ACCU1 must display a valid BCD word (only 0–9 digits and 0 or F sign) immediately before each S C / SP T.
  5. Re-enable Stop on programming error in the CPU properties if it was disabled, and run a one-shift soak test to confirm no new BCD violations appear.

Prevention and Best Practices

  • Default to IEC counters and timers. They use 16-bit / 32-bit integers and eliminate the BCD class of error entirely.
  • Centralize BCD conversion. Wrap the ITB in a single FC and call it from every site that loads a counter or timer; do not copy the ITB instruction into each network.
  • Validate operator inputs. Clamp HMI inputs to the valid range before the BCD conversion so that ITB never sees an out-of-range integer.
  • Configure OB121 with a single global error handler that logs the failing block (OB121 SW_FLT local variable) and raises a single alarm, even if you do not want the CPU to STOP on the first occurrence.
  • Document the BCD boundary. Add an STL comment such as // BCD range: -999..+999, requires ITB from INT above every S5 counter set, so future modifications do not silently break the conversion.

Edge Cases and Field Notes

  • S7-400 H-CPU / F-CPU: The F-CPU runtime rejects BCD violations in the safety program; treat them as hard fails and route around with IEC counters.
  • Cross-compilation from STEP 7 Classic to TIA Portal: TIA Portal may auto-insert ITB for migrated S5 counters, but only when the source code is recompiled without error. If the original S5 area was hand-coded, verify the migration log for implicit conversion warnings.
  • ProTool / WinCC flexible → TIA Portal HMI migration: Variable data types are sometimes widened, changing the byte layout. After migration, re-validate every BCD-related tag with a forced write to the boundary values (0, 999, 1000, 9999, −1).
  • Loading from an input word: Field devices occasionally transmit BCD for legacy compatibility (e.g., certain absolute encoders). Apply a checksum and nibble-range check in the PLC, not just BTI, to avoid interpreting noise as a BCD value.
  • Counter cascading: S5 counters cannot cascade natively. When chaining, route the CV of the upstream counter through an ITB before re-loading it as the PV of the downstream counter, especially if any arithmetic was applied between the two.

Troubleshooting Matrix

Table 2 — Symptoms, Causes, and Fixes
Symptom Likely Cause Diagnostic Step Fix
CPU goes to STOP, SF LED on, BCD conversion error in buffer S5 counter PV loaded from INT Open B-stack, jump to S C Insert ITB before S C
CPU stays in RUN, intermittent SF on operator input HMI writes INT to a BCD-tagged PV Watch DBW in status, cross-ref HMI tags Add ITB, clamp range on HMI
Error appears only on T# durations > 999s Integer source > 999, ITB range error Inspect ACCU1 before ITB Use DINT and DTB with double-word time, or reduce duration
Error after recipe / setpoint change only DB word misaligned or overwritten by other code Cross-reference the DBW, check data view Re-align DB layout, declare the field WORD not INT
Error only in one of many identical counters Specific PV is hard-coded with C# constant outside range Grep the source for L C# Replace with L <INT>; ITB; S C x

Migration Reference: S5 to IEC

Table 3 — STL Counter / Timer Equivalents
S5 Instruction IEC Block Type Range BCD Risk
C 0..255 + S Cx FB1 CTU / FB3 CTUD INT / DINT ±32 767 / ±2 147 483 647 None
SP T 0..255 FB4 TON (S7-300/400) / TP (S7-1200/1500) S5TIME / TIME 9 999 s / 24 d 20 h 31 m 23 s None for IEC
SE T 0..255 FB5 TOF S5TIME / TIME Same None
SD T 0..255 FB3 CTUD with PV as duration IEC DINT Application-defined None
Safety: When migrating safety-related S5 counters (used in F-CPU safety programs), the migration must be performed within the safety lifecycle and approved by the certifying TÜV assessor. IEC counter FBs must be wrapped in F-blocks from the F-library to maintain SIL.

FAQ

What does the "BCD conversion error" mean on a Siemens S7 CPU?

It means the CPU attempted to read a value as Binary-Coded Decimal and found an invalid nibble (hex A–F in a value or sign position). The most common source is loading an S5 counter preset (S Cx) or SIMATIC timer (SP Tx) from a memory word that was written as a plain integer, or from a BCD word that has been overwritten since it was loaded into ACCU1.

How do I find the exact network that raises the BCD error?

Open the diagnostic buffer in STEP 7 or TIA Portal, locate the most recent BCD conversion error entry, and double-click the B-stack to jump to the failing network. If OB121 masks the fault, temporarily change the CPU to "Stop on programming error" or insert an STP at the suspected instruction, then re-trigger the event so the buffer freezes the location.

Do I always need an ITB before S Cx?

You need ITB whenever the source is an INT (LAD/FBD operand, DBW from HMI, or result of arithmetic). If the source is a C# constant or a memory word that was loaded via L W#16#… using only BCD digits, the conversion is implicit and ITB is not required. When in doubt, add the ITB — the cycle-time cost is negligible.

Why does ITB sometimes fail with a range error?

ITB converts a 16-bit signed integer (range −32 768 to +32 767) to a 3-digit BCD (range −999 to +999). If the source integer is outside ±999, ITB itself raises a programming error. Use DTB with a 32-bit source for the wider range, or clamp the HMI input to ±999 before the conversion.

Can I just replace every S5 counter with an IEC counter to avoid BCD errors?

Yes for non-safety code. The IEC counter function blocks (CTU, CTD, CTUD) from the STEP 7 standard library store values as INT or DINT and never raise a BCD conversion error. For safety-related S5 counters in F-CPUs, use the F-IEC counters from the F-library so the safety signature is preserved.

Back to blog