Overview
The most common beginner failure in Siemens SCL (Structured Control Language) for the S7-300/S7-400 family is writing a syntactically valid organization block that compiles but never executes user logic. The classic symptom: a function block is declared, an instance DB is generated, and the OB calls it as FB10.DB10(); with no parameters and no body in the call site. The block goes through cyclic OB1 execution, the CPU is in RUN, and yet the outputs never change. This article documents the correct SCL source-file pattern for calling an FB from OB1, the role of the instance DB, and how parameter passing works under the hood.
Audience: engineers who program Step 7 V5.x in SCL, who edit .scl source files by hand or via the SCL Editor, and who need predictable cyclic execution of a self-written FB from OB1.
Prerequisites
- Step 7 V5.5+ or compatible SCL Compiler (SCL V5.3 SP6 or later recommended for S7-300/400).
- Configured S7-300 or S7-400 station in SIMATIC Manager with a CPU 314/315/317/319 or 412/414/416/417.
- S7 Program with at least one source file container in the S7 project's Sources folder.
- Working knowledge of SCL keyword blocks:
FUNCTION_BLOCK,DATA_BLOCK,ORGANIZATION_BLOCK,VAR_INPUT,VAR_OUTPUT,VAR,VAR_TEMP. - Reference: SCL for S7-300/400 Programming Manual (entry ID 109751606).
Why the OB1 Source Compiles but Does Nothing
The SCL compiler treats an empty parameter list on an FB call as legal. It does not warn that the FB will execute with the initial values declared in its VAR / VAR_INPUT sections. If the engineer writes:
ORGANIZATION_BLOCK OB1
VAR_TEMP
info : ARRAY[0..19] OF BYTE;
END_VAR
FB10.DB10();
END_ORGANIZATION_BLOCK
the call is interpreted as: execute FB10 using the instance DB10, take all inputs from their stored instance values, do not write any inputs from process images, and discard the outputs back to the instance. When the FB is purely combinational and reads its inputs only from VAR_INPUT, this means the logic runs once with whatever the instance DB last held — typically all zeros — and never reflects I0.0, I0.1, etc.
The OB1 template that the SCL compiler generates from Insert > Block > Organization Block contains the VAR_TEMP info : ARRAY[0..19] OF BYTE; reserved area (20 bytes required by the S7-300/400 system software) but no logic. Engineers often copy that template and add a single line, expecting it to "just work."
Reference: SCL Source File Structure for an FB + Instance DB + OB1
The minimal complete SCL source file that compiles and runs is shown below. The three blocks must coexist in the same compilation unit; the SCL compiler resolves the cross-references between FB, DB, and OB during the Compile step.
FUNCTION_BLOCK FB10
VAR_INPUT
START : BOOL;
END_VAR
VAR_OUTPUT
RUN : BOOL;
END_VAR
VAR
// Static (instance) variables
END_VAR
BEGIN
RUN := START OR RUN; // latching logic, classic seal-in
END_FUNCTION_BLOCK
DATA_BLOCK DB10 FB10
//
// Block Comment...
//
BEGIN
END_DATA_BLOCK
ORGANIZATION_BLOCK OB1
VAR_TEMP
// Reserved
info : ARRAY[0..19] OF BYTE;
// Temporary Variables
END_VAR
FB10.DB10(
START := I0.0,
RUN := Q0.0);
END_ORGANIZATION_BLOCK
info array at the start of VAR_TEMP is mandatory for OB1 on S7-300/400. The system uses it to record the OB start information (OB1_PRIORITY, OB1_OB_NUMBER, etc.). Removing it produces a compiler error or, in older SCL versions, a corrupted stack frame at runtime.Step-by-Step: Building and Calling the FB in OB1
-
Create the source container. In SIMATIC Manager, right-click the S7 program's Sources folder, choose Insert New Object > SCL Source. Name it (e.g.,
MainProgram). -
Declare the FB interface. In the source, write the
FUNCTION_BLOCK FB10header. DeclareSTART : BOOLunderVAR_INPUT,RUN : BOOLunderVAR_OUTPUT. Place any internal latches inVAR(these become instance-DB-resident static variables). -
Write the FB body. The
BEGIN ... END_FUNCTION_BLOCKsection holds the actual algorithm. For a seal-in:RUN := START OR RUN;. The static instance variables persist across calls — this is the whole point of an FB versus an FC. -
Declare the instance DB.
DATA_BLOCK DB10 FB10tells the SCL compiler to generate DB10 with the layout of FB10. The body can be empty; the compiler fills it from the FB declaration. -
Call from OB1 with explicit parameters. Use positional or named assignment. Named assignment is preferred because it is self-documenting and order-independent:
FB10.DB10( START := I0.0, RUN := Q0.0); - Compile the source. Right-click the source file in SIMATIC Manager and choose Compile > All (or use the SCL Editor's Compile > Selected Objects). Check the compiler output window for errors such as Unknown identifier or Type conflict.
- Download the blocks. In SIMATIC Manager, select the Blocks container and download to the target CPU. After download, perform a Cold Restart only if the DB initial values need to be reset; a warm restart is sufficient to load the new logic.
-
Verify in Monitor/Modify. Open FB10 in the LAD/FBD/STL editor, switch to Monitor mode, and toggle
I0.0on the simulator or in the process.Q0.0should latch whenI0.0is pulsed true.
How Parameter Passing Actually Works
Siemens SCL compiles an FB call into a sequence of STL-like operations. For FB10.DB10(START := I0.0, RUN := Q0.0), the compiler generates code that:
- Copies the value of
I0.0into theSTARTslot of instance DB10. - Calls the FB10 code with
DB10as the instance base register (DI/DB register pair). - Inside the FB, the body
RUN := START OR RUN;resolves asDB10.RUN := DB10.START OR DB10.RUN;— note the right-handRUNreads the previous latched value, and the left-handRUNwrites the new value back to the instance. - On return, the compiler copies
DB10.RUNto the assigned actual parameterQ0.0.
If the engineer writes FB10.DB10(); with no parameters, step 1 is skipped for inputs and step 4 is skipped for outputs. The FB executes but uses the instance DB's stored values verbatim. Because the S7-300/400 clears newly generated instance DBs to zero on download, the latching expression RUN := START OR RUN always evaluates to 0 OR 0 = 0. The output stays at zero forever.
Positional vs. Named Syntax
SCL accepts both styles. Positional:
FB10.DB10(I0.0, Q0.0); // input first, output second by declaration order
Named (recommended for readability and maintenance):
FB10.DB10(
START := I0.0,
RUN := Q0.0);
When the FB has multiple IN/OUT/IN_OUT parameters, the named form prevents the silent-miswire class of bug. Mixed forms are permitted; trailing parameters can be omitted by name with the := syntax.
Common Errors and Their Compiler Diagnostics
| Symptom | Compiler/runtime message | Likely cause | Fix |
|---|---|---|---|
| Logic never executes; output stays FALSE | None (silent) | Empty parameter list at the call site | Pass every VAR_INPUT/VAR_OUTPUT explicitly, or assign the inputs in a separate move before the call |
| Compiler error: Identifier 'DB10' unknown | SCL error at line of FB10.DB10()
|
The DATA_BLOCK DB10 FB10 declaration is missing or in a different source file not yet compiled |
Add the DATA_BLOCK block to the same source (or compile the source that owns it first) |
| Compiler error: DB and FB interface mismatch | SCL: Incompatible types for instance DB | FB10 was recompiled with new interface, but DB10 was not regenerated | Delete DB10 and recompile; the SCL compiler regenerates it from the FB |
| CPU goes to SF (system fault) on first scan | Diagnostic buffer: OB not loaded or OBxx stack overflow | Missing 20-byte info array in OB1 VAR_TEMP
|
Restore the reserved info : ARRAY[0..19] OF BYTE; section |
| Output flickers or behaves non-deterministically | None | Calling FB with both positional and named arguments in unexpected order | Switch to fully named syntax |
| Compiler: Untyped call / call-by-reference required | SCL error on call line | Calling an FC where an FB instance is expected, or vice versa | Use FC10(); for a function, FB10.DB10(); for a function block |
Verification Checklist
- Compile clean. No errors, no warnings in the SCL output window.
- Blocks visible. Blocks > FB10, DB10, OB1 are present in the S7 program container.
-
DB10 has the right layout. Open DB10 in the LAD/FBD/STL editor. It must show
STARTandRUNas BOOLs of the instance view, not as blank bytes. -
Online monitor. In Monitor/Modify, force
I0.0= 1.Q0.0should follow on the first scan, then stay latched whenI0.0returns to 0.DB10.RUNmust mirrorQ0.0. -
Watch the OB1 call site. In online Monitor on OB1, the
FB10.DB10(START := ...)line shows the current input and output values in the right-hand pane. - Diagnostic buffer clean. CPU > Diagnostic Buffer shows no OB1 stack overflow, no Unknown FB, no Type conflict in instance DB.
Alternative Patterns: Passing Parameters via Move Instructions
Some legacy SCL code populates the instance DB inputs with explicit := assignments to the DB symbol before the call:
ORGANIZATION_BLOCK OB1
VAR_TEMP
info : ARRAY[0..19] OF BYTE;
END_VAR
DB10.START := I0.0; // pre-fill instance input
FB10.DB10(); // call without parameter list
Q0.0 := DB10.RUN; // copy instance output to process image
END_ORGANIZATION_BLOCK
This pattern works and is sometimes preferred for code generation from external tools because the call line itself has no parameters. The trade-off: you lose the type checking that named parameter assignment provides. A misspelled symbol on the DB10. line fails to compile, but it does not warn about the loss of the latched state across a re-download with a "warm restart only" reset.
Migrating the Same Pattern to S7-1200/1500 / TIA Portal
The SCL syntax is essentially identical, but the surrounding conventions differ:
- OB1 in S7-1200/1500 is the main cyclic OB, generated by default as
Main [OB1]. TheVAR_TEMP info : ARRAY[0..19] OF BYTE;reserved area is not required on S7-1500 — TIA Portal's SCL compiler manages the start information internally. - Instance DBs are single-instance or multi-instance; for single-instance the call is
"MyFB"(START := I0.0, RUN := Q0.0);with the DB name as a string, or the call is implicit when the FB is inserted as a multi-instance under another FB. - The optimization of the
RUN := START OR RUNpattern is best implemented asRUN := RUN OR START;to keep the right-handRUNin the instance-DB static area on S7-1500 as well. See the SCL for S7-1200/1500 (entry ID 109751608) manual, section 3.5, for parameter-passing semantics.
Field-Proven Caveats
-
Initial values vs. actual values. The instance DB retains its last values across CPU warm restart unless the engineer explicitly reinitializes. For latching logic, this is usually desirable. For startup-into-safe-state designs, the FB body must explicitly clear
RUN := FALSEon first scan using anOB100or a one-shotFirstScanflag. -
Re-download of a single FB. If you re-download only FB10 and the FB interface changed (new
VAR_INPUTadded), DB10 must also be re-initialized. SCL's Compile > All handles this; a manual block download does not. See FAQ: "After changing the FB interface the instance DB is not updated" (entry ID 15364459). - Block consistency offline. When using the SCL source-file approach, the offline Blocks container is populated only by the SCL compiler. Editing FB10 in the LAD/FBD/STL editor after a SCL compile will cause a "block was changed externally" message the next time you compile the source. Decide on one source of truth (SCL source file) and stick to it.
- Cyclic time. The S7-300 OB1 call from the SCL source generates a call tree that the compiler tries to optimize. If OB1 calls FB10 which calls FB11, the cyclic time grows. The SCL manual recommends measuring with CPU > Module Information > Scan Cycle Time after every change.
Quick Reference: OB1 SCL Template (Copy-Paste)
ORGANIZATION_BLOCK OB1
VAR_TEMP
// Reserved for S7-300/400 system software (do not remove)
info : ARRAY[0..19] OF BYTE;
// User temporary variables
nScanCount : INT;
END_VAR
// --- cyclic logic begins here ---
FB10.DB10(
START := I0.0,
RUN := Q0.0);
nScanCount := nScanCount + 1;
// --- end cyclic logic ---
END_ORGANIZATION_BLOCK
Why does my OB1 in SCL compile but the FB logic does not run?
Most often the call site is empty: FB10.DB10();. With no parameter list, SCL skips copying process-image inputs into the instance DB and skips writing outputs back. The FB body executes once with whatever the instance DB already holds (zeros on first download). Pass parameters explicitly: FB10.DB10(START := I0.0, RUN := Q0.0);.
Do I have to re-declare the I/O addresses for every block call inside OB1?
Only at the call site where the FB/FC is invoked. The DATA_BLOCK DB10 FB10 declaration does not redeclare I/O — it only tells the SCL compiler to generate DB10 using the layout of FB10. The actual wiring of process image to FB inputs happens at the call in OB1.
Is the 20-byte info array in OB1 mandatory on S7-300/400?
Yes, for the OB1 template on S7-300 and S7-400. The system software uses the first 20 bytes of VAR_TEMP for start information (priority, OB number, etc.). Removing it causes a CPU fault on first scan. On S7-1200/1500 this reserved area is generated automatically by the TIA Portal SCL compiler and must not be added by hand.
Can I call the FB without parameters and set the inputs by writing to the instance DB directly?
Yes. The pattern DB10.START := I0.0; followed by FB10.DB10(); followed by Q0.0 := DB10.RUN; works. It is sometimes used in code-generated projects. The trade-off is that you lose the named-parameter type checking that catches miswired I/O at compile time.
Why does my latching FB keep losing its state across a download?
Because the instance DB is re-initialized when the DB is re-downloaded. To preserve state across downloads, download only the FB (and OB) and leave the DB untouched, or use a non-volatile area (e.g., a retentive VAR RETAIN inside the FB). For the seal-in RUN := START OR RUN, marking RUN as RETAIN or placing it in a retentive DB region preserves it through CPU restart but not through a full DB re-download.
What is the difference between calling an FC and an FB in SCL from OB1?
An FC (FC10();) has no instance DB and cannot retain state between calls — all internal variables are temporary. An FB (FB10.DB10();) requires an instance DB and uses the DB as the static-variable memory area. Use FCs for pure functions (e.g., a scaling block) and FBs for anything that needs to remember a previous value (e.g., a latched output, a step in a sequence).
Where can I find the official SCL syntax reference for S7-300/400?
The primary reference is the SCL for S7-300/400 Programming and Operating Manual (entry ID 109751606) on the Siemens Industry Online Support portal. For TIA Portal / S7-1200/1500, use SCL for S7-1200/1500 (entry ID 109751608). The Step 7 V5.5 SCL manual is also available as a PDF within the Step 7 installation under Documentation > English > SCL.