Overview of S7 Programming Languages
Siemens S7-300 and S7-400 controllers (and the integrated S7-300/400 inside the S7-1500 via legacy support packages) expose four or five IEC 61131-3 languages to the engineer: LAD (Ladder Diagram), FBD (Function Block Diagram), STL (Statement List, sometimes called AWL), SCL (Structured Control Language), and on S7-1500/1200 the addition of GRAPH (sequential function chart) and a refreshed CFC. STL is the only one of these that gives the programmer direct visibility of the accumulator, status word, address register, and RLO flow at the bit level. That visibility is exactly why veteran control engineers reach for STL when the application has dense math, indexed access into a process image, or peer-to-peer data handshakes that have to fit inside a single Profibus DP cycle.
For motion and high-speed process projects, the official Siemens position is that STL remains valid but SCL is the strategic replacement. The trade-off is throughput versus developer ramp-up. STL executes with the lowest interpreter overhead in the S7-300/400 CPU firmware, but it does not scale to large code bases the way SCL does. The recommendation in Siemens entry ID 109751795 is to keep STL inside optimised function blocks (FB) that are called from an SCL or LAD wrapper, so you gain STL's runtime behaviour without losing the readability of the rest of the project.
| Language | CPU Cycles / Statement | Indexed Memory Access | Math Density | Best Use |
|---|---|---|---|---|
| LAD / FBD | ~3-7 μs typical | Indirect only via block interface | Low (limited instruction set) | Boolean logic, simple sequencing |
| STL | ~0.1-0.3 μs typical | Native via AR1/AR2 and DBX | High | Indexed loops, Profibus handshake, motion glue code |
| SCL | Compiler optimised, ~1-4 μs typical | Array index syntax | Very high | Recipes, math, complex state machines |
| GRAPH | ~5-15 μs per step | Not applicable | Low | Sequential processes with discrete steps |
SFC 87 "C_DIAG" or via the diagnostic buffer, do not assume vendor brochure values.STL Statement List Fundamentals
An STL statement operates on one of three classes of operand: accumulators (ACCU1, ACCU2), status bits (RLO, STA, OR, OS, OV, CC0, CC1, BR), and address registers (AR1, AR2). The most common mental model for engineers moving from LAD is to read STL top-to-bottom as if the engineer were narrating the operations verbally: "load, compare, jump, store." STL is not a register machine in the C-language sense, but the accumulator metaphor is close enough that engineers familiar with assembly on x86 or ARM pick it up quickly.
Minimum instruction set needed for productive STL work:
| Operation | STL Mnemonic | Effect |
|---|---|---|
| Load | L |
Push operand into ACCU1, prior ACCU1 moves to ACCU2 |
| Transfer | T |
Copy ACCU1 to operand memory |
| Compare | >I, <I, ==I, <>I |
Sets CC0/CC1, RLO |
| Bit logic | A, O, X, AN, ON, XN |
AND, OR, XOR with RLO |
| Set/Reset | S, R |
Bit-level set/reset, RLO dependent |
| Jump | JU, JC, JCN, JL, LOOP |
Unconditional, conditional, list, decrement-and-jump |
| Block call | CALL, UC, CC |
Conditional/uncalled FB/FC/SFB/SFC |
| DB register | OPN, CDB, DBNO |
Open data block, exchange DI/DI2 |
| Address register | +AR1, +AR2, LAR1, LAR2, TAR1, TAR2 |
Pointer arithmetic |
Minimum STL program skeleton for an FB that increments a counter every cycle:
FUNCTION_BLOCK FB100
VAR
Cnt : INT; // instance memory
END_VAR
BEGIN
L #Cnt; // load current count
L 1; // push constant
+I; // ACCU2 + ACCU1 -> ACCU1
T #Cnt; // store back
L #Cnt;
L 1000; // limit
>I;
JC RESET; // jump if count > limit
BEU; // block end unconditional
RESET: L 0;
T #Cnt;
END_FUNCTION_BLOCK
This skeleton is the basic loop most textbooks use; production code should also handle overflow (OV bit) and use the LIMIT STL instruction for clamp-to-range in one cycle.
Indexed Memory Access with AR1 / AR2
The single biggest productivity jump an engineer gets from STL is indexed access into the process image, the bit memory, or an instance DB. LAD supports this only through block interface variables; STL exposes the AR1 and AR2 registers, plus the DBX/DBW/DBD indirect area-cross-pointer syntax.
There are three flavours of pointer in S7-300/400 STL:
| Pointer Width | Syntax | Range | Use Case |
|---|---|---|---|
| 32-bit area-cross (internal) | P#DB100.DBX0.0 BYTE 20 |
16 MB address space | Cross-DB indexed reads/writes |
| 32-bit area-internal | P#10.0 |
65535 bytes within one area | Loop inside one DB or PI |
| 48-bit DB pointer (legacy S7-200 style) |
DBW 0 as word |
Up to DB 32767 | Only when importing S7-200 migration |
A typical indexed walk through 100 WORD entries in DB200 to find the first non-zero value:
OPN DB200; // open target DB
LAR1 P#0.0; // pointer to first word
L 100; // loop counter
NEXT: T #LoopCnt;
L DBW [AR1,P#0.0]; // area-internal indirect read
<>I;
JC FOUND;
+AR1 P#2.0; // step by 2 bytes (one WORD)
L #LoopCnt;
LOOP NEXT;
L 0;
T #ResultIdx;
BEU;
FOUND: L 100;
L #LoopCnt;
-I;
T #ResultIdx; // 0..99 index
END_FUNCTION_BLOCK
The DBW [AR1,P#0.0] syntax is the heart of area-internal indirect access. The AR1 register holds the base pointer, the constant P#0.0 is the offset (here zero). Adding +AR1 P#2.0 advances the pointer by one WORD per iteration. This syntax is documented in the Siemens STL manual (entry ID 109751806) and is the form most training courses teach.
For area-cross (i.e. switching which DB you read from inside the loop), use the 32-bit area-cross pointer:
OPN DI 200; // open instance DB
LAR1 P#DBX 0.0 BYTE 10; // byte 10 of DB200
L DIW [AR1,P#0.0]; // indirect word read via area-cross pointer
Mixing area-internal with area-cross without reloading AR1 is a common bug source. If AR1 was last set to an area-internal pointer (P#10.0) and the code then executes L DBB [AR1,P#0.0], the S7 CPU still interprets the pointer as a 32-bit area-cross value and reads from DB0 / bit memory 0, which is rarely what the engineer intended. Always normalise AR1 by LAR1 P#DBX 0.0 BYTE 0 at function start if the FB is shared between call sites.
Profibus DP Master-Slave Handshake
Profibus DP (Decentralised Periphery) on S7-300/400 is centred on the DP master interface (CP 342-5, IM 308-C, or the integrated DP port on CPUs such as 315-2DP and 319-3PN/DP). The PROFIBUS Installation Guideline and IEC 61158-6 define the wire protocol; the S7 side is documented in the SIMATIC S7-300 Profibus DP manual (entry ID 109751784).
DP data exchange is a deterministic cyclic polling of slave I/O areas. Each slave is configured with GSD file parameters that declare the input and output lengths. The master writes outputs and reads inputs in a single telegram; with cyclic master-master mode (DX) or with acyclic RD_REC/WR_REC services the application gets parameter channels.
For data longer than one Profibus DP telegram (32 bytes input / 32 bytes output on most DP-V0 slaves), the engineer must implement a multi-telegram handshake. The standard pattern is a token-passing mailbox: the master increments a sequence number, the slave echoes it, and a new telegram is requested only after a matching echo arrives.
| Step | Master Output | Slave Output | Status |
|---|---|---|---|
| Idle | SEQ = 0, REQ = 0 | SEQ = 0, ACK = 0 | No pending transfer |
| Request | SEQ = 1, REQ = 1, payload[N] | SEQ = 0, ACK = 0 | New data sent |
| Acknowledge | SEQ = 1, REQ = 0 | SEQ = 1, ACK = 1 | Slave received |
| Release | SEQ = 0, REQ = 0 | SEQ = 0, ACK = 0 | Cycle complete, ready for next |
STL implementation of the master side of the handshake inside a cyclic OB1:
// Inputs are mapped to PIW and outputs to PQW by HW config
// Assuming output area starts at PQW 256 with 8 words,
// and input area at PIW 256 with 8 words.
NETWORK 1 // Increment SEQ on new data
A M 100.0; // application "new data" flag
AN M 100.1; // handshake busy
JCN NO_REQ;
L MW 110; // current SEQ
L 1;
+I;
T MW 110;
S M 100.1; // set busy
NO_REQ: NOP 0;
NETWORK 2 // Build output telegram
L MW 110; // SEQ
T PQW 256; // word 0 of output area
L DB10.DBW 0; // payload word 0
T PQW 258;
L DB10.DBW 2;
T PQW 260;
// ... up to PQW 270 (8 words total)
NETWORK 3 // Read and verify input telegram
L PIW 256; // SEQ echo from slave
L MW 110;
<>I;
JC TIMEOUT; // SEQ mismatch = error
L PIW 258; // payload word 0
T DB11.DBW 0;
L PIW 260;
T DB11.DBW 2;
// ...
NETWORK 4 // Clear busy on successful echo
AN M 100.2; // application "consumed" flag
R M 100.1;
BEU;
TIMEOUT: S M 100.3; // handshake error latched
R M 100.1;
END
The handshake must be visible from both sides. The slave's firmware (if the slave is a Siemens ET 200S, ET 200M, or third-party DP-V1 slave) returns the SEQ echo automatically if the I/O area is correctly mapped; the engineer's job is to verify the echo every cycle and to time out if no echo arrives within N DP cycles.
OB 82 (diagnostic interrupt) and OB 86 (rack failure) to capture slave loss. Diagnose the slave with SFC 13 "DPRTM" or SFB 52 "RDREC" for DP-V1 extended diagnostics. Wire SFC 13 to the DP slot of the slave; the returned diagnostic buffer tells you whether the error is wire break, configuration mismatch, or slave firmware fault.Motion Controller Integration with S7
Siemens motion controllers - FM 353, FM 354, FM 357-2, and the newer SIMOTION D4x5 series - all support a Profibus DP-V2 slave interface. For DP-V2 the slave is time-synchronous (isochronous mode), which gives the application a deterministic position update rate down to 250 μs, depending on the configured equidistant DP cycle. Configuration steps in SIMOTION SCOUT engineering manual:
- Configure the S7-300/400 as DP master in HW Config, add the SIMOTION slave from the GSD file (Siemens provides
SIM443.---and similar GSDs). - Select isochronous mode on the slave slot; the master OB is then triggered by OB 61-OB 64 (synchronisation cycle).
- Map at least 16 bytes of inputs and 16 bytes of outputs. The SIMOTION standard telegram 105 includes 8 words of position/velocity and 8 words of setpoints.
- In the S7 program, read/write these I/O areas inside OB 61 to align to the isochronous tick.
Sample STL in OB 61 to read position and write target velocity:
NETWORK 1 // Read position from SIMOTION telegram 105
L PIW 320; // word 0, position low
T DB200.DBW 0;
L PIW 322; // word 1, position high
T DB200.DBW 2;
L PID 324; // double word 2, actual velocity
T DB200.DBD 4;
NETWORK 2 // Write target velocity
L DB200.DBD 100; // setpoint from HMI
T PQD 320; // first 4 output bytes
The cross-vendor alternative is to use the SIMOTION "technology object" interface and drive it via Profidrive profile (PROFIdrive V3.0 / V4.0). PROFIdrive is standard in IEC 61800-7 and is documented in the PROFIdrive profile specification. For Profidrive, the engineer writes a control word (STW1) and a speed setpoint (NSOLL) to the slave; the slave returns a status word (ZSW1) and actual speed (NIST).
State machine for PROFIdrive Application Class 1 (velocity mode):
| State | STW1 bit pattern | Action |
|---|---|---|
| S1 Ready to switch on | 0000 0110 | Power electronics ready, no torque |
| S2 Switched on | 0000 0111 | Output stage enabled, no setpoint |
| S3 Operation enabled | 0000 1111 | Drive follows setpoint |
| S4 Quick stop | 0000 1011 | Ramp down with quick-stop ramp |
| S5 Fault | 0000 1111 (with fault bit) | Drive acknowledges fault, ready to reset |
Block Architecture: FB, FC, DB, UDT
The pattern recommended for S7 projects above ~2,000 STL lines is the multi-instance FB architecture. A UDT (User-Defined Type) declares a recurring data structure; an FB uses the UDT as an input, output, or static variable; multiple instances of the FB share the same instance DB.
TYPE UDT_MOTION
STRUCT
SetPos : DINT; // target position in encoder units
ActPos : DINT; // actual position
SetVel : REAL; // target velocity in mm/s
ActVel : REAL;
Enable : BOOL; // drive enable
Fault : BOOL;
SeqNum : INT; // handshake token
END_STRUCT;
END_TYPE
The motion FB then uses the UDT as its static VAR:
FUNCTION_BLOCK FB200
VAR
State : UDT_MOTION; // instance-local copy
END_VAR
Calling 50 motion axes from OB1 in a machine with 50 axes consumes one DB block per call site (DB200, DB201, ... DB249) only if the engineer uses single-instance FB calls. Multi-instance means a single DB250 holds 50 copies of the UDT, accessed via the "FB200".State.SetPos[Idx] notation in SCL, or via DBX arithmetic in STL.
Indirect Addressing in Function Blocks
A frequent real-world requirement is to read 16 measurement channels from a third-party Profibus slave into an instance DB. STL implementation with the area-internal pointer:
FUNCTION_BLOCK FB300
VAR_INPUT
StartIdx : INT;
EndIdx : INT;
END_VAR
VAR
Idx : INT;
END_VAR
BEGIN
OPN DB300; // data destination
L #StartIdx;
ITD; // INT to DINT for pointer math
SLD 3; // multiply by 8 bits = 1 byte
+AR1 // add to existing AR1? use LAR1 instead
// Correct pattern:
LAR1 P#0.0;
L #StartIdx;
ITD;
SLD 3; // byte offset
+AR1; // AR1 = base + offset
L #EndIdx;
L #StartIdx;
-I;
LOOP NEXT;
BEU;
NEXT: T #Idx;
L PIW [AR1,P#0.0]; // read PIW at offset
T DBW [AR1,P#0.0]; // write to DB300
L #Idx;
LOOP NEXT; // decrement ACCU1, jump if not zero
END_FUNCTION_BLOCK
The SLD 3 instruction is the bit-shift trick to convert an INT index to a byte pointer (each INT shift left by 1 = byte boundary; shift left by 3 = byte boundary × 2 = word boundary × 4 ...). For DOUBLE word access, SLD 5.
Error Handling and Diagnostics
STL gives direct access to the status word bits, which the application should monitor for division by zero (OV), illegal floating-point (OS), or accumulator overflow (UO from ==R). Wrap critical math in:
NETWORK 1 // divide with overflow capture
L DB10.DBD 0; // numerator
L DB10.DBD 4; // denominator
SRD 1; // shift to position divisor
/R; // floating divide
T DB10.DBD 8; // result
UN OV; // no overflow?
SPB OK;
L 0.0;
T DB10.DBD 8;
S DB10.DBX 12.0; // set "div error" flag
SPA CONTINUE;
OK: R DB10.DBX 12.0;
CONTINUE: NOP 0;
The diagnostic buffer of the S7 CPU (read with SFC 51 "RDSYSST" with SSL_ID W#16#0131 / W#16#0F31) lists the last 50 events with timestamp and event ID. Engineers integrating Profibus should poll this buffer in OB 82/OB 86 so that a slave going offline at 03:42:15 produces a time-stamped alarm in WinCC instead of an unexplained loss of view.
Best Practices Summary
- Keep STL inside FBs that have a single responsibility. The compiler optimises better and the reviewer can audit the math.
- Always reset AR1 at function start with
LAR1 P#DBX 0.0 BYTE 0if the FB is shared between call sites with different data blocks. - Use multi-instance DBs for repetitive structures (axes, channels, drives). One large DB is easier to back up than 50 small ones.
- Use the area-internal 32-bit pointer (
P#x.y) for loops inside a single area; use the area-cross pointer (P#DBx.DBX y.z BYTE n) only when switching DBs mid-function. - Implement a SEQ-ACK handshake for any Profibus DP payload longer than 32 bytes; never trust that two consecutive cycles of identical data mean the slave has read the new value.
- Monitor the status word (
OV,OS,UO) around every floating-point instruction; one missed check cascades into a corrupt recipe. - Time out Profibus handshakes after 5-10 DP cycles (configurable). A slave that drops off the bus mid-transfer otherwise leaves the master waiting forever.
- Use isochronous mode (OB 61-OB 64) for motion control. Cyclic OB1 jitter is too high for precision positioning; the isochronous interrupt is locked to the DP cycle start.
- Read the diagnostic buffer in OB 82/OB 86 with
SFC 51; surface the events in WinCC so the operator sees the cause, not just the symptom. - Document the STL blocks with the
TITLE =andAUTHOR =block attributes; the comment is uploaded to the CPU and visible in the online view.
Verification Procedure
After loading STL into the S7 CPU, perform the following checks before sign-off:
- Open the program in STEP 7 and verify the block consistency. Options > Block Consistency should report zero errors.
- Online: go to the FB in question and watch the STL with monitor on. Check that the accumulator and status word bits transition as expected when you toggle inputs.
- Single-scan: use
CRTL+F8orPLC > Monitor/Modify > Single Scanto step one cycle at a time. Verify thatAR1after the loop is the expected value, not an orphan pointer. - Force a Profibus slave to power-cycle. Watch the diagnostic buffer for OB 86 entry with the correct slot number and rack number.
- Trigger an OB 1 cycle overrun (add a long loop). Verify the CPU enters STOP with diagnostic event "OB1 cycle time exceeded" and the correct event ID.
- Back up the S7 project with
Archiveand verify the archive opens cleanly on a second engineering station.
FAQ
What is the difference between AR1 and AR2 in S7 STL?
AR1 is the primary address register, used for all indirect addressing via DBX [AR1,P#0.0] and similar syntax. AR2 is the secondary register, used by the system for some block calls and available to the application for parallel addressing operations. Most engineers use AR1 only and treat AR2 as reserved for the compiler.
Can STL call an SCL block or vice versa?
Yes. STL can call any FB, FC, SFB, or SFC regardless of the language it is written in. The block interface (VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR_TEMP) is language-neutral. The only restriction is that multi-instance variables declared inside an SCL FB cannot be used as the target of indirect STL writes without a static interface variable.
How do I migrate an S7-200 STL project to S7-300/400 or S7-1500?
Use the S7-200 migration tool in STEP 7 V5.x to convert the 200-STL to S7-300/400 STL, then re-test every block. The pointer format changes from 48-bit S7-200 to 32-bit area-cross S7-300, and the absolute address ranges expand. Direct migration to S7-1500 is not supported; use a re-implementation in SCL for portability.
Why does my Profibus DP handshake stall after the first telegram?
Most often the slave's input/output lengths are misconfigured in HW Config, so the slave's echoed SEQ is read from a different word offset than the master wrote. Verify the slot configuration with SFC 13 "DPRTM" or by looking at the DP slave diagnostic buffer. The second most common cause is a CRC or parity error on the segment; check the repeater LEDs and the segment terminator.
Is STL still supported on S7-1500?
STL is not a first-class language in TIA Portal for S7-1500; LAD, FBD, SCL, and GRAPH are the four supported. STL is supported only on S7-300/400 within TIA Portal via legacy blocks. For new development on S7-1500, use SCL for procedural code and GRAPH for sequential processes. For motion control on SIMOTION, SCL with the technology object library is the strategic path.