1. Overview: What SCL Is in the SIMATIC Environment
Structured Control Language (SCL) is a high-level, PASCAL-based text language for SIMATIC S7 CPUs. It implements the block structure defined by IEC 61131-3 and supplements the LAD, FBD, and STL graphical editors shipped with STEP 7 and TIA Portal. SCL is intended for:
- Complex arithmetic, loop, and case logic that is cumbersome in LAD/FBD.
- Data processing of arrays, structures, and indirect addressing.
- Reusable FCs and FBs that read/write instance DB tags and global PLC tags.
- Porting legacy STEP 7 V5.x SCL code into TIA Portal projects.
SCL supports both S7-300/400 firmware (using absolute DB addressing such as DB2.DBW0) and the S7-1200/1500 firmware (using symbolic tag access). The two addressing models are not interchangeable inside a single CPU: when a DB is created with the Optimized block access attribute, only symbolic tag names are accepted by the compiler. To re-enable absolute addressing on S7-1200/1500 the DB and the calling block must both be switched to Standard - S7-300/400 compatible.
For the canonical reference see the Siemens SIMATIC S7-1200 SCL programming manual and the legacy S7-SCL V4 Programming and Operating Manual.
2. Prerequisites
| Item | Requirement |
|---|---|
| Engineering tool | STEP 7 Basic/Professional V15 or later (TIA Portal). SCL editor ships with STEP 7 Professional; on STEP 7 Basic a separate SCL optional package is required. |
| CPU family | S7-1200 (firmware V4.0+ recommended), S7-1500, ET 200SP CPU, S7-300/400 (legacy import) |
| Authorization | "SCL" license key in TIA Portal (bundled with STEP 7 Professional, separately licensed for Basic). |
| Knowledge | Familiarity with LAD/FBD block creation, DBs, OB1 cycle, and PLC tag table. |
3. SCL Editor, Compiler, and Debugger Workflow
- Add a new block: Project tree → Program blocks → Add new block → type FC/FB → Language: SCL.
- Declare the interface (Input, Output, InOut, Static, Temp, Return) in the upper section of the editor.
- Write the implementation in the lower section using PASCAL-like syntax (BEGIN ... END_FUNCTION_BLOCK).
- Compile with Ctrl+B or the toolbar icon. Errors are listed in the Inspector → Info → Compile pane with line numbers and Siemens error codes (e.g.
Error 03351for an undeclared identifier). - Download to the CPU (online → reachable device) and use Monitor/Modify with breakpoints in the SCL debugger for step-by-step execution.
The compiler accepts the IEC 61131-3 operators (:=, =, <>, AND, OR, NOT, MOD, **) and SIMATIC extensions (:= as assignment, := within DB initialisation, // single-line comment).
4. Block Access Models: Optimized vs Standard
This is the single most common source of compilation failure when an engineer moves an SCL block from STEP 7 V5.x into TIA Portal, or from an S7-300/400 project into an S7-1200/1500 project.
| Attribute | Optimized block access (default on S7-1200/1500) | Standard - S7-300/400 compatible |
|---|---|---|
| Tag addressing | Symbolic only, e.g. "MyDB".MyTag or #iMyTag inside an FB |
Absolute permitted, e.g. DB2.DBW0
|
| Memory layout | Compiler places tags to optimise access; no fixed offset | Fixed offset from DBW0/DBD4 onwards; visible in the offset column |
| Supported CPUs | S7-1200/1500, ET 200SP CPU | S7-300/400, S7-1200/1500 (manual override) |
| Default state in TIA Portal | Enabled when a new DB is created | Disabled by default; toggle under DB properties → Attributes |
| Use case | New projects, symbolic programming, HMI tag consistency | Legacy import, mixed absolute/symbolic libraries, PROFINET I/O slot addressing |
To change the attribute:
- Right-click the DB or FC/FB in the project tree.
- Select Properties → Attributes.
- Tick Standard - S7-300/400 compatible (or uncheck Optimized block access).
- Recompile the calling block. The error
Cannot assign to symbolic name in optimized blockresolves once both the data block and the code block use the same attribute.
5. Accessing DB Tags from SCL
5.1 Symbolic access (S7-1200/1500 default)
// Inside an FB with instance DB "MotorInst"
#SpeedActual := "MotorDB".Setpoint;
"MotorDB".ErrorWord.%X0 := TRUE; // bit access on a WORD
IF "MotorDB".State = 3 THEN
"HMI".AlarmAck := 1;
END_IF;
Tags are referenced by their fully qualified name. Bit, byte, word, and dword slices are written with the %X0, %B0, %W0, %D0 suffix as defined by IEC 61131-3.
5.2 Absolute access (Standard - S7-300/400 compatible)
// On an S7-300/400 CPU or a block with the compatible attribute
DB2.DBW0 := 16#1234;
DB2.DBD4 := REAL#3.14159;
DB2.DBX2.0 := TRUE; // bit 0 of byte 2
iValue := DB2.DBD8;
When the block attribute is Standard - S7-300/400 compatible, both styles are accepted by the compiler and the absolute offsets are visible in the DB "Offset" column.
5.3 Mixed scenario
If the calling FC/FB is Optimized but the target DB is Standard, or vice versa, the compiler emits error 03061 — Inconsistent block access: absolute access to symbolic data is not permitted. The fix is to make the two blocks use the same attribute, or to change every absolute reference in the code to a symbolic reference.
6. Global PLC Tags versus DB Tags
SCL can read and write two categories of memory:
| Category | Where declared | Retention | Typical use |
|---|---|---|---|
| PLC tag (global) | PLC tag table | Configurable (Set in IDB) | I/O mapping, HMI shared variables, status flags |
| DB tag (instance or global DB) | Inside a DB | Per-tag setting in the DB | Per-Motor / per-Valve data, recipe sets, structured records |
To declare a new global tag:
- Open PLC tags → Default tag table.
- Add a row with name, data type, and address (or leave address empty for an unassigned tag).
- Reference from SCL with the quoted name:
"Conveyor_Run" := TRUE;
To declare a DB tag, open the data block and add rows in the same way; the generated name is "<DB name>".<Tag name>.
7. Declaring Variables Inside an SCL Block
FUNCTION_BLOCK "MotorCtrl"
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
iStart : BOOL;
iStop : BOOL;
iSetpoint : REAL;
END_VAR
VAR_OUTPUT
qRunning : BOOL;
qFault : BOOL;
END_VAR
VAR
sSpeed : REAL; // static, retained with instance DB
sTimer : TON; // instance of IEC timer
END_VAR
VAR_TEMP
tIdx : INT;
END_VAR
BEGIN
sTimer(IN := iStart AND NOT iStop,
PT := T#5S);
IF sTimer.Q THEN
qRunning := TRUE;
sSpeed := iSetpoint;
END_IF;
IF sSpeed > 1500.0 THEN
qFault := TRUE;
END_IF;
END_FUNCTION_BLOCK
Notes:
-
{ S7_Optimized_Access := 'TRUE' }sets the block attribute from source; it is equivalent to the dialog toggle described in section 4. - Multi-instance FBs (e.g.
sTimer : TON;) are placed in the static section so that the timer DB is embedded in the calling FB's instance DB. - Temporary variables in
VAR_TEMPare re-initialised on every call; never use them to store state across cycles.
8. Calling FBs and FCs from OB1
OB1 cannot be written in SCL. The standard pattern is:
- Author the application logic in one or more SCL FCs/FBs.
- In OB1 (LAD or FBD), drag the SCL block from the project tree onto a network.
- Wire inputs/outputs; for FBs, TIA Portal automatically creates an instance DB the first time the FB is dropped into OB1.
8.1 Unconditional FC call from OB1 (LAD)
| "MotorCtrl_DB"(
| iStart := "Start_PB",
| iStop := "Stop_PB",
| iSetpoint := "Recipe".RPM,
| qRunning => "HMI".MotorRunning,
| qFault => "HMI".MotorFault
| );
8.2 Conditional FB call from OB1
Wrap the call with an EN/ENO contact, or use a network with an AND condition on iStart AND NOT "E_Stop". The call itself is unconditional within the network; the network enables or disables it.
8.3 SCL calling another SCL block (inside the same program)
// Inside an FC "Sequence"
"MotorCtrl_DB"(iStart := #bAuto,
iStop := #bFault,
iSetpoint := #rRPM);
IF "MotorCtrl_DB".qRunning THEN
"ConveyorDB".Run := TRUE;
END_IF;
9. Importing Legacy S7-SCL Code from STEP 7 V5.x
Projects created in the legacy S7-SCL V4 editor can be migrated to TIA Portal with Project → Migrate project. After migration:
- All blocks are flagged as Standard - S7-300/400 compatible so that absolute addresses survive the import.
- User-defined types (UDTs) are converted to PLC data types.
- The "
:=" assignment and the ":=" operator remain unchanged; reserved-word conflicts (e.g. variable namedEND) must be renamed. - DBs that were created without the Optimized attribute can be left untouched; new SCL blocks added to the migrated project can be optimised on a per-block basis.
10. Compilation, Download, and Verification
- Compile the entire program: Project tree → right-click CPU → Compile → Software (rebuild all blocks).
- Check the Info → Compile pane. Errors show file name, block number, line, and column.
- Resolve all warnings related to multi-instance depth (CPU has a limit, e.g. S7-1516 supports 16 levels).
- Connect online, then Online → Download to device. TIA Portal performs a consistency check; mismatch of firmware versions will halt the download.
- Click Go online → Monitor all. SCL blocks display current values on tagged variables in yellow on the editor's left margin.
- Use Monitor/Modify on a single tag to force a value; with the SCL debugger active, breakpoints can be set by clicking the gutter next to a line number.
11. Common Compiler Errors and Remedies
| Error code | Meaning | Fix |
|---|---|---|
| 03061 | Absolute address used on an Optimized block (or vice versa) | Make the calling block and the target DB share the same attribute, or rewrite as symbolic access. |
| 03351 | Identifier not declared | Add the name to VAR_INPUT / VAR / VAR_TEMP / VAR_OUTPUT / PLC tags / DB. |
| 03521 | Type mismatch on assignment | Use explicit conversion: REAL_TO_INT, INT_TO_WORD, BOOL_TO_INT. |
| 03082 | Instance DB missing for FB call | Drop the FB onto OB1 once so TIA Portal auto-generates the instance DB, or create it manually with Add new block → DB → type: Instance → FB. |
| 02621 | OB1 contains unsupported language construct | OB1 must remain in LAD/FBD/STL. Move SCL code into an FC/FB called from OB1. |
12. Field-Proven Patterns and Edge Cases
12.1 Loop over an array of UDTs
FOR #i := 1 TO 16 DO
"ValveBank".Valve[#i].OpenCmd :=
"Recipe".Step[#i].Open AND NOT "E_Stop";
END_FOR;
The loop index #i is an INT; the array element must exist at compile time, otherwise the compiler emits 03130 — Index out of user-defined range.
12.2 Indirect addressing via POINTER / VARIANT
S7-1500 supports VARIANT and DB_ANY. Legacy S7-300/400 SCL uses the POINTER data type:
// Legacy SCL
pTemp : POINTER;
pTemp := ADR("MotorDB");
// write into the pointed-to byte
WORD_TO_BLOCK_DB(pTemp).DW[#iOffset] := #iValue;
This pattern requires Standard - S7-300/400 compatible; the compiler rejects WORD_TO_BLOCK_DB on Optimized blocks.
12.3 Calling an SCL FB from a LAD FB
Languages can be mixed inside a single FB instance. Create the wrapping FB in LAD, declare inst_Motor : "MotorCtrl"; in the static section, then call inst_Motor(iStart := "Start", ...) in a network. TIA Portal generates the multi-instance DB automatically.
12.4 Retain behaviour
For an S7-1500, mark static variables as Retain in the DB properties. SCL syntax:
VAR RETAIN
sProductionCount : DINT;
END_VAR
Without the RETAIN qualifier the variable is initialised on cold restart.
13. Verification Checklist Before Going Online
- [ ] CPU firmware matches the TIA Portal version matrix (see TIA Portal "Readme" file, e.g. V17 supports S7-1500 firmware V2.9 and V3.0).
- [ ] Every FB has an associated instance DB.
- [ ] All blocks used in OB1 are downloaded to the same CPU as OB1 (cross-CPU calls are not supported).
- [ ] HMI tags point to the symbolic name; absolute addresses will not bind if the DB is Optimized.
- [ ] Watchdog time (OB1 cycle time) is below 150 ms for a standard S7-1516; SCL loops with large iteration counts can blow the cycle and trigger OB80.
- [ ] Security: CPU protection level is set under CPU properties → Protection → Access level; production projects should disable write access to PLC tags from HMI.
14. Troubleshooting Matrix
| Symptom | Likely cause | Diagnostic step | Resolution |
|---|---|---|---|
| Download fails with "Inconsistent block" | Block attribute mismatch between DB and calling FB | Open Info → Compile; look for error 03061 | Set both to Optimized or both to Standard |
| SCL block visible in tree but not callable | Block not compiled | Check Compile pane for syntax error | Fix error, recompile |
| Value written in SCL not visible in HMI | HMI tag still points to absolute address of a now-Optimized DB | Inspect HMI tag → Connection | Rebind HMI tag to symbolic name |
| OB80 (time error) triggered | SCL loop exceeds cycle time | Online → Diagnostics → Cycle time | Reduce loop bound or split across multiple OBs (OB30 – OB38 cyclic interrupts) |
| "Identifier not declared" on PLC tag | PLC tag not in the active tag table | Open PLC tags, check the table the block sees | Move tag to Default tag table or add a new table and include it in the block |
15. Standards and Reference Documents
- IEC 61131-3:2013 — Programmable controllers, Part 3: Programming languages. Defines the SCL syntax subset (ST - Structured Text).
- Siemens SIMATIC S7-1200 SCL manual collection.
- Siemens S7-SCL V4 Programming and Operating Manual (legacy STEP 7 V5.x).
Why can't I write OB1 in SCL?
OB1 is the system-generated cyclic main block and is reserved for LAD, FBD, or STL. Author your application logic in SCL FCs/FBs and call them from OB1; TIA Portal will create an instance DB automatically the first time an FB is dropped onto an OB1 network.
How do I access a DB tag from SCL on an S7-1200?
Use the symbolic name in quotes: "MyDB".MyTag := 10; Absolute addressing such as DB2.DBW0 is only accepted when both the calling block and the data block are flagged Standard - S7-300/400 compatible under Properties → Attributes.
Which compiler error means the block attribute is wrong?
Error 03061 — "Inconsistent block access". Either flip the Optimized/Standard switch so the calling block and the DB match, or rewrite every absolute reference in the SCL source as a symbolic reference.
Can I mix LAD and SCL inside the same FB?
Yes. Create the outer FB in LAD, declare an instance of an SCL FB in the static section (inst : "MySclFb";), and call it from a LAD network. The generated multi-instance DB embeds the SCL FB's statics automatically.
Where is the official SCL getting-started documentation?
The TIA Portal online help ships SCL examples under Programming concepts → Programming languages → SCL. The legacy S7-SCL V4 manual still covers fundamentals; the current S7-1200/1500 reference is the SCL manual collection.