Programming SCL in TIA Portal: S7-1200/1500 Block Access Guide

David Krause12 min read
SiemensTIA PortalTutorial / 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

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.
Note: OB1 cannot be authored in SCL. The cyclic main OB is generated automatically and only accepts LAD, FBD, or STL source. SCL blocks (FCs, FBs, DBs, user-defined types) must be called from OB1, never replace it.

3. SCL Editor, Compiler, and Debugger Workflow

  1. Add a new block: Project tree → Program blocks → Add new block → type FC/FB → Language: SCL.
  2. Declare the interface (Input, Output, InOut, Static, Temp, Return) in the upper section of the editor.
  3. Write the implementation in the lower section using PASCAL-like syntax (BEGIN ... END_FUNCTION_BLOCK).
  4. 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 03351 for an undeclared identifier).
  5. 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:

  1. Right-click the DB or FC/FB in the project tree.
  2. Select Properties → Attributes.
  3. Tick Standard - S7-300/400 compatible (or uncheck Optimized block access).
  4. Recompile the calling block. The error Cannot assign to symbolic name in optimized block resolves once both the data block and the code block use the same attribute.
Warning: Changing the access attribute invalidates the offline/online block signature. The block must be re-downloaded to the CPU; any HMI tag bound to a DB offset will break until rebound to the symbolic name.

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:

  1. Open PLC tags → Default tag table.
  2. Add a row with name, data type, and address (or leave address empty for an unassigned tag).
  3. 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_TEMP are 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:

  1. Author the application logic in one or more SCL FCs/FBs.
  2. In OB1 (LAD or FBD), drag the SCL block from the project tree onto a network.
  3. 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 named END) 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.
Tip: If the migrated program must remain bit-compatible with an S7-300/400, leave both DBs and code blocks in Standard - S7-300/400 compatible. If you only need to use an S7-1500 as a replacement, switch DBs to Optimized in a controlled pass and update HMI tags from absolute to symbolic addresses.

10. Compilation, Download, and Verification

  1. Compile the entire program: Project tree → right-click CPU → Compile → Software (rebuild all blocks).
  2. Check the Info → Compile pane. Errors show file name, block number, line, and column.
  3. Resolve all warnings related to multi-instance depth (CPU has a limit, e.g. S7-1516 supports 16 levels).
  4. Connect online, then Online → Download to device. TIA Portal performs a consistency check; mismatch of firmware versions will halt the download.
  5. Click Go online → Monitor all. SCL blocks display current values on tagged variables in yellow on the editor's left margin.
  6. 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

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.

Back to blog