Resolving DINT to TIME Conversion Overflow in Siemens TIA Portal
When an HMI hands an integer to a Siemens S7 PLC representing a time in seconds, and the logic multiplies the value by 1000 to convert seconds to milliseconds for an IEC timer preset (PT), the program runs correctly through 32 seconds and then fails abruptly at 33 seconds. The IEC timer (TP, TON, TOF, TONR) starts with a negative preset, never expires, or wraps to a small positive value, and the entire timing path becomes unpredictable. The failure threshold sits exactly at 32,768 (0x8000), the upper bound of a 16-bit signed integer, and is one of the most common field issues when porting S5-era code to TIA Portal.
Root Cause: 16-bit vs 32-bit Data Width
In STEP 7 / TIA Portal, the MUL block selects the data width of the result from the widest operand. If the seconds tag coming from the HMI is declared as INT (16-bit) anywhere in the conversion chain - in the PLC tag table, in the DB interface, or via the implicit width of the MUL operands - the multiplication is executed as 16-bit arithmetic and the product overflows the moment it crosses +32,767. The visible break point in the field sits at 32-33 seconds because the HMI tag is rounded to whole seconds and the conversion chain is the only place where the width error manifests.
| Data Type | Width | Range | Effective Time Range |
|---|---|---|---|
| INT / WORD | 16 bits | -32,768 to +32,767 | -32.768 s to +32.767 s |
| DINT / DWORD | 32 bits | -2,147,483,648 to +2,147,483,647 | ±24.85 days (2,147,483 s) |
| TIME (IEC 61131-3) | 32 bits | T#-2,147,483,648 ms to T#+2,147,483,647 ms | ±24.85 days, internally identical to DINT |
| LTIME | 64 bits | ±292,471 years (ns resolution) | Practically unlimited |
Multiplying 33 by 1000 produces 33,000 - it does not overflow at the source. The break point reported in the field is therefore not the input value but the moment the result is forced into a 16-bit destination. The most common triggers are:
- The seconds tag from the HMI is declared as INT in the PLC tag table or DB interface.
- The MUL output is assigned to a 16-bit address (MWxxx) instead of a 32-bit address (MDxxx) or a DINT/TIME tag.
- A redundant CONV (Convert) block converts DINT to INT and silently drops the upper 16 bits.
- The IEC timer PT input is fed from a 16-bit intermediate tag.
Memory Area Mapping in STEP 7 / TIA Portal
The memory area symbols MW and MD identify 16-bit (Word) and 32-bit (Double Word) views of the same underlying bit memory area. Concretely, MD10 occupies the same bytes as MW10 and MW12, and any write to MD10 overwrites both word cells.
| Symbol | Width | Used For | Bit-Memory Overlap |
|---|---|---|---|
| MB | 8 bits | BYTE, BOOL arrays | MB10 |
| MW | 16 bits | INT, WORD | MW10 = MB10, MB11 |
| MD | 32 bits | DINT, DWORD, REAL, TIME | MD10 = MW10, MW12 = MB10..MB13 |
In LAD/FBD, the MUL block has a default assignment that follows the IEC 61131-3 rules: the output width follows the widest input. However, when the engineer types the address directly (e.g., entering MW10 as the output rather than MD10), the compiler emits a warning and may still allow the assignment, but the upper 16 bits of the result are lost on every scan cycle. The TIA Portal compiler warning looks like:
Warning: The address "MW10" points to a memory area that is smaller than the
formal parameter of the instruction "MUL" (formal parameter is a 32-bit data type).
Writing the product to MW10 when the MUL is computed as a DINT overwrites MW10 and MW12, but the CPU only stores the lower 16 bits at MW10. If the underlying data is, for example, 33,000 (0x000080E8 hex), only 0x80E8 is preserved; since 0x80E8 is interpreted as a signed INT it becomes -32,280, and the timer preset is now negative. The TIMER block with a negative PT treats the value as zero and never starts.
The TIME Data Type in S7 PLCs
IEC 61131-3 defines TIME as a 32-bit signed value representing milliseconds. The full range is T#-2_147_483_648ms to T#+2_147_483_647ms, approximately ±24.85 days. S7-1200 and S7-1500 CPUs support TIME natively on the inputs of every IEC timer (TP, TON, TOF, TONR), on the IEC LTIME variants, and on the standard arithmetic functions. The internal bit layout of TIME is identical to DINT - a 1:1 copy is sufficient to convert between them. The reference for the IEC 61131-3 data type definitions is maintained by PLCopen; the Siemens-specific implementation is documented in the SIMATIC S7-1200 and S7-1500 system manuals on the Siemens Industry Online Support portal.
Conversion Paths at a Glance
- DINT → TIME: Direct assignment. Both are 32-bit signed integers with the same internal layout. Declare the target as TIME and copy the bit pattern; no runtime conversion is required.
-
REAL → TIME: Use the
REAL_TO_TIMEconverter, or multiply by the conversion factor (REAL × 1000.0 → DINT → TIME). On S7-1500, conversion FCs are available in the standard library under "Extended instructions". -
INT → TIME: Must first widen to DINT to avoid the 32.7 s limit, then assign to a TIME variable. Use the
CONVbox with INT input and DINT output, or in SCL theINT_TO_DINTfunction. - WORD → TIME: Bit-copy; both are 16-bit unsigned. The same 32.7 s limit applies. Always widen to DWORD/DINT first.
To convert a DINT in milliseconds to a TIME, the cleanest pattern is:
// LAD
MUL "SecondsTag_DINT" 1000 "PresetTime_TIME"
// Result: PresetTime is TIME, holds (SecondsTag × 1000) ms
Or in SCL (Structured Control Language) on S7-1200/S7-1500:
"PresetTime" := DINT_TO_TIME("SecondsTag" * 1000);
"Timer_DB".PT := "PresetTime";
"Timer_DB".IN := "StartCommand";
Step-by-Step Fix in TIA Portal V15 and Later
Apply the following changes to the affected FC/FB and the PLC tag table. The procedure assumes a project that compiles and runs today with a 33 s ceiling.
- Open the PLC tag table and locate the seconds tag coming from the HMI. Change its declaration from INT or WORD to DINT. If the HMI hands the value to the PLC as a 16-bit tag, the conversion happens at the fieldbus driver (S7 communication places it in a DB of fixed width), so verify the DB declaration rather than the HMI tag.
- Open the network containing the multiplication. In LAD/FBD, click the MUL block and inspect the output operand. Replace
MWxxxwithMDxxx. If the MUL block currently outputs to a tag (not an address), confirm the tag's data type is DINT or TIME. - Remove the redundant
CONV(INT_TO_INT) blocks. A type cast from INT to INT is a no-op and the IEC compiler will not warn about lost width if the source is INT and the destination is INT. Replace with a single MUL whose output is the timer preset (declared TIME). - Connect the MUL output directly to the PT input of the IEC timer. The PT input is a TIME parameter; TIA Portal will perform an implicit DINT → TIME conversion that is a 1:1 bit copy. The Siemens SIMATIC S7-1200 system manual documents the PT input as TIME on the IEC timer blocks; see the SIMATIC S7-1200 product page for the latest edition.
- Recompile. The compiler should now report zero warnings on the affected network. If it does not, hover the warning to find the exact operand still declared at 16-bit width.
- Download to the PLC and go online. Open a watch table containing the seconds tag, the MUL output, and the timer instance's PT input.
Verification Procedure
After the change, perform the following online checks in TIA Portal. The values are chosen to make any residual 16-bit assignment visible at a glance.
-
Zero test: Force the seconds tag to 0. The MUL output reads 0 and the PT input of the timer reads
T#0ms. The timer must not start. -
One-second test: Force the seconds tag to 1. The MUL output reads 1,000 and the PT input reads
T#1s. The timer expires in exactly 1,000 ms after the rising edge of IN. -
32-second test: Force the seconds tag to 32. The MUL output reads 32,000 and the PT input reads
T#32s. The timer expires in 32 s. This is the boundary case in the original bug report. -
33-second test: Force the seconds tag to 33. The MUL output reads 33,000 (decimal, 0x000080E8 hex). The PT input reads
T#33s. This is the new pass case; before the fix the value wrapped to -32,280 (0xFFFF80E8). -
INT-max test: Force the seconds tag to 32,767. The MUL output reads 32,767,000 and the PT input reads
T#32767s(approximately 9.1 hours). Before the fix the output was 0xB70C0000 hex, which is interpreted as a signed DINT and reads as -1,216,096,000 - a clearly negative value. - DINT-max test: Force the seconds tag to 2,147,483. The MUL output overflows to the negative DINT range; the timer fails predictably. This is the expected behavior - the DINT range is the new limit, not the INT range.
- One-minute timing test: With the operator entering 60 s on the HMI, the IEC timer must time out exactly 60 seconds after the input edge. Use the watch table to monitor the timer's Q output and stop a stopwatch at the transition.
Alternative Implementation Patterns
Pattern A: Bypass the Multiplication by Setting the Timer Time Base
If the operator enters whole seconds and the application is simple, the IEC timer can be fed the seconds value directly when the timer's time base is set to seconds. In TIA Portal, configure the TON with time base "1 s" instead of "1 ms" and the integer is interpreted as seconds. The TimeBase parameter is exposed on the timer instance DB starting with S7-1200 firmware V4.0 and on all S7-1500 CPUs. Set the time base via the instance DB editor or in the call interface.
Pattern B: Use SCL with Explicit TIME Arithmetic
// SCL on S7-1200/S7-1500
"PresetTime" := DINT_TO_TIME("SecondsTag" * 1000);
"Timer_DB".PT := "PresetTime";
"Timer_DB".IN := "StartCommand";
Because both operands of the multiplication are DINT and the assignment target is TIME, the compiler cannot silently downcast to INT. This pattern is the most defensible against future changes and is the recommended approach for new code on the SIMATIC S7-1500 platform.
Pattern C: Route Through Named Tags Instead of Absolute Addresses
Tag-based code paths trigger the correct width selection in the TIA Portal compiler; address-based code paths do not. Replace every MW10 in the conversion chain with a DINT or TIME tag defined in the DB interface. The compiler will then warn explicitly if a downstream instruction is too narrow.
Pattern D: Use the IEC LTIME Block for Sub-Millisecond or Long-Duration Logic
For time values outside the ±24.85 day range, switch to LTIME and the TP_LTIME / TON_LTIME / TOF_LTIME blocks available in the S7-1500 standard library. The conversion follows the same pattern but uses 64-bit arithmetic throughout.
Compiler Warnings Reference
| Warning Text (Abbreviated) | Cause | Fix |
|---|---|---|
| Address points to memory area smaller than formal parameter | MUL/DIV/ADD output assigned to MW instead of MD | Change output to MD or to a DINT tag |
| Implicit conversion from DINT to INT may cause loss of information | Tag declared as INT receives DINT value | Re-declare the destination tag as DINT or TIME |
| Operation result is outside the valid range of data type INT | Arithmetic product exceeds ±32,767 | Widen both operands to DINT and the output to MD |
| Variable cannot be implicitly converted to formal parameter type | PT input expects TIME, receives INT | Cast via DINT_TO_TIME or change source to TIME |
| Inconsistent data types in the expression | Mix of INT and DINT operands in a single MUL/ADD | Normalize all operands to DINT before the arithmetic block |
Cross-Platform Notes
The same 16-bit / 32-bit issue exists on S7-300 and S7-400 (STEP 7 V5.x). The memory area symbols are identical: MW for 16-bit, MD for 32-bit. In SCL for S7-300/400 the MUL block always uses 32-bit arithmetic when both operands are DINT, so the fix is the same - declare the seconds tag as DINT in the corresponding DB and assign the product to a DINT or TIME variable.
On S7-1500 with TIA Portal V16 and later, an additional check is available: the IEC Check option in the project properties (under "PLC programming" → "Compiler"). When enabled, the compiler refuses to perform implicit narrowing conversions and the program will not compile until the operator explicitly widens the operands. Enable IEC Check on every new project; for legacy code, run a test build with IEC Check enabled to surface hidden width problems.
On LOGO! and S7-200 (legacy micro PLCs), the data width rules differ - LOGO! uses 32-bit values for all time arithmetic by default and S7-200 uses the older S5TIME BCD format. The IEC TIME data type and the MUL width inference discussed here apply to S7-300/400/1200/1500 only.
Time-Base Selection on S7-1200 / S7-1500
Starting with S7-1200 firmware V4.0 and on every S7-1500 CPU, the IEC timer instance exposes a TimeBase parameter that selects the resolution of the PT input. The allowed values are:
| TimeBase Value | Resolution | Max Range | Use Case |
|---|---|---|---|
| 0 | 1 ms | T#2_147_483_647 ms (24.85 d) | Default; requires seconds × 1000 conversion |
| 1 | 10 ms | T#21_474_836_470 ms (24.85 d) | Coarser timing, avoids the multiplication entirely |
| 2 | 100 ms | T#214_748_364_700 ms (24.85 d) | Slow timing, decimal HMI entries map directly |
| 3 | 1 s | T#2_147_483_647 s (24.85 d) | Whole-second HMI entries - no conversion needed |
Setting TimeBase := 3 on the timer instance DB and assigning the seconds tag directly to PT eliminates the multiplication and the 16-bit trap in a single change. The trade-off is loss of sub-second resolution; for the typical "delay before next step" timer this is acceptable.
Best Practices for Time Math in S7
- Declare all time-related tags in the PLC tag table and DB interfaces as DINT or TIME; never as INT or WORD. The IEC 61131-3 type system explicitly defines TIME as a 32-bit signed integer in milliseconds - reference PLCopen for the formal definition.
- Prefer SCL over LAD for time arithmetic. The implicit width rules in LAD/FBD are easy to misread; SCL is explicit and surfaces width mismatches at compile time.
- Use named tags rather than absolute addresses (MW10) wherever possible. The compiler can warn about width mismatches when the destination is a tag, but not when the destination is a raw address.
- Watch the
ET(elapsed time) output of the IEC timer. It is a TIME value that can be read withTIME_TO_DINTand split into seconds/minutes for HMI display. Same data width rules apply - assign to a DINT tag, never INT. - When commissioning, set the seconds tag to exactly 32,767 in the watch table and confirm the timer preset reads as expected. This is a single, fast check that catches any remaining 16-bit assignment in the conversion chain.
- Document the time base on the timer instance (e.g., comment on the FB: "PT is always milliseconds"). A one-line comment prevents the next engineer from re-introducing the bug.
- Enable the IEC Check option in the TIA Portal compiler settings for every new project. The compiler then refuses to narrow data types implicitly.
- For multi-instance timers in an FB, declare the multi-instance tag (e.g.,
Static: Timer_0 : TON) and call the block with a fully-qualified PT input (#Timer_0.PT) so the compiler can verify the width.
Field Commissioning Checklist
| Test | Seconds Input | Expected MUL Output | Expected PT |
|---|---|---|---|
| Zero boundary | 0 | 0 | T#0ms (timer does not start) |
| Sub-second boundary | 1 | 1,000 | T#1s |
| Pre-overflow boundary | 32 | 32,000 | T#32s |
| Post-overflow boundary (the bug) | 33 | 33,000 (0x000080E8) | T#33s (was negative before fix) |
| INT max boundary | 32,767 | 32,767,000 (~9.1 h) | T#32767s (was negative before fix) |
| Negative test | -1 | -1,000 | Invalid; timer does not start |
| Long-duration test | 86,400 | 86,400,000 | T#86400s (1 day) |
Diagnosing the Bug with the Watch Table and Cross-Reference
When the bug recurs after a code change, the fastest diagnosis path is:
- Go online and open the watch table that contains the seconds tag, the intermediate conversion tags, and the PT input of the timer.
- Switch all numeric columns to HEX display. The truncated 16-bit result is unmistakable in hex: 33,000 (correct DINT) reads 0x000080E8, the truncated 16-bit value reads 0x80E8, the negative wrap-around reads 0xFFFF80E8.
- Right-click the seconds tag in the watch table and select "Go to cross-reference". The cross-reference lists every use of the tag. Any network that writes the tag into a 16-bit destination is the bug source.
- Open the PLC tag table and filter on the seconds tag. The "Data type" column shows the declared width. Anything other than DINT, INT, or TIME needs to be reconciled with the MUL output expectation.
- Compile with IEC Check enabled. The compiler will now refuse to build if any narrowing conversion remains. This is the most reliable single-step verification.
Conversion From S5TIME (Legacy)
Projects migrated from S5 to S7-1200/S7-1500 sometimes retain S5TIME tags from the old S5 timer conventions. S5TIME is a 16-bit BCD format with 10 ms resolution and a maximum value of 9,990 seconds (approximately 2.7 hours). The BCD_TO_DINT and DINT_TO_BCD conversions are required to move data between S5TIME and the modern TIME format. A 60-second value in S5TIME is 16#0060, while the same value in TIME is 60,000 decimal. Confirm the format on every legacy timer before assuming the value is in milliseconds.
FAQ
Why does my TIA Portal MUL block not warn about the INT overflow at 33 seconds?
The compiler only warns when the destination operand is narrower than the instruction's formal parameter. If you typed MW10 (16 bits) as the output of a MUL that is otherwise computed at DINT width, TIA Portal V15 and V16 issue a warning; V14 and earlier may not. Switch the destination to MD10 (32 bits) or to a DINT tag to surface the warning and fix the truncation.
Can I just change the IEC timer time base to seconds and skip the multiplication?
Yes, on S7-1200 firmware V4.0+ and S7-1500 the TON/TOF/TP instance has a configurable TimeBase parameter (default 1 ms). Set it to 1 s (value 3), assign the seconds tag directly to the PT input, and remove the MUL. The conversion is then done by the timer itself, not by your code, so the 16-bit trap cannot occur. The trade-off is loss of sub-second resolution.
Is there a CONV block I can use to widen INT to DINT before multiplying?
Yes. Use the CONV (Convert) box with input INT and output DINT, or in SCL the expression INT_TO_DINT("SecondsTag") - though the more common idiom is to simply declare the source as DINT in the tag table. A CONV from INT to DINT is a sign-extending copy, so -1 stays -1, not 65,535. The original bug report mentioned CONV0 and CONV1 declared as Int - those are precisely the tags to change to DInt.
Does the same issue affect S7-300 and S7-400 with STEP 7 V5.x?
Yes. The MUL block in LAD/FBD uses the same width inference, and the same MW/MD distinction applies. In SCL the same explicit DINT declaration is the fix. STEP 7 V5.6 SP2+ may auto-warn on MW assignment to a DINT result depending on the OB/FB compile options. The fix path is identical: declare the seconds tag as DINT and assign the MUL output to MD or a DINT tag.
What is the difference between TIME, LTIME, S5TIME, and BCD time formats?
TIME is the 32-bit IEC format in milliseconds, used on S7-1200 and S7-1500. LTIME is the 64-bit extension (nanosecond resolution, ~292,000-year range). S5TIME is the legacy 16-bit BCD format from the S5 days, still supported on S7-300/400 timers (T0..T255) and on S7-1500 via legacy conversion blocks. S5TIME cannot represent times longer than 9,990 seconds, which is one of the reasons S7 migrated to the wider TIME format. Use the S5TIME_TO_TIME and TIME_TO_S5TIME conversion functions when bridging between legacy and modern timer formats.