Passing Siemens S7-400 TIMER Variables to Called FCs in STEP 7

David Krause16 min read
S7-400SiemensTutorial / How-to
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

In Siemens STEP 7 Simatic Manager on the S7-400 platform, the TIMER data type is not permitted as a local (TEMP) variable inside a Function (FC). The FC interface only supports elementary types such as BOOL, INT, REAL, TIME, S5TIME, and WORD in the TEMP section. To reuse a single timing routine across many devices (for example ten pressure switches, each driving its own on-delay lamp), the TIMER must be passed into the FC by reference: declare an INPUT parameter of type TIMER on the called FC and supply a different global timer word (T1, T2, ...) from the caller. This reference covers the two accepted methods — declared TIMER input and indirect addressing with TIMER_WORD — and contrasts the FC approach with the FB multi-instance alternative that exists in STEP 7 V5.x and TIA Portal.

The question this article resolves — "How do I pass a different timer to each call of the same FC, and why does STEP 7 refuse my local TIMER declaration?" — has a definitive answer: TIMER is a system resource, not a value. It must be bound to a stable storage address. The cleanest implementation uses an INPUT of type TIMER. The legacy alternative is indirect addressing through the timer word area, which preserves the FC interface as WORD/INT but requires explicit pointer arithmetic.

Why a Local TIMER Cannot Be Declared Inside an FC

An FC in STEP 7 is a "function without memory." Its TEMP area is allocated on the local stack of the current call and is released when the FC returns. A TIMER, however, is not a value — it is a handle to a hardware/system resource of the CPU. The CPU reserves a fixed pool of timer words at startup. The TEMP area of an FC cannot own that resource; the resource must live in a static storage area (DB, M-bit memory, or the global timer word area).

The error you see in SIMATIC Manager when you attempt TEMP of type TIMER is one of the following:

Compiler / Online Error Text Meaning
SF0017 Declaration section 'TEMP' does not allow data type TIMER TIMER not permitted in TEMP
Warning Type TIMER can only be used for IN/OUT/STAT Move declaration to interface
Online SF Diagnostic buffer event W#16#3581 / 3585 Invalid timer number on L/T/CU/CD

The same restriction applies to COUNTER. The STEP 7 V5.5 Programming with STEP 7 manual states explicitly in section 5.5: "Timers and counters may only be specified as input parameters of FCs and as static variables of FBs."

What TIMER Actually Means in STEP 7

When you write SD T1, the CPU does not copy a value; it activates a timer cell in the system data area and sets a status bit. The cell occupies two 16-bit words: one for the S5TIME preset/current value, and one for the status/control bits. S7-400 CPUs reserve 2048 such cells (T0 to T2047) regardless of whether your program uses them; the memory cost is fixed. See the S7-400 CPU 41x reference manual, chapter 4 for the per-CPU breakdown.

Prerequisites

  • STEP 7 V5.5 SP2 or later (SIMATIC Manager) — recommended patch HF11 or newer for Windows 10/11 compatibility
  • S7-400 CPU with sufficient free timer words; all CPU 41x variants support T0 through T2047 (see CPU 41x manual)
  • Hardware Configuration with OB1 (or OB35 for cyclic execution), and standard OBs 82/100/121/122 loaded
  • Symbolic names in the Symbol Table for the input/output bits of each unit (optional but recommended)
  • Cross-reference data enabled (Options → Cross-Reference) to verify no double-assignment of timer numbers

Solution 1: Declare a TIMER INPUT Parameter on the Called FC

This is the canonical method in STEP 7. The interface of the called FC (FC2) carries an INPUT of type TIMER. The caller (FC1) supplies the timer number from its own ladder or STL segment.

Step-by-Step: FC2 Interface Definition

  1. Open SIMATIC Manager → S7 Program → Blocks.
  2. Right-click → Insert New Object → Function → name it FC2.
  3. Open FC2. In the interface header, declare the following:
Interface Name Type Comment
IN i_Start BOOL Start edge (pressure switch)
IN i_PresetTime S5TIME On-delay preset, e.g. S5T#10S
IN_OUT t_Timer TIMER Pass T1, T2, ... from caller
OUT o_Lamp BOOL TRUE after time elapsed
OUT o_Running BOOL TRUE while timing
TEMP s_CoilState BOOL Local edge / state

Use IN_OUT for the timer interface to make it clear that the FC reads and writes the timer cell. IN alone works equally well; the timer cell is always written by the SD/SS/SP/SF instructions regardless of declaration direction.

FC2 Body (STL)


      A    #i_Start
      L    #i_PresetTime
      SD   #t_Timer          // On-delay start, uses passed timer cell
      A    #t_Timer          // Q bit
      =    #o_Running
      A    #t_Timer
      =    #o_Lamp
      AN   #i_Start          // reset on falling edge of start
      R    #t_Timer

The SD instruction loads the S5TIME preset and arms the timer. A #t_Timer reads the Q (elapsed) bit. R #t_Timer clears the cell when the start input falls.

Note: Passing the same TIMER symbol (e.g. T1) to two different call sites of FC2 from FC1 will drive one physical timer cell from two places. The CPU will dutifully set and reset T1 in whichever FC2 instance last ran, producing undefined lamp state. Use a unique T-cell per call site, or move to FB + IEC TON instance for a re-entrant solution.

FC1 Calling Pattern (LAD/FBD)

In FBD editor, insert a "Call FC2" box ten times. Wire each instance:

Call # i_Start i_PresetTime t_Timer o_Lamp
1 Unit1_PS S5T#10S T1 Unit1_Lamp
2 Unit2_PS S5T#10S T2 Unit2_Lamp
... ... ... ... ...
10 Unit10_PS S5T#10S T10 Unit10_Lamp

The graphic below shows the call topology: FC1 in OB1 dispatches ten calls to FC2, each binding a different global timer cell.

OB1 FC1 (caller) FC2 (OnDelayUnit) CALL x 10 i_Start, i_PresetTime o_Lamp, o_Running Global TIMER area T0 … T10 … T2047 2 words per cell S5TIME + status Unit 1 → T1 Unit 2 → T2 ... Unit 10 → T10

Solution 2: Indirect Addressing with TIMER_WORD

If the FC interface must remain type-stable (some legacy code generators cannot generate the TIMER interface, or the FC is generated from a third-party tool), the timer number can be carried in a WORD INPUT parameter and addressed indirectly. The indexed pattern L T [#temp_w] reads the bit-level status of the timer whose number is in #temp_w; the equivalent for driving the timer is to use the indexed SD/SS/SP/SF/R form with AR1/AR2.

Indirect Read of Timer Status


FUNCTION FC2 : VOID
VAR_INPUT
  i_Start : BOOL;
  i_TimerNo : WORD;        // e.g. W#16#0001 = T1
END_VAR
VAR_TEMP
  t_TimerNo : WORD;
END_VAR
BEGIN
      L    #i_TimerNo
      T    #t_TimerNo
      A    #i_Start
      L    S5T#10S
      SD   T [#t_TimerNo]   // direct indexed form: timer number from word
      L    T [#t_TimerNo]   // direct indexed read of Q bit
      T    MW 200

On S7-400 CPUs the indexed form of the TIMER instruction is legal since the very first firmware (V3.x). The address register form SD [AR1,P#0.0] is the more flexible option and is documented in the STEP 7 STL reference manual, chapter on Timer/Counter Instructions.

Indirect Form via Address Register


      L    P#T0              // pointer to first timer cell
      L    #i_TimerNo        // offset = (T-number) * 2 words
      ITD
      SLD   3                 // shift to bit offset (each word = 16 bits)
      +D                       // AR1 = P#T0 + offset
      LAR1
      A    #i_Start
      L    S5T#10S
      SD   [AR1,P#0.0]       // drive timer at AR1
Caution: Indirect timer addressing through AR1/AR2 was supported on S7-300 and S7-400 in STEP 7 V5.x. It is not portable to TIA Portal SCL, where the equivalent abstraction is the IEC TON/TOF/TP block stored in an FB instance DB.

Edge Detection and Reset Discipline

A common failure mode in on-delay timer FCs is the "permanently running" symptom: the lamp is on regardless of the start signal. The cause is that SD reloads the preset on every scan as long as the start input is TRUE. While this is correct behavior (the timer is held in a continuously-elapsed state, Q = TRUE), the lamp will not turn off when the start input drops — it is the R on falling edge that gives the timer its release semantics.

Two patterns are recommended:

Pattern A: Continuous-Start + Edge-Reset (Latch-style)


      A    #i_Start
      L    #i_PresetTime
      SD   #t_Timer
      AN   #i_Start
      R    #t_Timer

Pattern B: Edge-Start + Auto-Reset (Pulse-style)


      A    #i_Start
      FP   #s_Edge           // TEMP — but see note below
      S    #s_Latch          // TEMP — see note below
      A    #s_Latch
      L    #i_PresetTime
      SD   #t_Timer
      AN   #t_Timer
      R    #s_Latch
Re-entrancy warning: Pattern B uses TEMP variables for edge/latch memory. TEMP is not preserved across scan cycles — it is reinitialized when the FC is called. For a function that is called from OB1 (priority 1) and also from OB35 (priority 12), the TEMP storage is reallocated on each call, so the edge memory will not survive. Move the latch to a per-call instance (FB) or to global M bits dedicated to that call site. This is the most common source of "the timer runs on the first call but not the second" bugs in legacy STEP 7 code.

FC vs FB: The Multi-Instance Alternative

For a true instance-data model (one data set per pressure switch), STEP 7 offers Function Blocks (FB) with multi-instance capability. Each call site of an FB references its own instance DB, and the FB owns its own state — including the timer data — inside that DB. The IEC timers TP, TON, TOF from the STEP 7 standard library store their data inside the calling FB's instance, not in the global T area.

FB Variant in SCL (TIA Portal syntax)


FUNCTION_BLOCK "OnDelayUnitFB"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
  VAR
    instTON : TON;             // IEC on-delay; lives in instance DB
    instR_TRIG : R_TRIG;        // edge detect
  END_VAR
  VAR_INPUT
    i_Start : BOOL;
    i_PresetTime : TIME;
  END_VAR
  VAR_OUTPUT
    o_Lamp : BOOL;
  END_VAR
BEGIN
  "instR_TRIG"(CLK := #i_Start);
  "instTON"(
    IN := #i_Start,
    PT := #i_PresetTime);
  #o_Lamp := "instTON".Q;
END_FUNCTION_BLOCK

Each call from FC1 uses a separate instance DB (DB1 through DB10), each carrying its own instTON and instR_TRIG. The routine is fully re-entrant and survives OB priority changes. The corresponding programming reference is the S7-1200/1500 Programming and Operating Manual (the S7-400 equivalent is the STEP 7 V5.5 manual, chapters 6 and 7).

Comparison Table

Criterion FC + global TIMER input FB + IEC TON instance
Memory model No instance data; relies on global T area Instance DB; data local to instance
Re-entrancy Unsafe (M / TEMP shared between call sites) Safe (each instance has own DB)
Number of timer resources Limited to 2048 T-cells per CPU Limited only by DB number / work memory
Code visibility Same FC shared by all units Same FB shared by all units
Block consistency check Manual numbering required Automatic instance update on interface change
Suitable for legacy S5 migration Yes (direct S5 timer mapping) No (S5 code rewrite)
Recommended for new code No Yes

CPU Compatibility Matrix

CPU family Minimum firmware Timer words (T) IEC TON in FB instance
CPU 412-1 / 412-2 PN V4.2+ 2048 Yes
CPU 414-2 DP / 414-3 PN/DP V4.2+ 2048 Yes
CPU 416-2 / 416-3 PN/DP V4.2+ 2048 Yes
CPU 417-4 V4.2+ 2048 Yes

The number of timer words is fixed at 2048 for the entire S7-400 family; the count does not change with firmware or hardware revision. The IEC TON block is part of the STEP 7 standard library and is independent of the T-cell area — it is a software construct that lives inside the instance DB.

S5TIME Bit Layout (Reference)

The preset on an S5 timer is an S5TIME value of 16 bits, organized as BCD-coded value plus a 2-bit time-base selector. Reference: STEP 7 STL Reference Manual.

Bits 15…14 Bits 13…12 (time base) Bits 11…0 (BCD value) Resolution Range
00 00 0…999 0.01 s 10 ms to 9 s 990 ms
00 01 0…999 0.1 s 100 ms to 1 m 39 s 900 ms
00 10 0…999 1 s 1 s to 16 m 39 s
00 11 0…999 10 s 10 s to 2 h 46 m 30 s

Example: S5T#10S = W#16#2100 — time base 10 s (bits 13/12 = 10), BCD value 0001 (1 × 10 s = 10 s).

Conversion Between S5TIME, TIME, and LTIME

STEP 7 V5.x supports explicit conversion functions in the standard library:

From To Function Source
S5TIME TIME FC40 "S5TI_TIM" Standard Library → IEC Function Blocks
TIME S5TIME FC41 "TIM_S5TI" Standard Library → IEC Function Blocks
S5TIME BCD bit pattern Manual: read low 12 bits, decode time base STEP 7 V5.5 manual, ch. 9

FC40 returns a TIME duration in milliseconds for a legacy two-decade S5 timer. FC41 does the reverse with rounding to the nearest S5-time-base step.

Timing Diagram (Verification Reference)

The expected behavior of FC2 with a 10 s on-delay, when called by FC1 with T1 bound:

i_Start t=0 t=10s t=15s T1.Q o_Lamp

Reading: at t=0, i_Start goes TRUE; FC2 arms T1. T1.Q rises at t=10s; o_Lamp follows. At t=15s, i_Start goes FALSE; FC2 resets T1; o_Lamp falls.

Verification Procedure

  1. Compile FC1 and FC2. The expected result is "0 errors, 0 warnings". A warning like "TIMER used as parameter" is informational and indicates the interface is correctly recognized.
  2. Download the blocks to the S7-400. From SIMATIC Manager: PLC → Download to Target System. Confirm online and check for SF (system fault) — a clean download leaves the CPU in RUN.
  3. Open the LAD/FBD/STL editor for FC2 and set up Monitor/Modify on the t_Timer input. Verify the timer number (e.g. T1) is correctly resolved to the symbol.
  4. Force i_Start = TRUE on one call site. After the configured 10 s, o_Lamp must transition to TRUE. Use the online monitor view of the associated timer word to confirm the elapsed-time bits increment.
  5. Repeat for all ten call sites with different pressure switch and lamp assignments. Each must reach its 10 s on-delay independently.
  6. Cross-reference: in SIMATIC Manager select the T-area, right-click → Cross-References. Each T1..T10 should be referenced exactly once (in the corresponding FC2 call from FC1). Duplicate references indicate a parameter-binding mistake.
  7. Edge test: drop i_Start = FALSE mid-timing. The timer must reset. The Q bit must fall within one OB1 scan.
  8. Restart test: trigger CPU restart (STOP → RUN, or via MRES). All S5 timers are cleared on restart per the CPU's startup OB. Verify that the application re-arms the timers via its normal start signals.

Troubleshooting Matrix

Symptom Diagnostic / Event Cause Remedy
"Declaration section 'TEMP' does not allow data type TIMER" Compile error TIMER placed in TEMP Move declaration to IN/IN_OUT/STAT
"Type conflict in parameter t_Timer" Compile error Passing WORD or INT instead of TIMER symbol Pass a TIMER symbol such as T1, not a literal 1
Online SF on CPU, diagnostic buffer event W#16#3581 SF: 3581 Timer number out of range or duplicate assignment Check CPU timer count; check the FC is not called twice with the same T-number
Timer never reaches elapsed state None CPU in restart, OB100 cleared all timers Add re-trigger of start condition after restart
o_Lamp always TRUE regardless of i_Start None SD called continuously with the same start signal, R never called Add R on falling edge of i_Start
Same T-number driven by two FC2 call sites None Caller mistakenly passed T1 to two different units Use unique T-cells per call; use FB + instance
TEMP edge flag causes intermittent restart None M-bit / TEMP used inside FC shared between call sites Move edge memory into per-unit DB or use FB instance
"Type TIMER cannot be used as OUTPUT parameter" Compile error Attempting OUT/IN_OUT of type TIMER Use INPUT only; expose Q as BOOL OUT
T1 counts up but Q bit never goes high None Preset value S5TIME is zero (S5T#0s) Use S5T#10S or equivalent non-zero preset
"Address P#Tnn out of input area" Compile error Indirect pointer arithmetic off by one Recompute offset: timer number × 2 words × 8 bits/word = × 16

Memory and Performance Considerations

Each global timer cell occupies 16 bytes of system data area (16 bits × 2 words). The 2048 cells therefore consume 32 KB of system data on the S7-400. The IEC TON instance variant consumes DB space per call — typically 32 bytes per FB instance including edge detection. For 100 unit instances, that is approximately 3.2 KB of work memory, a fraction of the global T-cell cost. When the number of timers approaches the 2048 limit, the FB + IEC TON variant is mandatory; the FC + global T pattern is not scalable beyond that ceiling.

OB1 cycle time is unaffected by either approach; both are O(1) per call. The FC + global T pattern has the additional cost of a pointer dereference in the SD instruction (since the timer number is bound to the formal parameter). The FB + IEC TON pattern uses a direct DB access and is typically 5–10% faster per call on a CPU 414.

Cross-Platform Notes

  • S7-300 (CPU 31x): Same FC + global TIMER pattern applies. The T-cell count varies: CPU 312 = 256, CPU 314 = 256, CPU 315-2 DP = 256, CPU 319-3 PN/DP = 2048. See the S7-300 CPU 31x technical data.
  • S7-1200 (CPU 12x): TIA Portal only. The global TIMER area does not exist; only IEC TP/TON/TOF blocks in FB instances are supported. The FC + TIMER INPUT pattern from S7-400 is not portable.
  • S7-1500 (CPU 15x): TIA Portal only. The global TIMER area does not exist; same restriction as S7-1200.
  • ET 200S IM151 / IM154: The TIMER area is not supported on the IM module's local CPU (if present). The IEC FB + TON pattern must be used.

Frequently Asked Questions

Why can't I declare TIMER as a TEMP (local) variable in an FC?

TIMER is not a value type — it is a handle to a hardware timer cell in the CPU's system data area. An FC's TEMP region is allocated on the local stack for the duration of the call and discarded on return, so it cannot own a system resource. Declare the TIMER as an INPUT (or move to an FB STAT) so the resource is bound to a stable address.

Can I declare a TIMER as an OUTPUT of an FC?

No. STEP 7 V5.x and TIA Portal both restrict TIMER to INPUT parameters of FCs. Use an INPUT parameter, drive it with SD/SS/SP/SF inside the FC, and expose the result bit (Q) as an OUT BOOL if you need to return the timer status to the caller.

How many timer words are available on an S7-400 CPU?

The S7-400 system data reserves 2048 timer words (T0 to T2047) for all CPU 41x variants. The exact number is fixed at hardware configuration time and is not user-expansible; verify the count in your CPU's datasheet on the S7-400 CPU 41x manual. Beyond that, switch to IEC TON/TOF/TP inside an FB instance DB.

Is indirect timer addressing with AR1 supported on S7-400?

Yes. The indirect form SD [AR1,P#0.0] is supported on S7-300 and S7-400 CPUs from the firmware versions documented in the STEP 7 STL reference manual. The address register must point to a valid timer cell (P#T0 + offset) before the SD/SS/SP/SF/R instruction; otherwise the CPU raises an addressing error and the OB121 handler is called.

Should I use FC with global TIMER input or FB with IEC TON instance?

For new code, prefer FB with the IEC TON block from the standard library. It stores timing data inside the instance DB, eliminating shared-global resource conflicts, supports re-entrant calls from OBs of different priorities, and survives block interface changes without renumbering. Use the FC + global TIMER pattern only when maintaining legacy S5-style code or when the call environment guarantees exclusive timer-cell ownership.

Back to blog