Siemens standard telegram logic is the PLC code that packs commands into the control word STW1, sends a speed setpoint scaled so 16#4000 = 100 % of p2000, and unpacks the drive's status word ZSW1 and actual values. The drive starts on 16#047E then 16#047F, stops on 16#047E, and acknowledges faults with a rising edge on bit 7 (16#04FE). Every block for Telegram 1, Telegram 20 and free telegram 999 is below as copy-paste SCL and DB source.
- Bits 1, 2, 3, 4, 5, 6 and 10 of STW1 are held at 1; only ON (bit 0) and acknowledge (bit 7) change in normal running.
- OFF2 and OFF3 are active-low: a 0 stops the drive, so a broken signal fails safe.
- Read “running” from ZSW1 bit 2, never from your own Run command.
- Every scaled value is a percentage of a drive reference parameter; match p2000, p2002, p2003 and r2004 in the PLC.
Try it first: the Live PLC–VFD Simulator runs the same control and status words.
What Standard Telegram Logic Means
A PROFIdrive standard telegram is a fixed list of 16-bit process data words (PZD) that the PLC and the SINAMICS drive exchange every PROFINET cycle. The telegram itself only moves the words; the logic is what your PLC program does with them: build the control word from machine commands, convert rpm into a drive percentage, and turn the status word back into Ready, Running, Fault and actual speed.
The same logic serves every telegram on this page. Telegram 1 (PZD-2/2) carries control word and speed; Telegram 20 (PZD-2/6) adds current, torque, power and a fault word; free telegram 999 (PZD-8/8 or 16/16) keeps the first two words and lets you choose the rest.
| Telegram | PLC → drive | Drive → PLC | Drive setting |
|---|---|---|---|
Standard 1 PZD-2/2 | STW1, NSOLL_A | ZSW1, NIST_A | p0922 = 1 |
Standard 20 PZD-2/6 | STW1, NSOLL_A | ZSW1, NIST_A, current, torque, power, NAMUR word | p0922 = 20 |
Free 999 PZD-8/8 | STW1, speed + 6 free | ZSW1, speed + 6 free | p0922 = 999 |
Free 999 PZD-16/16 | STW1, speed + 14 free | ZSW1, speed + 14 free | p0922 = 999 |
Animated Telegram Flow
Pick a telegram to see its words move between PLC and drive. The lower panel replays the start-up logic that every block on this page follows.
16#00000 rpmPower up: ZSW1 bit 6 “switching on inhibited” is set.
Control Word Logic (STW1)
STW1 is identical in Telegram 1, 20 and the free telegram. The logic has three kinds of bit: commands you switch (ON, acknowledge, reverse), active-low stops that must stay 1 to run (OFF2, OFF3), and enables held at 1 permanently.
| Bit | Signal | Logic in the FB |
|---|---|---|
| 0 | ON / OFF1 | Run AND NOT AckFault AND NOT SwitchOnInhibit |
| 1 | No OFF2 (coast stop) | NOT CoastStop — 0 removes pulses, motor coasts |
| 2 | No OFF3 (quick stop) | NOT QuickStop — 0 stops on the fast ramp p1135 |
| 3 | Enable operation | Held TRUE |
| 4 | Enable ramp-function generator | Held TRUE |
| 5 | Continue ramp-function generator | Held TRUE |
| 6 | Enable speed setpoint | Held TRUE |
| 7 | Acknowledge fault | AckFault — acts on the 0 → 1 edge |
| 10 | Control by PLC | Held TRUE — without it the drive ignores the telegram |
| 8, 9, 11–15 | Drive-specific | Left 0; reverse is done with a negative setpoint instead |
Try it: STW1 logic builder
Tick bits to build a control word, or load one of the values the FB sends.
STW1 = 16#0000
Status Word Logic (ZSW1)
ZSW1 is the drive's answer. The FB copies each useful bit to a named BOOL output, so the rest of your program and the HMI never deal with bit numbers.
| Bit | Meaning when 1 | FB output |
|---|---|---|
| 0 | Ready to switch on | ReadyToSwitchOn |
| 1 | Ready for operation | Ready |
| 2 | Operation enabled (running) | Running |
| 3 | Fault present | Fault |
| 4 / 5 | OFF2 / OFF3 not active | — |
| 6 | Switching on inhibited | SwitchOnInhibit |
| 7 | Alarm (warning) present | Alarm |
| 8 | Speed setpoint and actual within tolerance | AtSetpoint |
| 9 | Control requested from PLC | — |
| 10–15 | Comparison value reached, limits, brake, temperature, direction, overload (drive-specific) | Read from ZSW1 word |
Try it: ZSW1 decoder
Start-Up State Logic: 16#047E to 16#047F
The drive follows the PROFIdrive state machine, so the order of control words matters. Sending 16#047F straight after power-up leaves the drive in “switching on inhibited”. The FB solves this in one line: ON is held at 0 while ZSW1 bit 6 is set, so the drive always sees 16#047E first.
| Step | PLC sends STW1 | Drive reports in ZSW1 |
|---|---|---|
| 1. Power up | 16#047E (ON forced to 0) | Bit 6 switching on inhibited |
| 2. Ready | 16#047E | Bit 0 ready to switch on |
| 3. Run | 16#047F + speed setpoint | Bits 1 and 2, motor ramps up |
| 4. Stop (OFF1) | 16#047E | Bit 2 drops after the ramp-down |
| 5. Fault | — | Bit 3 fault present |
| 6. Acknowledge | 16#04FE for one scan, then 16#047E | Bit 3 clears, back to step 1 or 2 |
Test Each Telegram: Animated Test Bench
Choose a telegram and drive it like the PLC would. The bench runs the same STW1 logic as the FBs below, a simulated G120 answers through ZSW1 and the actual-value words, and the checklist ticks off each test as the drive passes it. Press Run automatic test to watch the full sequence play by itself.
Power up: the drive reports “switching on inhibited”. The FB holds STW1 at 16#047E until it clears.
Speed and Actual-Value Scaling Logic
The drive does not understand rpm. Every analog word is a signed percentage where 16#4000 (16384) is 100 % of a reference parameter in the drive.
// Speed setpoint (Telegram 1, 20, free word 2)
NSOLL_A = Speed_rpm / p2000 * 16384 // 16#4000 = 100 %
// Actual values back from the drive
Speed_rpm = NIST_A / 16384 * p2000
Current_A = IAIST / 16384 * p2002 // Telegram 20, word 3
Torque_Nm = MIST / 16384 * p2003 // Telegram 20, word 4
Power_kW = PIST / 16384 * r2004 // Telegram 20, word 5
// Limits: -32768 .. +32767 = about -200 % .. +200 % of the referenceWorked example: p2000 = 1500 rpm, setpoint 750 rpm → 750 / 1500 × 16384 = 8192 = 16#2000. If the drive returns NIST_A = 16#2000, the FB shows 750.0 rpm. A negative value runs the motor in reverse, which is how the FB's Reverse input works.
Copy-Paste Code: Separate .scl and .db Package for Each Telegram
Each telegram has its own package of three source files, so you can download, import and test one telegram on its own without touching the others. Every package uses unique block names (DB_Tel1_HMI, DB_Tel20_HMI, DB_Free8_HMI, DB_Free16_HMI and so on), so two or more packages can also live in the same PLC.
Telegram 1 (PZD-2/2) package
p0922 = 1 · 3 source files · blocks FB_G120_Tel1_PZD2x2, DB_Tel1_HMI, IDB_Tel1_Drv01, FC_Tel1_Call
FB_G120_Tel1_PZD2x2.sclfunction blockDB_Tel1_PZD2x2.dbHMI DB + instance DBFC_Tel1_Call.sclcall FC, then"FC_Tel1_Call"();in OB1
Step 1 · Function block
FUNCTION_BLOCK "FB_G120_Tel1_PZD2x2"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - SINAMICS G120, Standard Telegram 1 (PZD-2/2)
//PLC -> Drive : PZD1 STW1, PZD2 NSOLL_A (16#4000 = 100 % of p2000)
//Drive -> PLC : PZD1 ZSW1, PZD2 NIST_A_GLATT
//Drive setting : p0922 = 1
VAR_INPUT
Run : Bool; // TRUE = run (STW1.0 ON / OFF1)
Reverse : Bool; // TRUE = negative speed setpoint
AckFault : Bool; // pulse TRUE to acknowledge a fault (STW1.7)
CoastStop : Bool; // TRUE = OFF2, pulses off, motor coasts
QuickStop : Bool; // TRUE = OFF3, fast ramp stop (p1135)
SpeedSP_rpm : Real; // speed setpoint in rpm (positive)
RefSpeed_rpm : Real := 1500.0; // MUST equal drive p2000
HW_ID : HW_IO; // hardware ID of the telegram (system constant)
END_VAR
VAR_OUTPUT
ReadyToSwitchOn : Bool; // ZSW1.0
Ready : Bool; // ZSW1.1
Running : Bool; // ZSW1.2 operation enabled
Fault : Bool; // ZSW1.3
SwitchOnInhibit : Bool; // ZSW1.6
Alarm : Bool; // ZSW1.7
AtSetpoint : Bool; // ZSW1.8
ActSpeed_rpm : Real; // actual speed in rpm
STW1 : Word; // control word sent (for watch table)
ZSW1 : Word; // status word received (for watch table)
CommError : Bool; // TRUE = DPRD_DAT / DPWR_DAT error
RdStatus : Int; // 0 = read OK
WrStatus : Int; // 0 = write OK
END_VAR
VAR
Tx : Array[1..2] of Word; // PZD1..2 to drive
Rx : Array[1..2] of Word; // PZD1..2 from drive
END_VAR
VAR_TEMP
tStw1 : Word;
tSp : LReal;
END_VAR
BEGIN
// 1. Read the complete telegram from the drive (consistent)
#RdStatus := DPRD_DAT(LADDR := #HW_ID, RECORD => #Rx);
#ZSW1 := #Rx[1];
// 2. Decode status word ZSW1
#ReadyToSwitchOn := #ZSW1.%X0;
#Ready := #ZSW1.%X1;
#Running := #ZSW1.%X2;
#Fault := #ZSW1.%X3;
#SwitchOnInhibit := #ZSW1.%X6;
#Alarm := #ZSW1.%X7;
#AtSetpoint := #ZSW1.%X8;
// 3. Build control word STW1 (base 16#047E, ON adds bit 0 = 16#047F)
// ON is held at 0 while "switching on inhibited" so the drive always
// passes through 16#047E first, even if Run is already TRUE at power-up.
#tStw1 := 16#0000;
#tStw1.%X0 := #Run AND NOT #AckFault AND NOT #SwitchOnInhibit; // ON / OFF1
#tStw1.%X1 := NOT #CoastStop; // OFF2 (active low)
#tStw1.%X2 := NOT #QuickStop; // OFF3 (active low)
#tStw1.%X3 := TRUE; // enable operation
#tStw1.%X4 := TRUE; // enable ramp-function generator
#tStw1.%X5 := TRUE; // continue ramp-function generator
#tStw1.%X6 := TRUE; // enable speed setpoint
#tStw1.%X7 := #AckFault; // acknowledge on rising edge
#tStw1.%X10 := TRUE; // control by PLC
#STW1 := #tStw1;
#Tx[1] := #tStw1;
// 4. Speed setpoint: rpm -> NSOLL_A (16#4000 = 16384 = 100 % of p2000)
IF #RefSpeed_rpm > 0.0 THEN
#tSp := REAL_TO_LREAL(#SpeedSP_rpm) / REAL_TO_LREAL(#RefSpeed_rpm) * 16384.0;
IF #Reverse THEN
#tSp := -#tSp;
END_IF;
#tSp := LIMIT(MN := -32767.0, IN := #tSp, MX := 32767.0);
#Tx[2] := INT_TO_WORD(LREAL_TO_INT(#tSp));
// 5. Actual speed: NIST_A -> rpm
#ActSpeed_rpm := INT_TO_REAL(WORD_TO_INT(#Rx[2])) / 16384.0 * #RefSpeed_rpm;
ELSE
#Tx[2] := 16#0000;
#ActSpeed_rpm := 0.0;
END_IF;
// 6. Write the complete telegram to the drive (consistent)
#WrStatus := DPWR_DAT(LADDR := #HW_ID, RECORD := #Tx);
#CommError := (#RdStatus <> 0) OR (#WrStatus <> 0);
END_FUNCTION_BLOCKStep 2 · Data blocks
DATA_BLOCK "DB_Tel1_HMI"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
//Softwell Automation - HMI command / status DB, Telegram 1 (PZD-2/2)
//Generate "FB_G120_Tel1_PZD2x2" from its .scl source BEFORE this file.
//Edit Ref_rpm (= p2000) and the other reference values to match the drive.
VAR
Drv01 : Struct // Telegram 1 (PZD-2/2)
Cmd_Run : Bool;
Cmd_Reverse : Bool;
Cmd_Ack : Bool;
Cmd_Coast : Bool;
Cmd_QuickStop : Bool;
SP_rpm : Real;
Ref_rpm : Real := 1500.0; // = p2000
Sts_Ready : Bool;
Sts_Running : Bool;
Sts_Fault : Bool;
Sts_Alarm : Bool;
Sts_CommError : Bool;
Act_rpm : Real;
STW1 : Word;
ZSW1 : Word;
END_STRUCT;
END_VAR
BEGIN
END_DATA_BLOCK
DATA_BLOCK "IDB_Tel1_Drv01"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
"FB_G120_Tel1_PZD2x2"
BEGIN
END_DATA_BLOCKStep 3 · Call function
FUNCTION "FC_Tel1_Call" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - calls drive 01 on Telegram 1 (PZD-2/2).
//Generate order: FB_G120_Tel1_PZD2x2.scl, then DB_Tel1_PZD2x2.db, then this file.
//Call this FC from OB1: "FC_Tel1_Call"();
//HW_ID: replace 269 with the hardware identifier of the telegram
//(Device view > telegram row > Properties > System constants), or drag the
//system constant (e.g. "Drive_1~...telegram...") onto the pin.
BEGIN
"IDB_Tel1_Drv01"(Run := "DB_Tel1_HMI".Drv01.Cmd_Run,
Reverse := "DB_Tel1_HMI".Drv01.Cmd_Reverse,
AckFault := "DB_Tel1_HMI".Drv01.Cmd_Ack,
CoastStop := "DB_Tel1_HMI".Drv01.Cmd_Coast,
QuickStop := "DB_Tel1_HMI".Drv01.Cmd_QuickStop,
SpeedSP_rpm := "DB_Tel1_HMI".Drv01.SP_rpm,
RefSpeed_rpm := "DB_Tel1_HMI".Drv01.Ref_rpm,
HW_ID := 269,
Ready => "DB_Tel1_HMI".Drv01.Sts_Ready,
Running => "DB_Tel1_HMI".Drv01.Sts_Running,
Fault => "DB_Tel1_HMI".Drv01.Sts_Fault,
Alarm => "DB_Tel1_HMI".Drv01.Sts_Alarm,
ActSpeed_rpm => "DB_Tel1_HMI".Drv01.Act_rpm,
STW1 => "DB_Tel1_HMI".Drv01.STW1,
ZSW1 => "DB_Tel1_HMI".Drv01.ZSW1,
CommError => "DB_Tel1_HMI".Drv01.Sts_CommError);
END_FUNCTIONTelegram 20 (PZD-2/6) package
p0922 = 20 · 3 source files · blocks FB_G120_Tel20_PZD2x6, DB_Tel20_HMI, IDB_Tel20_Drv01, FC_Tel20_Call
FB_G120_Tel20_PZD2x6.sclfunction blockDB_Tel20_PZD2x6.dbHMI DB + instance DBFC_Tel20_Call.sclcall FC, then"FC_Tel20_Call"();in OB1
Step 1 · Function block
FUNCTION_BLOCK "FB_G120_Tel20_PZD2x6"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - SINAMICS G120, Standard Telegram 20 (PZD-2/6)
//PLC -> Drive : PZD1 STW1, PZD2 NSOLL_A
//Drive -> PLC : PZD1 ZSW1, PZD2 NIST_A_GLATT, PZD3 IAIST_GLATT (current),
// PZD4 MIST_GLATT (torque), PZD5 PIST_GLATT (power), PZD6 MELD_NAMUR
//Scaling : 16#4000 = 100 % of p2000 / p2002 / p2003 / r2004
//Drive setting : p0922 = 20
VAR_INPUT
Run : Bool; // TRUE = run (STW1.0 ON / OFF1)
Reverse : Bool; // TRUE = negative speed setpoint
AckFault : Bool; // pulse TRUE to acknowledge a fault (STW1.7)
CoastStop : Bool; // TRUE = OFF2, motor coasts
QuickStop : Bool; // TRUE = OFF3, fast ramp stop
SpeedSP_rpm : Real; // speed setpoint in rpm (positive)
RefSpeed_rpm : Real := 1500.0; // MUST equal p2000
RefCurrent_A : Real := 10.0; // MUST equal p2002
RefTorque_Nm : Real := 10.0; // MUST equal p2003
RefPower_kW : Real := 4.0; // MUST equal r2004
HW_ID : HW_IO; // hardware ID of the telegram (system constant)
END_VAR
VAR_OUTPUT
ReadyToSwitchOn : Bool; // ZSW1.0
Ready : Bool; // ZSW1.1
Running : Bool; // ZSW1.2
Fault : Bool; // ZSW1.3
SwitchOnInhibit : Bool; // ZSW1.6
Alarm : Bool; // ZSW1.7
AtSetpoint : Bool; // ZSW1.8
ActSpeed_rpm : Real; // PZD2
ActCurrent_A : Real; // PZD3
ActTorque_Nm : Real; // PZD4
ActPower_kW : Real; // PZD5
NamurWord : Word; // PZD6 MELD_NAMUR fault / alarm bits
STW1 : Word;
ZSW1 : Word;
CommError : Bool;
RdStatus : Int;
WrStatus : Int;
END_VAR
VAR
Tx : Array[1..2] of Word; // PZD1..2 to drive
Rx : Array[1..6] of Word; // PZD1..6 from drive
END_VAR
VAR_TEMP
tStw1 : Word;
tSp : LReal;
END_VAR
BEGIN
// 1. Read 6 words from the drive
#RdStatus := DPRD_DAT(LADDR := #HW_ID, RECORD => #Rx);
#ZSW1 := #Rx[1];
// 2. Decode ZSW1
#ReadyToSwitchOn := #ZSW1.%X0;
#Ready := #ZSW1.%X1;
#Running := #ZSW1.%X2;
#Fault := #ZSW1.%X3;
#SwitchOnInhibit := #ZSW1.%X6;
#Alarm := #ZSW1.%X7;
#AtSetpoint := #ZSW1.%X8;
// 3. Build STW1 (16#047E ready, 16#047F run)
#tStw1 := 16#0000;
#tStw1.%X0 := #Run AND NOT #AckFault AND NOT #SwitchOnInhibit;
#tStw1.%X1 := NOT #CoastStop;
#tStw1.%X2 := NOT #QuickStop;
#tStw1.%X3 := TRUE;
#tStw1.%X4 := TRUE;
#tStw1.%X5 := TRUE;
#tStw1.%X6 := TRUE;
#tStw1.%X7 := #AckFault;
#tStw1.%X10 := TRUE;
#STW1 := #tStw1;
#Tx[1] := #tStw1;
// 4. Speed setpoint rpm -> NSOLL_A
IF #RefSpeed_rpm > 0.0 THEN
#tSp := REAL_TO_LREAL(#SpeedSP_rpm) / REAL_TO_LREAL(#RefSpeed_rpm) * 16384.0;
IF #Reverse THEN
#tSp := -#tSp;
END_IF;
#tSp := LIMIT(MN := -32767.0, IN := #tSp, MX := 32767.0);
#Tx[2] := INT_TO_WORD(LREAL_TO_INT(#tSp));
ELSE
#Tx[2] := 16#0000;
END_IF;
// 5. Scale actual values (16#4000 = 100 % of the reference parameter)
#ActSpeed_rpm := INT_TO_REAL(WORD_TO_INT(#Rx[2])) / 16384.0 * #RefSpeed_rpm;
#ActCurrent_A := INT_TO_REAL(WORD_TO_INT(#Rx[3])) / 16384.0 * #RefCurrent_A;
#ActTorque_Nm := INT_TO_REAL(WORD_TO_INT(#Rx[4])) / 16384.0 * #RefTorque_Nm;
#ActPower_kW := INT_TO_REAL(WORD_TO_INT(#Rx[5])) / 16384.0 * #RefPower_kW;
#NamurWord := #Rx[6];
// 6. Write 2 words to the drive
#WrStatus := DPWR_DAT(LADDR := #HW_ID, RECORD := #Tx);
#CommError := (#RdStatus <> 0) OR (#WrStatus <> 0);
END_FUNCTION_BLOCKStep 2 · Data blocks
DATA_BLOCK "DB_Tel20_HMI"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
//Softwell Automation - HMI command / status DB, Telegram 20 (PZD-2/6)
//Generate "FB_G120_Tel20_PZD2x6" from its .scl source BEFORE this file.
//Edit Ref_rpm (= p2000) and the other reference values to match the drive.
VAR
Drv01 : Struct // Telegram 20 (PZD-2/6)
Cmd_Run : Bool;
Cmd_Reverse : Bool;
Cmd_Ack : Bool;
Cmd_Coast : Bool;
Cmd_QuickStop : Bool;
SP_rpm : Real;
Ref_rpm : Real := 1500.0; // = p2000
Ref_A : Real := 10.0; // = p2002
Ref_Nm : Real := 10.0; // = p2003
Ref_kW : Real := 4.0; // = r2004
Sts_Ready : Bool;
Sts_Running : Bool;
Sts_Fault : Bool;
Sts_Alarm : Bool;
Sts_CommError : Bool;
Act_rpm : Real;
Act_A : Real;
Act_Nm : Real;
Act_kW : Real;
NamurWord : Word;
STW1 : Word;
ZSW1 : Word;
END_STRUCT;
END_VAR
BEGIN
END_DATA_BLOCK
DATA_BLOCK "IDB_Tel20_Drv01"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
"FB_G120_Tel20_PZD2x6"
BEGIN
END_DATA_BLOCKStep 3 · Call function
FUNCTION "FC_Tel20_Call" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - calls drive 01 on Telegram 20 (PZD-2/6).
//Generate order: FB_G120_Tel20_PZD2x6.scl, then DB_Tel20_PZD2x6.db, then this file.
//Call this FC from OB1: "FC_Tel20_Call"();
//HW_ID: replace 270 with the hardware identifier of the telegram
//(Device view > telegram row > Properties > System constants), or drag the
//system constant (e.g. "Drive_1~...telegram...") onto the pin.
BEGIN
"IDB_Tel20_Drv01"(Run := "DB_Tel20_HMI".Drv01.Cmd_Run,
Reverse := "DB_Tel20_HMI".Drv01.Cmd_Reverse,
AckFault := "DB_Tel20_HMI".Drv01.Cmd_Ack,
CoastStop := "DB_Tel20_HMI".Drv01.Cmd_Coast,
QuickStop := "DB_Tel20_HMI".Drv01.Cmd_QuickStop,
SpeedSP_rpm := "DB_Tel20_HMI".Drv01.SP_rpm,
RefSpeed_rpm := "DB_Tel20_HMI".Drv01.Ref_rpm,
RefCurrent_A := "DB_Tel20_HMI".Drv01.Ref_A,
RefTorque_Nm := "DB_Tel20_HMI".Drv01.Ref_Nm,
RefPower_kW := "DB_Tel20_HMI".Drv01.Ref_kW,
HW_ID := 270,
Ready => "DB_Tel20_HMI".Drv01.Sts_Ready,
Running => "DB_Tel20_HMI".Drv01.Sts_Running,
Fault => "DB_Tel20_HMI".Drv01.Sts_Fault,
Alarm => "DB_Tel20_HMI".Drv01.Sts_Alarm,
ActSpeed_rpm => "DB_Tel20_HMI".Drv01.Act_rpm,
ActCurrent_A => "DB_Tel20_HMI".Drv01.Act_A,
ActTorque_Nm => "DB_Tel20_HMI".Drv01.Act_Nm,
ActPower_kW => "DB_Tel20_HMI".Drv01.Act_kW,
NamurWord => "DB_Tel20_HMI".Drv01.NamurWord,
STW1 => "DB_Tel20_HMI".Drv01.STW1,
ZSW1 => "DB_Tel20_HMI".Drv01.ZSW1,
CommError => "DB_Tel20_HMI".Drv01.Sts_CommError);
END_FUNCTIONFree telegram 999 (PZD-8/8) package
p0922 = 999 · 3 source files · blocks FB_G120_Free_PZD8x8, DB_Free8_HMI, IDB_Free8_Drv01, FC_Free8_Call
FB_G120_Free_PZD8x8.sclfunction blockDB_Free_PZD8x8.dbHMI DB + instance DBFC_Free8_Call.sclcall FC, then"FC_Free8_Call"();in OB1
Step 1 · Function block
FUNCTION_BLOCK "FB_G120_Free_PZD8x8"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - SINAMICS G120 / S120, Free telegram 999 (PZD-8/8)
//Word 1 = STW1 / ZSW1 and word 2 = speed (16#4000 = 100 % of p2000) by convention.
//Words 3..8 are free: interconnect them in the drive with r2050[x] (receive)
//and p2051[x] (send). See the BICO table on the Softwell blog page.
//Drive setting : p0922 = 999
VAR_INPUT
Run : Bool; // TRUE = run (STW1.0 ON / OFF1)
Reverse : Bool; // TRUE = negative speed setpoint
AckFault : Bool; // pulse TRUE to acknowledge a fault (STW1.7)
CoastStop : Bool; // TRUE = OFF2
QuickStop : Bool; // TRUE = OFF3
SpeedSP_rpm : Real; // speed setpoint in rpm (positive)
RefSpeed_rpm : Real := 1500.0; // MUST equal p2000
TxUser : Array[3..8] of Word; // free PLC -> drive words (PZD3..PZD8)
HW_ID : HW_IO; // hardware ID of the telegram (system constant)
END_VAR
VAR_OUTPUT
ReadyToSwitchOn : Bool; // ZSW1.0
Ready : Bool; // ZSW1.1
Running : Bool; // ZSW1.2
Fault : Bool; // ZSW1.3
SwitchOnInhibit : Bool; // ZSW1.6
Alarm : Bool; // ZSW1.7
AtSetpoint : Bool; // ZSW1.8
ActSpeed_rpm : Real; // word 2 from drive
RxUser : Array[3..8] of Word; // free drive -> PLC words (PZD3..PZD8)
STW1 : Word;
ZSW1 : Word;
CommError : Bool;
RdStatus : Int;
WrStatus : Int;
END_VAR
VAR
Tx : Array[1..8] of Word; // PZD1..8 to drive
Rx : Array[1..8] of Word; // PZD1..8 from drive
END_VAR
VAR_TEMP
tStw1 : Word;
tSp : LReal;
i : Int;
END_VAR
BEGIN
// 1. Read all 8 words from the drive
#RdStatus := DPRD_DAT(LADDR := #HW_ID, RECORD => #Rx);
#ZSW1 := #Rx[1];
// 2. Decode ZSW1
#ReadyToSwitchOn := #ZSW1.%X0;
#Ready := #ZSW1.%X1;
#Running := #ZSW1.%X2;
#Fault := #ZSW1.%X3;
#SwitchOnInhibit := #ZSW1.%X6;
#Alarm := #ZSW1.%X7;
#AtSetpoint := #ZSW1.%X8;
// 3. Build STW1 (16#047E ready, 16#047F run)
#tStw1 := 16#0000;
#tStw1.%X0 := #Run AND NOT #AckFault AND NOT #SwitchOnInhibit;
#tStw1.%X1 := NOT #CoastStop;
#tStw1.%X2 := NOT #QuickStop;
#tStw1.%X3 := TRUE;
#tStw1.%X4 := TRUE;
#tStw1.%X5 := TRUE;
#tStw1.%X6 := TRUE;
#tStw1.%X7 := #AckFault;
#tStw1.%X10 := TRUE;
#STW1 := #tStw1;
#Tx[1] := #tStw1;
// 4. Speed setpoint rpm -> word 2
IF #RefSpeed_rpm > 0.0 THEN
#tSp := REAL_TO_LREAL(#SpeedSP_rpm) / REAL_TO_LREAL(#RefSpeed_rpm) * 16384.0;
IF #Reverse THEN
#tSp := -#tSp;
END_IF;
#tSp := LIMIT(MN := -32767.0, IN := #tSp, MX := 32767.0);
#Tx[2] := INT_TO_WORD(LREAL_TO_INT(#tSp));
#ActSpeed_rpm := INT_TO_REAL(WORD_TO_INT(#Rx[2])) / 16384.0 * #RefSpeed_rpm;
ELSE
#Tx[2] := 16#0000;
#ActSpeed_rpm := 0.0;
END_IF;
// 5. Copy the free words
FOR #i := 3 TO 8 DO
#Tx[#i] := #TxUser[#i];
#RxUser[#i] := #Rx[#i];
END_FOR;
// 6. Write all 8 words to the drive
#WrStatus := DPWR_DAT(LADDR := #HW_ID, RECORD := #Tx);
#CommError := (#RdStatus <> 0) OR (#WrStatus <> 0);
END_FUNCTION_BLOCKStep 2 · Data blocks
DATA_BLOCK "DB_Free8_HMI"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
//Softwell Automation - HMI command / status DB, Free telegram 999 (PZD-8/8)
//Generate "FB_G120_Free_PZD8x8" from its .scl source BEFORE this file.
//Edit Ref_rpm (= p2000) and the other reference values to match the drive.
VAR
Drv01 : Struct // Free telegram 999 (PZD-8/8)
Cmd_Run : Bool;
Cmd_Reverse : Bool;
Cmd_Ack : Bool;
Cmd_Coast : Bool;
Cmd_QuickStop : Bool;
SP_rpm : Real;
Ref_rpm : Real := 1500.0; // = p2000
TxUser : Array[3..8] of Word; // to drive r2050[2..7]
Sts_Ready : Bool;
Sts_Running : Bool;
Sts_Fault : Bool;
Sts_Alarm : Bool;
Sts_CommError : Bool;
Act_rpm : Real;
RxUser : Array[3..8] of Word; // from drive p2051[2..7]
STW1 : Word;
ZSW1 : Word;
END_STRUCT;
END_VAR
BEGIN
END_DATA_BLOCK
DATA_BLOCK "IDB_Free8_Drv01"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
"FB_G120_Free_PZD8x8"
BEGIN
END_DATA_BLOCKStep 3 · Call function
FUNCTION "FC_Free8_Call" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - calls drive 01 on Free telegram 999 (PZD-8/8).
//Generate order: FB_G120_Free_PZD8x8.scl, then DB_Free_PZD8x8.db, then this file.
//Call this FC from OB1: "FC_Free8_Call"();
//HW_ID: replace 271 with the hardware identifier of the telegram
//(Device view > telegram row > Properties > System constants), or drag the
//system constant (e.g. "Drive_1~...telegram...") onto the pin.
BEGIN
"IDB_Free8_Drv01"(Run := "DB_Free8_HMI".Drv01.Cmd_Run,
Reverse := "DB_Free8_HMI".Drv01.Cmd_Reverse,
AckFault := "DB_Free8_HMI".Drv01.Cmd_Ack,
CoastStop := "DB_Free8_HMI".Drv01.Cmd_Coast,
QuickStop := "DB_Free8_HMI".Drv01.Cmd_QuickStop,
SpeedSP_rpm := "DB_Free8_HMI".Drv01.SP_rpm,
RefSpeed_rpm := "DB_Free8_HMI".Drv01.Ref_rpm,
TxUser := "DB_Free8_HMI".Drv01.TxUser,
HW_ID := 271,
Ready => "DB_Free8_HMI".Drv01.Sts_Ready,
Running => "DB_Free8_HMI".Drv01.Sts_Running,
Fault => "DB_Free8_HMI".Drv01.Sts_Fault,
Alarm => "DB_Free8_HMI".Drv01.Sts_Alarm,
ActSpeed_rpm => "DB_Free8_HMI".Drv01.Act_rpm,
RxUser => "DB_Free8_HMI".Drv01.RxUser,
STW1 => "DB_Free8_HMI".Drv01.STW1,
ZSW1 => "DB_Free8_HMI".Drv01.ZSW1,
CommError => "DB_Free8_HMI".Drv01.Sts_CommError);
END_FUNCTIONFree telegram 999 (PZD-16/16) package
p0922 = 999 · 3 source files · blocks FB_G120_Free_PZD16x16, DB_Free16_HMI, IDB_Free16_Drv01, FC_Free16_Call
FB_G120_Free_PZD16x16.sclfunction blockDB_Free_PZD16x16.dbHMI DB + instance DBFC_Free16_Call.sclcall FC, then"FC_Free16_Call"();in OB1
Step 1 · Function block
FUNCTION_BLOCK "FB_G120_Free_PZD16x16"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - SINAMICS G120 / S120, Free telegram 999 (PZD-16/16)
//Word 1 = STW1 / ZSW1 and word 2 = speed (16#4000 = 100 % of p2000) by convention.
//Words 3..16 are free: interconnect them in the drive with r2050[x] (receive)
//and p2051[x] (send). See the BICO table on the Softwell blog page.
//Drive setting : p0922 = 999
VAR_INPUT
Run : Bool; // TRUE = run (STW1.0 ON / OFF1)
Reverse : Bool; // TRUE = negative speed setpoint
AckFault : Bool; // pulse TRUE to acknowledge a fault (STW1.7)
CoastStop : Bool; // TRUE = OFF2
QuickStop : Bool; // TRUE = OFF3
SpeedSP_rpm : Real; // speed setpoint in rpm (positive)
RefSpeed_rpm : Real := 1500.0; // MUST equal p2000
TxUser : Array[3..16] of Word; // free PLC -> drive words (PZD3..PZD16)
HW_ID : HW_IO; // hardware ID of the telegram (system constant)
END_VAR
VAR_OUTPUT
ReadyToSwitchOn : Bool; // ZSW1.0
Ready : Bool; // ZSW1.1
Running : Bool; // ZSW1.2
Fault : Bool; // ZSW1.3
SwitchOnInhibit : Bool; // ZSW1.6
Alarm : Bool; // ZSW1.7
AtSetpoint : Bool; // ZSW1.8
ActSpeed_rpm : Real; // word 2 from drive
RxUser : Array[3..16] of Word; // free drive -> PLC words (PZD3..PZD16)
STW1 : Word;
ZSW1 : Word;
CommError : Bool;
RdStatus : Int;
WrStatus : Int;
END_VAR
VAR
Tx : Array[1..16] of Word; // PZD1..16 to drive
Rx : Array[1..16] of Word; // PZD1..16 from drive
END_VAR
VAR_TEMP
tStw1 : Word;
tSp : LReal;
i : Int;
END_VAR
BEGIN
// 1. Read all 16 words from the drive
#RdStatus := DPRD_DAT(LADDR := #HW_ID, RECORD => #Rx);
#ZSW1 := #Rx[1];
// 2. Decode ZSW1
#ReadyToSwitchOn := #ZSW1.%X0;
#Ready := #ZSW1.%X1;
#Running := #ZSW1.%X2;
#Fault := #ZSW1.%X3;
#SwitchOnInhibit := #ZSW1.%X6;
#Alarm := #ZSW1.%X7;
#AtSetpoint := #ZSW1.%X8;
// 3. Build STW1 (16#047E ready, 16#047F run)
#tStw1 := 16#0000;
#tStw1.%X0 := #Run AND NOT #AckFault AND NOT #SwitchOnInhibit;
#tStw1.%X1 := NOT #CoastStop;
#tStw1.%X2 := NOT #QuickStop;
#tStw1.%X3 := TRUE;
#tStw1.%X4 := TRUE;
#tStw1.%X5 := TRUE;
#tStw1.%X6 := TRUE;
#tStw1.%X7 := #AckFault;
#tStw1.%X10 := TRUE;
#STW1 := #tStw1;
#Tx[1] := #tStw1;
// 4. Speed setpoint rpm -> word 2
IF #RefSpeed_rpm > 0.0 THEN
#tSp := REAL_TO_LREAL(#SpeedSP_rpm) / REAL_TO_LREAL(#RefSpeed_rpm) * 16384.0;
IF #Reverse THEN
#tSp := -#tSp;
END_IF;
#tSp := LIMIT(MN := -32767.0, IN := #tSp, MX := 32767.0);
#Tx[2] := INT_TO_WORD(LREAL_TO_INT(#tSp));
#ActSpeed_rpm := INT_TO_REAL(WORD_TO_INT(#Rx[2])) / 16384.0 * #RefSpeed_rpm;
ELSE
#Tx[2] := 16#0000;
#ActSpeed_rpm := 0.0;
END_IF;
// 5. Copy the free words
FOR #i := 3 TO 16 DO
#Tx[#i] := #TxUser[#i];
#RxUser[#i] := #Rx[#i];
END_FOR;
// 6. Write all 16 words to the drive
#WrStatus := DPWR_DAT(LADDR := #HW_ID, RECORD := #Tx);
#CommError := (#RdStatus <> 0) OR (#WrStatus <> 0);
END_FUNCTION_BLOCKStep 2 · Data blocks
DATA_BLOCK "DB_Free16_HMI"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
//Softwell Automation - HMI command / status DB, Free telegram 999 (PZD-16/16)
//Generate "FB_G120_Free_PZD16x16" from its .scl source BEFORE this file.
//Edit Ref_rpm (= p2000) and the other reference values to match the drive.
VAR
Drv01 : Struct // Free telegram 999 (PZD-16/16)
Cmd_Run : Bool;
Cmd_Reverse : Bool;
Cmd_Ack : Bool;
Cmd_Coast : Bool;
Cmd_QuickStop : Bool;
SP_rpm : Real;
Ref_rpm : Real := 1500.0; // = p2000
TxUser : Array[3..16] of Word; // to drive r2050[2..15]
Sts_Ready : Bool;
Sts_Running : Bool;
Sts_Fault : Bool;
Sts_Alarm : Bool;
Sts_CommError : Bool;
Act_rpm : Real;
RxUser : Array[3..16] of Word; // from drive p2051[2..15]
STW1 : Word;
ZSW1 : Word;
END_STRUCT;
END_VAR
BEGIN
END_DATA_BLOCK
DATA_BLOCK "IDB_Free16_Drv01"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
NON_RETAIN
"FB_G120_Free_PZD16x16"
BEGIN
END_DATA_BLOCKStep 3 · Call function
FUNCTION "FC_Free16_Call" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 1.0
//Softwell Automation - calls drive 01 on Free telegram 999 (PZD-16/16).
//Generate order: FB_G120_Free_PZD16x16.scl, then DB_Free_PZD16x16.db, then this file.
//Call this FC from OB1: "FC_Free16_Call"();
//HW_ID: replace 272 with the hardware identifier of the telegram
//(Device view > telegram row > Properties > System constants), or drag the
//system constant (e.g. "Drive_1~...telegram...") onto the pin.
BEGIN
"IDB_Free16_Drv01"(Run := "DB_Free16_HMI".Drv01.Cmd_Run,
Reverse := "DB_Free16_HMI".Drv01.Cmd_Reverse,
AckFault := "DB_Free16_HMI".Drv01.Cmd_Ack,
CoastStop := "DB_Free16_HMI".Drv01.Cmd_Coast,
QuickStop := "DB_Free16_HMI".Drv01.Cmd_QuickStop,
SpeedSP_rpm := "DB_Free16_HMI".Drv01.SP_rpm,
RefSpeed_rpm := "DB_Free16_HMI".Drv01.Ref_rpm,
TxUser := "DB_Free16_HMI".Drv01.TxUser,
HW_ID := 272,
Ready => "DB_Free16_HMI".Drv01.Sts_Ready,
Running => "DB_Free16_HMI".Drv01.Sts_Running,
Fault => "DB_Free16_HMI".Drv01.Sts_Fault,
Alarm => "DB_Free16_HMI".Drv01.Sts_Alarm,
ActSpeed_rpm => "DB_Free16_HMI".Drv01.Act_rpm,
RxUser => "DB_Free16_HMI".Drv01.RxUser,
STW1 => "DB_Free16_HMI".Drv01.STW1,
ZSW1 => "DB_Free16_HMI".Drv01.ZSW1,
CommError => "DB_Free16_HMI".Drv01.Sts_CommError);
END_FUNCTIONOB1 call for each package
// OB1 - add the line for each package you imported
"FC_Tel1_Call"(); // Telegram 1, PZD-2/2
"FC_Tel20_Call"(); // Telegram 20, PZD-2/6
"FC_Free8_Call"(); // Free telegram, PZD-8/8
"FC_Free16_Call"(); // Free telegram, PZD-16/16Single Telegram 1 drive without the HMI DB
// OB1 - SCL network: one Telegram 1 drive, instance DB "IDB_Drive_1"
"IDB_Drive_1"(Run := "Motor1_Run",
AckFault := "Motor1_Reset",
SpeedSP_rpm := "HMI_Set_RPM",
RefSpeed_rpm := 1500.0, // = p2000
HW_ID := "Drive_1~Standard_telegram_1",
Running => "Motor1_Running",
Fault => "Motor1_Fault",
ActSpeed_rpm => "HMI_Act_RPM");Free telegram drive parameters (BICO)
Set these in the drive after p0922 = 999. Receive words are r2050[x], bits of word 1 are r2090.x, send words are p2051[x]; index 0 is PZD1. Confirm parameter numbers in your control unit's list manual.
// Free telegram 999 - receive (PLC -> drive)
p0922 = 999 // free telegram
p0840[0] = r2090.0 // ON / OFF1
p0844[0] = r2090.1 // OFF2
p0848[0] = r2090.2 // OFF3
p0852[0] = r2090.3 // enable operation
p1140[0] = r2090.4 // enable ramp-function generator
p1141[0] = r2090.5 // continue ramp-function generator
p1142[0] = r2090.6 // enable setpoint
p2103[0] = r2090.7 // acknowledge fault
p0854[0] = r2090.10 // control by PLC
p1070[0] = r2050[1] // main speed setpoint (word 2)
// Free telegram 999 - send (drive -> PLC)
p2051[0] = r2089[0] // word 1: ZSW1
p2051[1] = r0063 // word 2: actual speed
p2051[2] = r0027 // word 3: current (example)
p2051[3] = r0031 // word 4: torque (example)
p2051[4] = r0032 // word 5: power (example)
p2051[5] = r0026 // word 6: DC-link voltage (example)
// save: copy RAM to ROMWatch table for testing a package
// Telegram 1 package - use DB_Tel20_HMI, DB_Free8_HMI or DB_Free16_HMI for the others
"DB_Tel1_HMI".Drv01.Cmd_Run Bool TRUE / FALSE
"DB_Tel1_HMI".Drv01.SP_rpm Real 750.0
"DB_Tel1_HMI".Drv01.STW1 Hex 16#047E stopped, 16#047F running
"DB_Tel1_HMI".Drv01.ZSW1 Hex from drive
"DB_Tel1_HMI".Drv01.Sts_Running Bool ZSW1 bit 2
"DB_Tel1_HMI".Drv01.Sts_Fault Bool ZSW1 bit 3
"DB_Tel1_HMI".Drv01.Act_rpm Real about 750.0 when running
"DB_Tel1_HMI".Drv01.Sts_CommError Bool must be FALSEImport the Code into TIA Portal
- In the project tree, open the PLC, expand External source files and double-click Add new external file.
- Select the saved .scl or .db file, right-click it and choose Generate blocks from source.
- For each telegram, generate its three files in the package order: the FB
.scl, then the.db(HMI DB + instance DB), then the call FC.scl. - In the package's call FC, replace the example hardware ID (269, 270, 271 or 272) with each telegram's hardware identifier (Device view → telegram row → Properties → System constants).
- Enter p2000 (and p2002, p2003, r2004 for Telegram 20) in that package's HMI DB (for example
DB_Tel1_HMI), set p0922 in the drive, then download.
Troubleshooting the Telegram Logic
| Symptom | Likely cause | Fix |
|---|---|---|
| STW1 stays 16#047E with Run TRUE | ZSW1 bit 6 still set, or drive fault | Check ZSW1; acknowledge any fault |
| STW1 16#047F, motor does not turn | Speed setpoint 0 or p0922 different from TIA | Check SP_rpm and the drive's telegram |
| Speed half or double | Ref_rpm ≠ p2000 | Copy p2000 into the DB |
| RdStatus 16#8090 | Wrong hardware ID | Use the telegram row's system constant |
| RdStatus 16#80B1 | FB length ≠ configured telegram | Use the FB that matches the telegram |
| Fault will not clear | Cmd_Ack held TRUE | Pulse it for one scan |
Step-by-Step Lab: Standard Telegram Logic on Live Hardware
Hands-on- An S7-1200 (firmware V4+) or S7-1500 and a G120 with a PROFINET control unit in one TIA Portal project.
- p2000 known and the motor uncoupled or on a test bench.
- Estimated time: 45 minutes.
Generate the blocks
Download the Telegram 1 package and generate FB_G120_Tel1_PZD2x2.scl, DB_Tel1_PZD2x2.db and FC_Tel1_Call.scl in that order. Add "FC_Tel1_Call"(); to OB1.
Check the ready logic
Download, go online and watch STW1 and ZSW1 in hexadecimal with no command.
Run and verify scaling
Set SP_rpm to 750.0 and Cmd_Run to TRUE.
Test the stops and acknowledge
Try Cmd_Coast, Cmd_QuickStop and Cmd_Run = FALSE in turn, then force a fault and pulse Cmd_Ack.
You can predict the hex value of STW1 before you change a command, and read the drive state from ZSW1 without looking it up.
For the same Telegram 1 logic in Ladder, see the G120 PROFINET standard FB, and for every bit in detail, SINAMICS G120 STW1 and ZSW1 bits.
Frequently asked questions
What is Siemens standard telegram logic?
It is the PLC program logic that builds the STW1 control word from machine commands, scales the speed setpoint so that 16#4000 equals 100 percent of p2000, and decodes the ZSW1 status word and actual values coming back from a SINAMICS drive.
Why does the drive need 16#047E before 16#047F?
After power-up or a fault the drive is in switching on inhibited (ZSW1 bit 6). It only leaves that state when it sees ON = 0 with the stop and enable bits set, which is 16#047E. Then 16#047F switches it on.
How do I acknowledge a fault with the standard telegram?
Set STW1 bit 7 for at least one scan to give a 0 to 1 edge, which is 16#04FE with ON at 0, then return to 16#047E. Holding bit 7 permanently does not acknowledge a new fault.
What does 16#4000 mean in the speed word?
16#4000 (16384) is 100 percent of the drive reference speed p2000. With p2000 = 1500 rpm, 16#2000 is 750 rpm and a negative value runs in reverse.
Can I copy the SCL and DB code straight into TIA Portal?
Yes. Each telegram has its own package of three files. Save each box with the file name shown, add it under External source files and choose Generate blocks from source: the FB .scl first, then the .db, then the call FC .scl.
Which telegram should I use, 1, 20 or 999?
Use Telegram 1 for start, stop and speed. Use Telegram 20 when you also want current, torque, power and a fault word. Use free telegram 999 when you need to choose the signals yourself.