Generating Standalone Data Blocks in SCL for S7-300/400 and TIA Portal
Structured Control Language (SCL) on Siemens SIMATIC S7-300/400 controllers (STEP 7 V5.x) and the TIA Portal engineering environment allows engineers to declare Data Blocks (DBs) directly in source files rather than assembling them field-by-field in the LAD/FBD/STL editor. This is the recommended approach for projects that need long configuration tables, parameter lists, recipe structures, or shared memory maps referenced by multiple Function Blocks (FBs) and Functions (FCs).
This article documents the canonical SCL syntax for declaring a global, standalone DB, contrasts it with instance-DB generation, and shows how to leverage the TIA Portal Openness API to automate bulk generation. The patterns apply to SIMATIC S7-300, S7-400, S7-1200, and S7-1500 controllers, with notes on syntax differences between STEP 7 V5.x and TIA Portal.
1. Prerequisites
- STEP 7 V5.5 / V5.6 (or compatible) with the S7-SCL add-on installed, OR TIA Portal V16 / V17 / V18 / V19 / V20 / V21 with the SCL editor.
- For automated bulk generation: TIA Portal Openness API installed (licensed add-on on TIA Portal).
- Source organization: an SCL source file (
.scl) inside the S7 program / PLC software tree, OR a SCL/STL source container in the Sources folder of the S7 project. - Symbol table access: the global DB symbol must be declared as
DB nwherenis the DB number you reserve.
DATA_BLOCK grammar). TIA Portal ships the same grammar for the S7-1200/1500 controllers.
2. Understanding DB Types: Instance vs Global
Before declaring a DB, decide which kind you actually need.
| DB Type | Created by | Tied To | Typical Use | Auto-Generated? |
|---|---|---|---|---|
| Instance DB | FB call / instance declaration | A specific FB | Holds static VAR of that FB across calls | Yes, when you instantiate the FB |
| Global / Standalone DB | Manual creation, SCL source, or Openness API | Nothing - freely referenced | Shared configuration, recipes, lookup tables | No, must be declared explicitly |
| System DB (SDB) | STEP 7 internally | Hardware / CPU config | Hardware interrupt assignments, etc. | Generated by HW Config / device config |
| Array DB | Manual creation | None | Large contiguous typed memory | No |
The user's pattern - one configuration DB referenced from many FBs - is a global, standalone DB. It must NOT be created as an instance of any FB, otherwise SCL will append the FB's VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR_STATIC, and VAR_TEMP regions into it, which is exactly the behavior the user reported as undesirable.
3. Declaring a Standalone Global DB in SCL (STEP 7 V5.x / TIA Portal)
The grammar for declaring a global DB in an SCL source file is:
DATA_BLOCK <DB name or number>
{ TITLE = '<comment text>' ; }
{ AUTHOR : '<author>' ; }
{ FAMILY : '<family>' ; }
{ NAME : '<name>' ; }
{ VERSION : <number> ; }
STRUCT
<variable declaration>
...
END_STRUCT ;
BEGIN
<initialization assignments>
END_DATA_BLOCK
The minimum required form is:
DATA_BLOCK logic_config
STRUCT
input_list : ARRAY[0..8191] OF WORD;
block_list : ARRAY[0..8191] OF STRUCT
typ : BYTE;
inputs : WORD;
input_index: WORD;
END_STRUCT;
END_STRUCT ;
BEGIN
END_DATA_BLOCK
Key points to observe:
- The block is opened with the keyword
DATA_BLOCKand closed withEND_DATA_BLOCK. There is no trailing semicolon afterEND_DATA_BLOCK. - The block name (
logic_config) must be unique within the S7 program. It is registered in the symbol table as typeDBwith the address assigned by the compiler. - The header attributes (
TITLE,AUTHOR,FAMILY,NAME,VERSION) are optional butTITLEis the comment that appears in the block properties dialog and the cross-reference. - The
STRUCTwrapper around the variable declarations is mandatory in SCL for a global DB; it ensures the compiler allocates the DB with a length matching the sum of the members. - The
BEGIN ... END_DATA_BLOCKsection holds initialization values and is optional. If you need default values, list them by symbolic name. If you omit the section, the DB is filled with zeros (or the configured retentive defaults from the CPU).
4. Referencing the Standalone DB from FBs and FCs
Once compiled, the DB is treated as a global symbol. You can access its members from any code block (OB, FB, FC) using fully qualified symbolic names:
my_index := logic_config.block_list[logic_pos].input_index;
my_input := logic_config.input_list[my_index];
Or by absolute addressing using the DB number assigned by the compiler:
L DBW [AR1,P#0.0] // load logic_config.input_list[my_index]
T MW 100
For S7-300/400, a global DB occupies a single open DB register. You open it with OPN DB (STL) or implicitly by using fully qualified symbolic access in SCL.
RETAIN attribute). In STEP 7 V5.x, set the Non-Retain area in the DB properties. In TIA Portal, check the "Retain" column in the tag table of the DB. Tags outside the retentive area are reset to their initial values on a cold restart; tags inside are preserved across power cycles and warm restarts.
5. Step-by-Step Workflow: Creating the DB Inside the SCL Editor
The fastest, most error-resistant way to write a long DB in SCL is to start from the SCL editor template rather than typing the DATA_BLOCK header by hand.
5.1 STEP 7 V5.x / S7-SCL
- Open the S7 project in SIMATIC Manager.
- Right-click the Sources folder of the S7 program and choose Insert New Object → SCL Source.
- Open the source file by double-clicking it. The SCL editor launches.
- From the menu, choose Insert → Block Template → DB. A pre-populated
DATA_BLOCKskeleton is inserted at the cursor. - Fill in the variable declarations between
STRUCTandEND_STRUCT. - Choose File → Compile (or press Ctrl+F7) to generate the DB.
- Open the generated DB in the LAD/FBD/STL editor to verify length, offsets, and default values.
5.2 TIA Portal (S7-1200 / S7-1500 / S7-300/400 as configured)
- In the project tree, right-click the Program blocks folder of the PLC device.
- Choose Add new block → Data block.
- Set the type to Global DB (default), assign a number, and confirm.
- The DB editor opens in the TIA Portal with a table of declared tags. You can paste a tab-separated list directly into the table for bulk creation.
- Alternatively, use External source files: add a
.sclsource to the External Sources folder, right-click, and choose Generate blocks from source.
Both paths end in a single global DB whose members can be referenced from any code block in the program.
6. Auto-Generation Patterns: ARRAY, STRUCT, UDT
Long configuration lists are best expressed as ARRAY elements with STRUCT element types or as a User-Defined Type (UDT) repeated by an ARRAY. UDTs are particularly useful when the same shape is needed in several DBs.
6.1 Inline ARRAY of STRUCT (no UDT)
DATA_BLOCK motor_table
STRUCT
motor : ARRAY[1..64] OF STRUCT
name : STRING[16];
rated_rpm : REAL;
rated_kw : REAL;
enable_tag : BOOL;
fb_instance : INT; // index of associated FB instance DB
END_STRUCT;
END_STRUCT ;
BEGIN
END_DATA_BLOCK
6.2 UDT-Based Repetition
First declare a UDT (this example is TIA Portal SCL syntax; STEP 7 V5.x uses TYPE ... END_TYPE with a separate UDT block):
TYPE "UDT_motor"
STRUCT
name : STRING[16];
rated_rpm : REAL;
rated_kw : REAL;
enable_tag : BOOL;
fb_instance : INT;
END_STRUCT;
END_TYPE
Then declare the DB using the UDT:
DATA_BLOCK motor_table
STRUCT
motor : ARRAY[1..64] OF "UDT_motor";
END_STRUCT ;
BEGIN
END_DATA_BLOCK
Advantages of the UDT approach:
- Single source of truth for the record shape - one change updates every DB that uses it.
- Bulk initialization in the
BEGINblock is cleaner:motor[1].rated_rpm := 1450.0; - Easier to export/import through TIA Portal Openness (see Section 7).
6.3 STEP 7 V5.x SCL UDT syntax
In STEP 7 V5.x, UDTs are block objects (block type UDT) created in the S7 program. The SCL source to declare one is:
TYPE UDT10
STRUCT
name : STRING[16] ;
rated_rpm : REAL ;
rated_kw : REAL ;
enable_tag: BOOL ;
fb_instance : INT ;
END_STRUCT ;
END_TYPE
And the DB referencing the UDT:
DATA_BLOCK DB100
STRUCT
motor : ARRAY[1..64] OF UDT10 ;
END_STRUCT ;
BEGIN
END_DATA_BLOCK
7. TIA Portal Openness API for Bulk DB Generation
When a project requires hundreds or thousands of tags in a global DB - for example a configuration table generated from a spreadsheet - manually editing the DB is impractical. TIA Portal exposes the Openness API, a .NET API that drives the engineering UI programmatically.
7.1 High-Level Workflow
- Add a reference to
Siemens.EngineeringandSiemens.Engineering.Hmiin your .NET project. - Open a TIA Portal instance via
new TiaPortalInstance(TiaPortalMode.WithUserInterface)orWithoutUserInterface. - Open the project with
project.Open(...). - Navigate to the target PLC's Program blocks folder.
- For each DB to create: instantiate a
PlcBlockUserGroupor directly add aPlcBlockwithBlockType = DataBlock. - Populate the
PlcBlock'sInterfaceby writing the SCL source body to aPlcTextAssociationor by setting theAttributescollection. - Call
plcBlock.Compile()to compile the DB inside TIA Portal.
7.2 C# Skeleton (Conceptual)
using Siemens.Engineering;
using Siemens.Engineering.SW;
using Siemens.Engineering.SW.Blocks;
var tia = new TiaPortalInstance(TiaPortalMode.WithUserInterface);
var project = tia.GetOpenProject() ?? tia.Projects.Open(new FileInfo(@"C:\Proj\MyProj.ap21"));
var device = project.GetService<DeviceService>().Devices.First();
var sw = device.GetService<SoftwareContainer>().Software as PlcSoftware;
var blockGroup = sw.BlockGroup.Groups.Find("Program blocks").Groups.Find("MyConfig");
PlcBlock db = PlcBlock.Create(blockGroup, "logic_config", BlockType.DataBlock, 0 /* auto-number */, true /* isDB */, null);
db.ProgrammingLanguage = ProgrammingLanguage.SCL;
db.Interface.TextualSclSource = @"
DATA_BLOCK logic_config
STRUCT
input_list : ARRAY[0..8191] OF WORD;
block_list : ARRAY[0..8191] OF STRUCT
typ : BYTE;
inputs : WORD;
input_index : WORD;
END_STRUCT;
END_STRUCT;
BEGIN
END_DATA_BLOCK
";
db.Compile();
8. XML Schema Notes for SCL DB Export/Import
When DBs are exported from TIA Portal (for example via the project archive or a custom Openness script), the data is serialized to an XML form. Two non-obvious rules govern round-tripping SCL DBs through XML.
-
The
%prefix on the DB name is stripped in XML. The%character is added automatically by the TIA Portal importer when the block is reconstructed. The XML payload therefore contains the bare name, e.g.<Name>logic_config</Name>even though the in-project name is%logic_config. Reference: Export/Import of Structured Types of SCL Blocks - TIA Portal. -
Whitespace between address parts is allowed. Symbolic addresses such as
DB10.DBX0.0can appear in the XML asDB10 . DBX 0 . 0. Both forms import identically. The importer normalizes the spacing.
These rules matter when you build a generator that produces XML to feed back into TIA Portal: do not inject literal % characters, and do not worry about tightening or relaxing internal whitespace in address strings.
9. Verification
After generating the DB, perform the following checks before downloading to the CPU.
- Compile cleanly. In STEP 7 V5.x, the status bar shows 0 errors, 0 warnings. In TIA Portal, open the Info → Compile tab and confirm the same.
-
Check DB length. In the block properties, the "Length in bytes" must equal the sum of the member sizes. For the example,
8192 * 2 = 16384bytes forinput_listplus8192 * 5 = 40960bytes forblock_list, total57344bytes (within the S7-300/400 DB size limits for the CPU in use). - Cross-reference. Use Options → Cross References in STEP 7 V5.x or the cross-reference in TIA Portal to confirm that the FBs and FCs that should read the configuration DB do so, and that no instance DB is accidentally pointing at the same number.
- Watch table test. Open a watch table, force a value in the new DB, run a single scan, and verify the consumer FB sees the change. For an S7-300/400, use the VAT or the Monitor/Modify function with a breakpoint on the consuming FB.
- Retain test. With the configuration DB marked retentive, perform a power cycle (off / on) and confirm values are preserved.
10. Common Errors and Troubleshooting
| Symptom | Probable Cause | Fix |
|---|---|---|
| Compiler "Identifier already used" | The DB name collides with an existing symbol or an instance DB number | Rename the DB or change the reserved DB number in the symbol table |
| Compiler "Type not declared" for a STRUCT member | Inline STRUCT missing END_STRUCT or wrong nesting |
Recheck brackets; SCL requires explicit closure of every STRUCT and ARRAY
|
| DB has extra members inherited from an FB | The block was compiled as an instance of an FB | Re-declare as a global DB using the DATA_BLOCK template in SCL |
| Values reset to zero on warm restart | Tags are not marked retentive | Open the DB properties, set the retentive boundary past the last needed tag |
Openness import creates a DB named %logic_config
|
Source XML included a literal % prefix |
Strip the % from the XML; the importer will add it automatically |
| DB length exceeds work memory | ARRAY bounds too large for the target CPU | Reduce the upper bound, split into multiple DBs, or migrate to a CPU with a larger work memory |
| Compiler "STRING without length specification" | Use of STRING without bracketed length |
Always specify STRING[n] with explicit length |
11. S7-300/400 vs S7-1200/1500 Differences
The DATA_BLOCK syntax is essentially identical between STEP 7 V5.x and TIA Portal, with these practical differences:
-
UDT declaration site. STEP 7 V5.x uses a standalone UDT block (
UDT n). TIA Portal uses theTYPE ... END_TYPEregion inside a global DB or inside a PLC data type block. - Optimized vs standard block access. S7-1500 DBs are optimized by default; symbolic but not absolute access is allowed. S7-300/400 DBs are standard by default; both are allowed.
- Retentive declaration. TIA Portal lets you tick "Set in IDB" per tag. STEP 7 V5.x uses a single retentive boundary in the DB properties.
-
Initialization syntax. Identical in both worlds; multi-line initializers in the
BEGINblock are compiled identically.
12. Field-Proven Tips
-
Start from the template, not the empty file. The Insert → Block Template → DB menu item in the SCL editor pre-fills the header correctly and is faster than hand-typing
DATA_BLOCK ... END_DATA_BLOCK. -
Use ARRAY of UDT for tables. Editing 64 individual STRUCT definitions is error-prone; one UDT and an
ARRAYof it is 5 lines of code. - Reserve the DB number. In STEP 7 V5.x, place a placeholder symbol in the symbol table with the desired DB number before compiling, so the compiler does not assign an unexpected number that collides with an instance DB.
- Mind the CPU limits. S7-300 CPUs (CPU 312/314/315/317/319) impose per-DB size limits (typically 8 KB to 64 KB depending on the CPU). The example with 57344 bytes fits a CPU 319 but not a CPU 312. Check the CPU datasheet before declaring large ARRAYS.
- Avoid instance DBs for shared data. A common antipattern is to store shared configuration inside an FB's instance DB and read it from other FBs via "multi-instance" tricks. This creates hidden coupling and makes the project harder to maintain. Use a global DB instead.
-
Compile the SCL source as a single unit. When the SCL source file contains the
DATA_BLOCKdeclaration, the SCL compiler resolves forward references and emits the DB in the right order. If you mix UDT, FB, and DB declarations in one source file, compile the whole file at once.
FAQ
Why does the SCL compiler add FB local variables to my DB?
Because the DB has been created as an instance of an FB rather than a global DB. Re-declare the block using DATA_BLOCK <name> as the first line (the standalone header, not the instance header that SCL inserts when an FB is placed). The Insert → Block Template → DB menu item always inserts the standalone header.
How large can a single global DB be on an S7-300/400?
It depends on the CPU. A CPU 312 limits DBs to 8 KB; CPU 315-2 DP to 16 KB; CPU 317-2 to 64 KB; CPU 319-3 to 64 KB. The S7-400 series extends this to 64 KB on most CPUs and several MB on the CPU 417. Always check the CPU datasheet for the exact figure.
Can I declare a global DB inside the same SCL source as FBs?
Yes. The SCL source file may contain any combination of TYPE, DATA_BLOCK, FUNCTION_BLOCK, and FUNCTION declarations, in any order. Compile the entire source file in one pass so the compiler can resolve cross-references.
How do I keep my configuration DB values across a power cycle?
Mark the tags that must survive as retentive. In STEP 7 V5.x, set the retentive boundary in the DB properties past the last retained tag. In TIA Portal, tick the "Retain" column in the DB tag table for each tag you want to keep. The CPU preserves retained values across power off / on and across warm restarts.
What is the difference between a UDT and a DB with an inline STRUCT?
A UDT is a reusable type definition. You declare it once and reference it from many DBs, FBs, or FCs as a custom data type. An inline STRUCT is a one-off type used only inside the DB where it appears. Use UDTs when the same record shape is needed in more than one place or when you want to change the shape in one location and have it propagate everywhere.