Overview: What a "Database" Means on an S7-1200
A SIMATIC S7-1200 CPU does not ship with a relational database engine, an SQL layer, or a true file-based table manager such as the kind found in PC servers running Oracle, Microsoft SQL Server, or MySQL. Inside the CPU's load memory and work memory, all persistent application data is stored in data blocks (DB), and the closest engineering analog to a "table" is an array of a PLC data type (UDT) stored in a global DB. The 1200's firmware (V4.0 and later) adds a complementary function: the Data Log instruction set, which can write CSV-style records to the internal flash or to a Siemens SMC (SIMATIC Memory Card) and which survives a power cycle.
This guide shows how to combine both mechanisms to satisfy a typical industrial requirement: keep the last N records (commonly 100) resident in PLC memory for in-process comparison, and at the same time forward a copy to an external device (panel, PC, MES, or peer PLC) for archiving. The approach is CPU-portable, deterministic, and survives firmware updates from V4.2 through V4.7 (the most recent S7-1200 firmware line as of this writing). For an authoritative description of the CPU's memory model, refer to the S7-1200 Programmable Controller System Manual entry on the Siemens Industry Online Support portal.
Prerequisites
-
CPU: SIMATIC S7-1200, firmware V4.0 or later. Data Log functionality is available from V4.0; multiple simultaneous Data Log records and the
DataLogWriteinstruction are optimized in V4.2 and V4.4. CPU models 1211C, 1212C, 1214C, 1215C, and 1217C are all supported. - Engineering software: TIA Portal V15.1 or later. The V17 / V18 releases add the UDT-as-array editor and the data block snapshot compare that this article uses.
- Memory card: A Siemens SMC (6ES7 954-8Lxxxxx series) is required if you intend to log records across power cycles. The internal flash is used for the recipe and Data Log area only; retain variables and DBs are kept in the work memory of the CPU.
- External device: Identify the target (PC with WinCC Runtime, panel, MES via OPC UA server on the CPU, S7 partner, or Modbus TCP master). The S7-1200 CPU exposes an OPC UA server from firmware V4.4 onward, which is documented in the S7-1200 OPC UA Server Function Manual.
- Record structure: A list of tags that constitute a single record. Typical examples are batch number (DINT), timestamp (DTL), measured value (REAL), quality code (BYTE), operator ID (STRING[16]).
Design the Record as a UDT
Creating a User-Defined Data Type (UDT) centralises the record layout, makes any later change a one-touch edit, and lets the same UDT be reused in multiple DBs and FB interfaces. In TIA Portal:
- Project tree → PLC_x → PLC data types → Add new data type.
- Name it
type_Record. - Declare the columns. A typical 28-byte record layout for a 100-record buffer fits easily inside a 1212C's 50 KB work memory and is shown below.
| Name | Data type | Length (bytes) | Comment |
|---|---|---|---|
| RecordID | DINT | 4 | Monotonic counter, 1..2^31-1 |
| Timestamp | DTL | 12 | Date-and-time, µs resolution |
| BatchNo | DINT | 4 | Batch / lot identifier |
| Value | REAL | 4 | Measured value |
| Quality | BYTE | 1 | 0=Good, 1=Bad, 2=Substituted |
| Operator | STRING[16] | 18 | Operator tag from HMI login |
| Total | 43 | Round up to 44 with word alignment |
DTL is the Siemens-native 12-byte structure (YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, NANOSECOND plus a weekday field) defined in the S7-1200 System Manual, Section on Data Types. Using DTL instead of a custom date-time avoids the cost of converting between DATE_AND_TIME and STRING whenever the data is forwarded to the panel or to a relational database downstream.
Allocate the Global DB with an Array of UDT
- Project tree → PLC_x → Program blocks → Add new block → DB (global).
- Name it
DB_Records. Disable "Optimized block access" if you intend to access the array from an S7 PUT/GET partner or from a non-TIA-aware OPC client. Keep it optimized for symbolic access from TIA Portal code only. - Inside the DB, add a single tag:
Records : Array[0..99] of "type_Record". Index 0..99 yields exactly 100 elements. - Set the retentivity of the array to "Set in IDB" and tick Retain for the array. For a 1214C with 10 KB retain area, a 100×44-byte array (4400 bytes) fits. For a 1211C with only 2 KB retain, scale the array to 45 elements and persist the rest to Data Log on the SMC.
- Add two control tags to the same DB:
-
WriteIndex : INT— next free slot. Range 0..99. -
RecordCount : DINT— monotonic, never resets. Used as the RecordID seed.
-
Write Logic: Append a New Record
The canonical write is "fill the slot at WriteIndex, then increment modulo 100". The following structured-text snippet is suitable for an SCL (S7-1200 SCL is included with every TIA Portal install from V13 onward) function block called FB_RecordAppend:
// FB_RecordAppend -- call in OB1 on the rising edge of a "Save" trigger
#tmpRecord.RecordID := DB_Records.RecordCount + 1;
#tmpRecord.Timestamp := DTL_FROM_DT(IN := DATE_AND_TIME#STARTUP);
#tmpRecord.BatchNo := "DB_Process".ActiveBatch;
#tmpRecord.Value := "DB_Process".LastMeasured;
#tmpRecord.Quality := "DB_Process".QualityCode;
#tmpRecord.Operator := "DB_HMI".CurrentUser;
// Write into the ring buffer
DB_Records.Records[DB_Records.WriteIndex] := #tmpRecord;
// Advance the index with wrap-around
IF DB_Records.WriteIndex = 99 THEN
DB_Records.WriteIndex := 0;
ELSE
DB_Records.WriteIndex := DB_Records.WriteIndex + 1;
END_IF;
// Bump the global counter
DB_Records.RecordCount := DB_Records.RecordCount + 1;
This is a ring buffer: once 100 writes have occurred, the oldest record is overwritten in place. That matches the original requirement: "the last 100 records have to be in PLC memory for comparing". No memory is moved, no garbage collection is triggered, and the write completes in a single OB1 cycle regardless of the array size, which is critical for a 1 ms OB1.
Read Logic: Search and Compare
Searching the 100-element array in ladder is verbose; a compact SCL loop is cleaner. Place this code in a function FC_FindByBatch:
// FC_FindByBatch -- returns index of newest record with given batch
#foundIndex := -1;
FOR #i := 0 TO 99 DO
IF DB_Records.Records[#i].BatchNo = #searchBatch THEN
#foundIndex := #i;
#foundValue := DB_Records.Records[#i].Value;
#foundTime := DB_Records.Records[#i].Timestamp;
EXIT; // newest first because search starts at index 0
END_IF;
END_FOR;
IF #foundIndex = -1 THEN
// batch not in buffer
END_IF;
The search executes in ≤100 iterations, each at most a few microseconds, so worst-case scan-time impact is well below 1 ms on any 1200 CPU. If your scan budget is tighter (1 ms OB1 with multiple search calls per cycle), precompute a hash index in a second array of the same size or split the array by BatchNo modulo (e.g. 4 sub-buffers of 25 elements) so the search domain shrinks by 4×.
Export to an External Device
Three engineering routes are common.
Route A — OPC UA push
From firmware V4.4 the S7-1200 CPU can act as an OPC UA server. Enable the server in the CPU properties → OPC UA → Server, and add DB_Records to the address space. The MES or panel client can subscribe to the array as a structured variable. This route is recommended when the external device is a SCADA host. The companion S7-1200 OPC UA Server Function Manual lists the variable-count and subscription limits per CPU (e.g. 1214C: 2000 nodes, 100 monitored items).
Route B — Data Log to the SIMATIC Memory Card
The Data Log instructions DataLogCreate, DataLogWrite, DataLogClose, and DataLogOpen write a CSV-style file with a 2-byte header and one row per call. The on-card file path is /DataLogs/<name>.csv. Each row can contain up to 253 bytes; the array of UDT, serialised as 44 bytes, fits in a single row. Use this route when the panel needs to display history or when the PC pulls the CSV through the Web Server of the CPU. Web-server based file access is documented in the S7-1200 System Manual, Chapter on Web Server.
Route C — Triggered PUT to a peer CPU or HMI
For a Compact HMI (Comfort Panel) on PROFINET, a single PUT instruction can copy 100×44 = 4400 bytes in one transaction if the peer supports the "Any-Pointer" type. The peer receives the array into a matching DB. Avoid this route for >8000 bytes: split the transfer into multiple PUT calls gated by a state machine.
Memory Sizing
Use the formula Bytes_used = N_records × sizeof(UDT), then add a 10 % reserve for DB block overhead and any padding introduced by the optimised-access compiler. Reference values for a 1214C with firmware V4.4:
| Array size | Bytes (UDT = 44 B) | Work memory | Retain area fit? |
|---|---|---|---|
| 50 records | 2200 | <1 % of 100 KB | Yes, any CPU |
| 100 records | 4400 | <1 % of 100 KB | 1212C+, not 1211C |
| 500 records | 22000 | ~22 % of 100 KB | 1214C with 10 KB retain: NO; use SMC |
| 1000 records | 44000 | ~44 % of 100 KB | 1215C / 1217C only |
If the working set exceeds the retain area, treat the array as transient (non-retentive) and rely on the Data Log file as the long-term store. The Data Log file is appended to the SMC, which can be 4 GB, 12 GB, or 32 GB depending on the card part number; CSV row size × expected rows fits comfortably even on the smallest 4 GB card.
Optimisation Patterns
Pattern 1 — FIFO with two indices
Replace the single WriteIndex with a pair Head and Tail. Head points to the next slot to write, Tail to the next slot to read. This delivers a true FIFO that an external MES can pull record-by-record, instead of a pure ring buffer. The downside is a higher cost per write: every read must also bump the tail, and the SCL write must check that Head <> Tail-1 to avoid overrun.
Pattern 2 — Indexed access by RecordID
Keep the ring buffer but add a parallel Array[0..99] of DINT of RecordID values. The MES can ask for a specific ID and the PLC does a linear scan in ≤100 µs. This is the pattern used by most OPC UA companion specifications for batch reporting.
Pattern 3 — Time-bucketed sub-buffers
Split the 100-slot array into four 25-slot sub-buffers, one per shift. Routing logic inserts the new record into the sub-buffer that matches the current hour. Operators only ever see the current shift's 25 records, but the union of all four sub-buffers spans the 24-hour window.
Pattern 4 — Triggered snapshot on alarm
Configure the S7-1200 to write a snapshot of the entire 100-element array to the Data Log only when an alarm bit is set. The on-card CSV then becomes an alarm-log rather than a continuous stream, and the Web Server can present the latest 20 alarm snapshots directly on the diagnostic pages of the S7-1200.
Verification
-
Online watch: In TIA Portal, open
DB_Recordswith "Monitor all". Trigger 110 consecutive writes; confirm thatWriteIndexwraps from 99 back to 0 and that RecordID continues monotonically. - Power-cycle test: Power off the CPU, restore power, observe that RecordCount survives and the array content is intact (because of the retentive setting on the array). For a 1211C with insufficient retain area, expect the array to be zeroed; verify that the Data Log CSV on the SMC still contains the 110 rows.
-
Search latency: In the
FC_FindByBatchfunction, expose the iteration counter#ion the watch table and confirm that a worst-case miss leaves#i = 99, i.e. a full scan was executed. - OPC UA subscription: From UaExpert or a custom .NET client, subscribe to the array tag and confirm that updates are delivered within the publish interval (default 500 ms).
- Data Log file integrity: Power-cycle the CPU, remove the SMC, open the file in Notepad, confirm row count and field count match expectations.
Troubleshooting Matrix
| Symptom | Likely cause | Remediation |
|---|---|---|
| Records overwrite each other; ID never increments | WriteIndex not advanced, or OB1 calling the FB on every cycle | Gate the FB call on a rising-edge flag, or move it into a cyclic OB30/OB35 with a longer period |
| Array lost on power cycle | Array not marked retentive, or retain area too small for the chosen N | Reduce N, or move long-term storage to the Data Log on the SMC |
| OPC UA client sees array as "unknown type" | UDT not registered with the OPC UA server | In CPU properties → OPC UA → Companion specification, mark the UDT as a known structure; reload |
| Data Log instruction returns status 80A1 (file system error) | SMC not present, write-protected, or not formatted as "Active" | Insert an SMC formatted as the active card; verify in the Web Server → "Service and maintenance" page |
| External partner cannot access array | Optimised block access enabled on DB_Records and the partner uses absolute addressing | Create a non-optimised mirror DB, copy in OB1 with MOVE_BLK, expose the mirror to the partner |
| Search always returns -1 | STRING[16] padded with spaces; compare with = fails on padded STRINGs |
Use EQ_String instruction or right-trim the search key before comparison |
| Record timestamp is 1970-01-01 | CPU clock not synchronised | Enable NTP or set clock from the panel on a periodic trigger |
Standards and Reference Material
Although the S7-1200 does not implement a SQL engine, the relational concepts of primary key (RecordID), indexed column (BatchNo), and row (one array element) map directly onto the array-of-UDT construct. The definitions of these terms on the Oracle database reference, the Microsoft Azure data dictionary, and the AWS database overview confirm that the S7-1200 pattern satisfies the structural definition of a database: an organised collection of structured information stored electronically in a computer system. The implementation, however, is purpose-built for real-time deterministic control and does not need a DBMS overhead.
For deeper background on the underlying storage model, the Wikipedia database entry and the Google Cloud database guide describe the trade-offs between in-memory tables, flat files, and managed RDBMS, which is the same trade-off the S7-1200 resolves by combining the DB array (in-memory table) with the Data Log file (flat file on flash).
FAQ
Does the S7-1200 support a real SQL database like MySQL or SQLite?
No. The CPU runs only the SIMATIC firmware; it cannot host a DBMS. The closest equivalent is a global DB containing an array of a UDT, optionally combined with a Data Log CSV on the SIMATIC Memory Card for long-term persistence. Use an external PC or IPC running WinCC Runtime or an MES if a real RDBMS is required.
What is the maximum number of records I can keep in the array?
It is bounded by the work memory of the CPU. With the 44-byte UDT used in this article, a 1214C (100 KB work memory) can hold approximately 2000 records if the array is non-retentive. The retentive cap is the CPU's retain area: 10 KB on a 1214C, so only about 220 records can be marked retentive. Above that, drop the retentive flag and store records only in the Data Log on the SMC.
Will the data survive a firmware update?
Yes, provided the SMC is the active card and the data blocks are part of the project that is downloaded. A firmware update on an S7-1200 preserves user data on the SMC and the retain area. Backup the project to the SMC before any V4.x to V4.y update to allow a fallback.
Can the panel read the array directly without extra code?
Yes. If the panel is a Siemens Comfort or Unified Comfort panel on PROFINET, bind the HMI tag directly to the array element or to the whole array. For TIA Portal V17 onward, symbolic access allows the panel to consume the UDT array element-by-element, including the DTL timestamp, with no extra PLC code.
How do I move the Data Log CSV to a PC automatically?
Enable the Web Server on the S7-1200, and the data log files on the SMC are browsable under "Data Logs" in the Web Server pages. For automated retrieval, use an FTP client against the S7-1200's FTP server (firmware V4.3 and later) or pull the file via a script on the engineering station using the S7-1200 as an SMB share. The S7-1200 System Manual, Chapter on Web Server, lists the supported file operations and the access rights of the standard user roles.