Why the SCL Compiler Rejects ARRAY OF TON
In a Siemens S7 function block, declaring a single timer as a static multi-instance works: Test : TON; compiles without error. The declaration Test : ARRAY[1..3] OF TON; does not — the SCL compiler refuses it. The reason is structural: a TON (SFB4) is an FB/SFB type built with IN and OUT parameters, and this type is not permitted as an array element in the static (multi-instance) data area. This is a compiler-level restriction, not a syntax mistake, so no re-declaration trick inside the same static area will make it compile.
This blocks the intuitive pattern of looping over instances, e.g. calling Test[i] or Self_FB[i] inside FOR i := 1 TO 3 DO .... Any loop-based call over indexed multi-instances of an FB type requires one of the workarounds below.
Workarounds for Indexed Multi-Instance Calls
| Approach | Mechanism | Limitation |
|---|---|---|
| CASE OF with individual calls | Declare three separate multi-instances and select each call with a CASE OF instruction | Much code and scrolling; scales poorly |
| WORD_TO_BLOCK_DB | Convert an index/word to a DB number and call with instance DBs | Loses the multi-instance concept entirely |
| Buffer DB with manual copy | Create one extra buffer DB and manually copy contents in/out per call | Manual copy logic; not clean |
| Wrapper FB | Build an FB that calls one DB with all input/output assignments, then call that FB three times with different DBs | Still not a true multi-instance |
Indexed Memory Addressing (Use With Caution)
Because each TON occupies 22 bytes of instance data, you can build your own "array": once you know where the first TON starts in memory, index subsequent timers at 22-byte offsets. Example calculation: TON #i starts at base + (i - 1) * 22 bytes. This avoids the CASE OF duplication, but addressing by raw memory offset bypasses the compiler's type checking and is fragile — any change to the static declaration silently shifts the offsets. Treat this as a last resort, not a clean solution.
Recommended Decision Path
- If the instance count is small and fixed, use separate multi-instance declarations with a CASE OF selector — verbose but fully type-checked.
- If calls must be indexed dynamically, use WORD_TO_BLOCK_DB or a wrapper FB with per-call DBs and accept the loss of true multi-instancing.
- Avoid raw 22-byte indexed addressing unless you control the instance layout permanently and document the offsets.
FAQ
TON (SFB4) is an FB/SFB type built with IN and OUT parameters, and this type is not permitted as an array element in the multi-instance static area. A single Test : TON; declaration is fine; the array form is blocked by the compiler.
How do I call multiple TON instances in a FOR loop in S7?
You cannot index multi-instances directly. Use a CASE OF instruction with individually declared instances, or switch to WORD_TO_BLOCK_DB / a wrapper FB called with different instance DBs.
How many bytes does a TON use in S7 instance data?
A TON occupies 22 bytes, so timer #i can theoretically be addressed at base + (i - 1) * 22 bytes. This memory-indexing method bypasses type checking and breaks if the static declaration changes, so it is not considered a clean solution.