Problem Overview
The symptom is a runtime String processing error raised by an S7-1200 CPU 1214C (firmware 4.1) when a user attempts to copy one SCL STRING variable to another. The naïve assignment
String2 := String1;
with both tags declared at a length of 20 bytes consistently faults. The same fault occurs with
String2 := LEFT(IN := String1, L := 20);
where String2 remains empty on every scan. The defect is observable on TIA Portal V13 SP1 Update 9 with the matching S7-1200 system image; it is not a CPU hardware failure and is recoverable with corrected SCL syntax and tag declarations.
Affected Versions and Tooling
| Component | Version Confirmed | Notes |
|---|---|---|
| STEP 7 / TIA Portal | V13 SP1 Update 9 | Project engineering environment |
| S7-1200 CPU | CPU 1214C DC/DC/DC and DC/DC/RLY | Tested hardware |
| CPU Firmware | FW 4.1 | Released with TIA V13 SP1; ships with STRING 254-byte maximum |
| Programming Language | SCL (Structured Control Language) | Issue is syntax/declaration driven, not STL or LAD |
| String Length Tested | 20 bytes | Inside 0..254 byte range |
Firmware 4.x on the S7-1200 line is the first generation to include the optimized block interface and full STRING support. The error presents regardless of whether the optimized block attribute is enabled or disabled, but the declaration location of the variables (local temp, local static, or global DB) is the controlling factor.
Root Cause Analysis
The String processing error on the S7-1200 is the runtime diagnostic emitted when the firmware detects an inconsistency in the STRING header. Every S7 STRING is a compound of two header words followed by a character array:
- Word 0 (Bytes 0..1): Maximum length in characters (e.g. 254)
- Word 2 (Bytes 2..3): Current (actual) length in characters
- Bytes 4..257: Character payload (ASCII)
An SCL assignment A := B for STRING types is valid only when both operands are fully qualified, declared symbols with the same maximum length. Three conditions each independently trigger the fault observed in the report:
-
Unqualified tag references. The bare names
String1andString2are not resolvable as global symbols; the SCL compiler will accept them only as local tags (with the#prefix in TIA V13 onward) or as fully qualified DB members (with the"DB_name".prefix). -
Uninitialized temporary strings. If the destination
String2is a TEMP variable, the STRING header on entry to the block contains whatever pattern is on the stack. The runtime checkactual_length <= max_lengthfails and the CPU raisesString processing errorbefore the assignment proceeds. -
Length-mismatch propagation from
LEFT. TheLEFTstandard function returns a STRING whose actual length is set to theLinput; if the receiving variable has a smaller maximum length than the caller's expected, the same header check trips.LEFTreturning an empty string in the field report indicates the destination was never written — the fault was raised and execution aborted before the copy.
# or DB-qualifier that worked in V11/V12 will compile but fail at download or in the first scan on V13+ targets. Always re-validate legacy SCL blocks after a TIA upgrade.
String Data Type Specification (S7-1200)
| Property | Value |
|---|---|
| Keyword |
STRING[ n ] where 0 ≤ n ≤ 254
|
| Total memory footprint | n + 2 bytes for header + 2 bytes for max length = n + 4 bytes |
| Default initialization (in DB) | Empty string (actual length = 0, all character bytes = 16#00) |
| Default initialization (TEMP, STATIC) | Undefined — must be initialized explicitly |
| Wide character variant |
WSTRING — UCS-2, header = 4 + 2*length bytes |
| Access via AT view | Yes; declare AT overlay on a byte array of size n+4 |
For the 20-byte strings in the source report, each instance occupies 24 bytes (2 bytes max + 2 bytes current + 20 bytes payload). All SCL STRING operators — :=, LEFT, RIGHT, MID, CONCAT, DELETE, INSERT, REPLACE, FIND, LEN — read and rewrite the 4-byte header. Any operator invoked on an uninitialized TEMP string can fault.
Fix 1 — Use Fully Qualified DB Tag Names
Declare both strings as global symbols inside a global data block. This is the recommended pattern for cross-block or HMI-visible strings on S7-1200.
- Open the project tree in TIA Portal and add a new Data Block (DB), e.g.
Data_block_10. - Inside
Data_block_10add two static tags:String1 : STRING[20]; // 24 bytes total String2 : STRING[20]; // 24 bytes total - Disable the Optimized block access attribute on the DB if any external (non-S7-1200) client accesses the absolute addresses — otherwise leave it enabled, the STRING operator set is identical.
- In the SCL source, write the assignment with the full DB qualifier:
"Data_block_10".String2 := "Data_block_10".String1; - Compile (Ctrl+B) and download. The PLC should now copy the entire 20-character payload in one scan without raising the error.
If the SCL block does not accept the literal "Data_block_10" it means the DB has not been added to the block's interface. Right-click the block in the project tree → Properties → Interfaces and confirm the DB appears under Used Blocks, or use a multi-instance call where the DB is the instance itself.
Fix 2 — Local Tags in a Function (FC) or Function Block (FB)
When both strings live inside a single SCL block, the correct SCL syntax uses the # prefix introduced in TIA V11 and tightened in V13 SP1:
FUNCTION_BLOCK "FB_String_Copy"
VAR
String1 : STRING[20]; // STATIC — retained between scans
String2 : STRING[20]; // STATIC
END_VAR
BEGIN
#String2 := #String1;
END_FUNCTION_BLOCK
Rules for the # prefix:
-
#is required for all block-local tags (TEMP, STATIC, CONSTANT, IN, OUT, IN_OUT) inside the interface. -
#is forbidden for global DB members — use"DB_name".Memberinstead. - Constants are read with the literal, e.g.
String2 := 'X';for a 1-char string.
String1 and a global tag of the same name. Rename one of them to avoid the warning, which can mask the runtime fault if disabled.
Fix 3 — Initialize Temporary Strings First
The original post's recommendation to write string2 := 'X'; before the bulk copy is a valid workaround for TEMP variables. The full pattern:
FUNCTION "FC_String_Copy" : Void
VAR_TEMP
String1 : STRING[20];
String2 : STRING[20];
END_VAR
BEGIN
// Initialize headers to prevent undefined-length faults
#String1 := ''; // max=20, actual=0, payload cleared
#String2 := '';
#String1 := 'Hello S7-1200!';
#String2 := #String1; // safe copy
END_FUNCTION
The empty-string literal '' sets the current length to 0 and zeroes the character array. After that, any subsequent SCL string operator sees a consistent header and the firmware will not raise String processing error.
Fix 4 — Correct Use of the LEFT Standard Function
LEFT returns a STRING. To capture the result, the destination tag must be large enough to hold the requested length, and the call must use a fully qualified source:
"Data_block_10".String2 := LEFT(
IN := "Data_block_10".String1,
L := 20
);
Common pitfalls:
-
Llarger thanIN— returns the entire string, no error. -
L= 0 — returns an empty string; destination remains unchanged (a common reasonString2"stays empty" in the field report whenLwas inadvertently set to 0). - Mixing
STRINGandWSTRING— SCL will not implicitly convert; use theSTRING_TO_WSTRINGandWSTRING_TO_STRINGconverters in the CONVERT block group.
Alternative Copy Methods
| Method | SCL Statement | Use When |
|---|---|---|
| Direct assignment | #dst := #src; |
Same block, both fully qualified. |
| DB-to-DB assignment | "DB_A".s2 := "DB_B".s1; |
Cross-block copy, same max length. |
| Slice via AT view | #dst AT view of ARRAY OF BYTE := #src AT view of ARRAY OF BYTE; |
Bulk-byte copy; bypasses header checks — only for advanced users. |
| Concat trick | #dst := CONCAT(IN1 := '', IN2 := #src); |
Forces header rewrite; helpful when header is suspected corrupt. |
MOVE_BLK |
Use the MOVE (DWORD) or BLKMOV (SFC 20) on the full 24 bytes | Performance-critical loops; not type-safe. |
IEC standard STRING_TO_... converters |
#dst := STRING_TO_CHAR(IN := #src); |
Legacy compatibility for non-SCL blocks. |
The CONCAT with empty string trick is worth keeping in the toolbox: it explicitly writes a fresh header (max length = 254 by default, but constrained by destination) and is a one-line sanity test when chasing header corruption on legacy projects.
Runtime Error Codes and Diagnostics
| Diagnostic Buffer Entry | Meaning | Likely Cause |
|---|---|---|
| String processing error (no detailed code) | Header inconsistency | Uninitialized TEMP string; max length of source > max length of destination; or operator on a constant. |
| Area length error when reading | Source outside valid memory | String tag points to a deleted DB; check Cross-references in TIA. |
| Area length error when writing | Destination too small | Source has actual length > destination max length; resize destination or truncate with LEFT. |
| OB not loaded / OB 121 raised | CPU tried to call a non-existent error OB | Programming error OB not present; CPU goes to STOP. |
The S7-1200 firmware will only invoke the user's Programming error OB (OB 121) if it has been generated and downloaded. Without OB 121, the CPU transitions to STOP on the first String processing error and writes the diagnostic event "String processing error in FC/FB n, area: ..." to the diagnostic buffer.
Verification Procedure
- Online → Go online with the CPU; confirm the active program matches the compiled project (no download differences in the Compare editor).
- Open the watch table that contains the source and destination strings; force the source to a known value, e.g.
'TEST_1234567890ABCDE'. - Trigger the SCL block once (set EN input or call via cyclic task). Confirm the destination reflects the source byte-for-byte, including the actual length in the Monitor value pane.
- Inspect Online & diagnostics → Diagnostics buffer; there should be no String processing error entries after the corrected code is in place.
- Repeat the watch-table test with the SCL editor in monitor mode, then set a breakpoint on the assignment line; verify the assignment executes without the LED pattern indicating a STOP transition (STOP/RUN LED solid green during the test).
- Cycle power to the CPU; if the strings are STATIC or DB-global, values persist; if they are TEMP, they reset to empty after the next cold restart, which is expected.
Common Pitfalls and Field Tips
-
Mixing STRING and WSTRING. WSTRING is 16-bit UCS-2; assignments between the two require explicit conversion. The SCL compiler will reject implicit conversion with a type-mismatch error, but a runtime
String processing errorcan occur if the conversion is attempted viaCHAR_TO_...with insufficient buffer. - Watch the second header word. If a string's actual length ever exceeds its max length, every subsequent operator faults. Use the Monitor pane to display both header words when debugging legacy code.
- HMI aliasing. An HMI tag pointing at a STRING DB member with a length override larger than the DB's max length will write past the end of the DB; the SCL block then reads a corrupt header on the next scan.
- Retentivity. TIA V13 SP1 honors the Retain attribute for STRING variables. A retained string survives a warm restart but its actual length is part of the retained image — verify that the destination DB's retentivity settings match between HMI, PLC, and the loaded project.
- Compiler version drift. A block compiled in TIA V13 SP1 is forward-compatible to V14/V15 but the V13 STRING operator set is more limited; if copying logic is added later, re-compile under the current TIA version.
Troubleshooting Matrix
| Symptom | Likely Cause | First Action |
|---|---|---|
| CPU goes to STOP, String processing error in buffer | Uninitialized TEMP or length mismatch | Initialize with #s := '';; verify max lengths equal |
Destination stays empty after LEFT call |
L = 0 or uninitialized source |
Inspect L value in watch table; check source actual length |
| Compiler error Unknown identifier 'String1' | Bare name without # or DB prefix |
Add # for local or "DB_name". for global |
| Compiler accepts, runtime faults only on first cycle | TEMP not initialized | Use STATIC instead, or pre-assign empty string |
| Watch table shows wrong character count | Header corruption from a previous, larger write | Re-initialize the string in OB100 / startup |
Reference Links
- Siemens Industry Online Support — S7-1200 portal
- S7-1200 Programmable Controller — System Manual (entry ID 109751706)
- STEP 7 (TIA Portal) SCL programming manual (entry ID 81318674)
- .NET String.Copy(String) — Microsoft Learn
FAQ
Why does my S7-1200 raise "String processing error" on a simple SCL assignment?
The fault is raised when the STRING header (max length + actual length + payload) is inconsistent. The most common cause on TIA V13 SP1 is an uninitialized temporary string or a bare-name tag reference that the compiler cannot resolve. Initialize the destination with #s := ''; and qualify the source with # or "DB_name"..
Do I have to use the # prefix for local variables in TIA Portal V13 SP1?
Yes. TIA V11 introduced the # prefix for block-local symbols and TIA V13 SP1 tightened the check. Omitting the prefix for a TEMP or STATIC tag will compile with a warning on legacy firmware but the runtime may STOP on firmware 4.x. Use #tagname inside FCs/FBs and "DB_name".tagname for global DB members.
Why does LEFT leave my destination string empty?
LEFT returns a STRING with the actual length set to the L input. If L is 0, the result is an empty string and the destination is effectively cleared. Verify L in the watch table and ensure the destination is a fully qualified symbol with a max length ≥ L.
Can I mix STRING and WSTRING in the same assignment?
No. SCL does not implicitly convert between 8-bit STRING and 16-bit WSTRING. Use the standard converters STRING_TO_WSTRING and WSTRING_TO_STRING from the CONVERT library, and ensure the destination has sufficient capacity for the wider encoding.
What is the maximum STRING length on a CPU 1214C firmware 4.1?
254 characters. Each STRING[n] occupies n + 4 bytes of memory. For the 20-byte strings in this case report, each instance is 24 bytes. Firmware 4.1 supports STRING and WSTRING with the same operator set used in TIA V13 SP1.