A permissive is checked before starting and does not necessarily stop a running machine. An interlock is checked continuously and trips the machine when it fails. Build permissives as a chain of normally open contacts driving a Ready bit, build interlocks as latched trips with a deliberate reset, and always publish which condition is missing so the operator can see it.
- Permissive to start, interlock to keep running; the two need different logic and different reset behaviour.
- Latch a trip so it cannot clear itself before anyone sees it.
- A Ready bit without a reason bit forces the operator to phone maintenance to find out what is missing.
Permissive, Interlock and Trip
| Term | Checked | Effect when not satisfied | Example |
|---|---|---|---|
| Permissive | Before start | Start command refused | Guard door closed, downstream conveyor ready |
| Interlock | Continuously | Machine stops | Motor overload, loss of cooling |
| Trip | Continuously, latched | Machine stops and stays stopped | Emergency stop, high high temperature |
| Inhibit | During a defined state | Command ignored | Cannot open valve while pump running |
A pump that needs suction pressure before starting has a permissive. A pump that must stop if suction pressure is lost has an interlock. Often both apply to the same signal with different limits, and writing them as one condition is where machines start behaving unpredictably.
None of this replaces a safety system. Emergency stops, light curtains and guard locking belong in a safety relay or a fail-safe CPU with a certified architecture. PLC interlocks are process protection, not personnel protection, and the two must be designed separately.
Building the Permissive Chain
Write the permissive as a single rung of normally open contacts in series, ending in a Ready coil. Each contact is a condition that must be true.
- Guard doors closed and locked.
- No active trip present.
- Downstream equipment ready to receive.
- Air pressure and lubrication healthy.
- Mode selected and no manual override active.
Keeping them in one visible chain is the point. Going online, an engineer sees the whole start condition at a glance and the open contact is obvious. Splitting the same conditions across six networks with intermediate flags makes fault finding slower for no benefit.
Field wiring convention
Wire safety-relevant field contacts normally closed so that a broken wire produces the safe state. Then the PLC input is true in the healthy condition and a normally open contact in the program reads correctly. Getting this backwards means a cut cable leaves the machine believing everything is fine.
The same reasoning applies to the stop button in the basic start/stop circuit.
Interlocks, Latching and Reset Handling
An interlock is evaluated every scan while the machine runs. When it fails, the machine must stop and the reason must survive long enough to be read.
- Detect the condition and set a bit in the fault word.
- Latch the fault so it stays set even if the condition clears immediately.
- Drop the run command and stop the equipment.
- Record which fault was first, because a single trip usually causes several.
- Require a deliberate reset before the fault bits clear.
First-out detection
When a motor trips, its downstream equipment often trips too. Without first-out logic, five faults appear simultaneously and nobody knows which came first. Capture the first fault into a separate register at the moment of the trip and hold it until reset. It is a few lines of code that saves hours on site; the complete SCL is in first-out capture code below.
Reset that means something
A reset should clear latched faults only when the underlying conditions have actually cleared. An auto-reset that fires every scan hides the fault entirely, and the machine appears to stop for no reason.
Build safe machine logic properly
Practical Siemens sessions covering permissives, interlocks, fault handling and commissioning.
Publishing Status So the Operator Can Act
The logic is only half the job. If the machine will not start and the screen says nothing, an operator's only option is a phone call.
Publish three things to the HMI interface data block:
- Ready: a single bit summarising the permissive chain.
- NotReadyReason: an integer identifying the first missing permissive, mapped to text on the panel.
- FaultWord and FirstOut: the latched interlock bits and the fault that tripped first.
On the panel (laid out as in HMI screen design best practices), map the reason integer through a text list so the operator reads "Waiting for guard door 2 closed" instead of a number. The configuration is covered in the HMI sequence status screen, and the fault word, latch and reset that feed Any_Fault are built step by step in HMI alarm configuration: IO mapping and alarm mapping FC. The worked example below continues that project.
| Mistake | Consequence |
|---|---|
| Permissives and interlocks in one condition | Machine trips on conditions that should only block starting |
| Unlatched trips | Fault clears before anyone sees it |
| No first-out capture | Five faults, no idea which came first |
| Auto reset every scan | Faults invisible, machine stops for no visible reason |
| Ready bit with no reason | Every start refusal becomes a maintenance call |
Worked Example in TIA Portal: Conveyor Motor M1 Start Chain
The theory above becomes concrete with one motor. This example continues the project from HMI alarm configuration in TIA Portal, which already provides DB_IO (field signals, 1 = healthy), "DB_Alarm".Alarm (15 latched alarms with reset) and "DB_Alarm".Any_Fault. Here we add the start chain for conveyor motor M1, a contactor feedback trip, first-out capture and the not-ready reason. The same address rule applies: %I only in FC_InputMapping, %Q only in FC_OutputMapping, symbolic DB members everywhere else.
Signals, data block and program structure
| PLC tag | Address | Wiring | DB_IO member | Role |
|---|---|---|---|---|
Start_PB | %I2.0 | NO push button | Start_PB | Start command (momentary) |
Stop_PB_OK | %I2.1 | NC push button, 1 = not pressed | Stop_PB_OK | Interlock: stop at any time; a broken wire also stops |
Auto_Mode | %I2.2 | Selector switch, 1 = AUTO | Auto_Mode | Permissive 5 |
Downstream_Ready | %I2.3 | Contact from downstream conveyor, 1 = ready | Downstream_Ready | Permissive 3 |
M1_Running | %I2.4 | Contactor K1 auxiliary NO, 1 = pulled in | M1_Running | Feedback for the 2 s trip |
HS_SafetyDoor_OK, SS_AirPressure_OK | %I0.2, %I1.4 | NC, from the alarm lesson | already in DB_IO | Permissives 1 and 4 |
Motor_M1_Run | %Q0.0 | Contactor K1 coil (via interposing relay) | written from "DB_Motor".Run_Cmd | Output, in FC_OutputMapping |
Create a global optimized data block DB_Motor (DB30):
| DB_Motor member | Data type | Written by | Meaning |
|---|---|---|---|
Ready | Bool | FC_MotorM1 Network 1 | All permissives satisfied, M1 may start |
Run_Cmd | Bool | FC_MotorM1 Network 2 | Run command to the contactor |
NotReadyReason | Int | FC_MotorStatus | 0 = ready, 1 – 5 = first missing permissive |
FirstOut | Int | FC_MotorStatus | 0 = no trip, 1 – 16 = alarm bit that tripped first + 1 |
OB1 Network 1 CALL "FC_InputMapping" // %I → DB_IO OB1 Network 2 CALL "FC_AlarmMapping" // DB_IO → DB_Alarm.Alarm, Any_Fault (incl. %X15 trip) OB1 Network 3 CALL "FC_MotorM1" // Ready, Run_Cmd (LAD) OB1 Network 4 CALL "FC_MotorStatus" // NotReadyReason, FirstOut (SCL) OB1 Network 5 CALL "FC_OutputMapping" // DB_Motor.Run_Cmd → %Q0.0
Which condition is a permissive and which is an interlock
Classify every condition before writing a single contact. The table is the specification for the two networks that follow.
| Condition | Signal | Permissive (start) | Interlock (running) | Why |
|---|---|---|---|---|
| Guard door closed | DB_IO.HS_SafetyDoor_OK | Yes, reason 1 | Through alarm HS-03 → Any_Fault | Opening the door also latches HS-03; the actual stop is done by the safety relay |
| No latched alarm | NOT DB_Alarm.Any_Fault | Yes, reason 2 | Yes | Every fault in the alarm word stops M1 and blocks restart until reset |
| Downstream conveyor ready | DB_IO.Downstream_Ready | Yes, reason 3 | No | Only matters when starting; a running line handles it with its own sequence |
| Compressed air OK | DB_IO.SS_AirPressure_OK | Yes, reason 4 | Through alarm SS-03 → Any_Fault | Low air while running becomes a latched alarm |
| AUTO selected | DB_IO.Auto_Mode | Yes, reason 5 | No | Switching to MANUAL should not stop a running motor |
| Stop push button | DB_IO.Stop_PB_OK | – | Yes | Operator stop, always effective |
| Contactor feedback | DB_IO.M1_Running | – | Yes, 2 s trip → Alarm.%X15 | Detects a contactor that did not pull in or dropped out |
Network 1 – the permissive chain
"DB_Motor".Ready; the order also defines the not-ready reason numbers.Network 2 – start/stop seal-in with the Any_Fault interlock
This is where "DB_Alarm".Any_Fault from the alarm lesson blocks the start command and stops a running motor. The position of each contact in the rung decides whether it acts as a permissive or as an interlock.
// SCL equivalent of Network 2
"DB_Motor".Run_Cmd := ( ("DB_IO".Start_PB AND "DB_Motor".Ready) OR "DB_Motor".Run_Cmd )
AND "DB_IO".Stop_PB_OK
AND NOT "DB_Alarm".Any_Fault;
Because Any_Fault is the collective bit of a latched alarm word, the motor cannot be restarted until the operator has reset the alarm, and reset only works once the field contact is healthy again. That is the "reset that means something" rule from above, implemented once for every alarm.
Contactor feedback trip on spare bit %X15
Add one network to FC_AlarmMapping, before the Any_Fault network, using the spare bit of the alarm word and an IEC timer instance "T_M1_Feedback" (TON_TIME). Add a 16th discrete alarm on the HMI: trigger bit 15, class SS_System, text "M1 contactor feedback missing – check K1, overload and control fuse".
// FC_AlarmMapping – M1 commanded but contactor not confirmed for 2 s → latch %X15
"T_M1_Feedback".TON(IN := "DB_Motor".Run_Cmd AND NOT "DB_IO".M1_Running,
PT := T#2S);
"DB_Alarm".Alarm.%X15 := "T_M1_Feedback".Q
OR ("DB_Alarm".Alarm.%X15 AND NOT "DB_Alarm".Reset_Cmd);
When the trip latches, Any_Fault drops Run_Cmd, the timer input goes false, and the latch keeps the alarm until reset. The 2 s value must be longer than the contactor's pull-in time plus input filter delay.
First-out capture code (FC_MotorStatus, SCL)
One fault usually causes others: low air pressure stops a cylinder, a guard is opened to look, the MPCB trips on the stalled motor. All three alarms are latched, but only one is the cause. First-out stores the alarm that arrived while the register was still empty and holds it until everything has been reset.
// FC_MotorStatus – TEMP: #w : Word; #i : Int;
// First-out: capture the first alarm bit while FirstOut is still 0
IF "DB_Motor".FirstOut = 0 AND "DB_Alarm".Alarm <> 16#0000 THEN
#w := "DB_Alarm".Alarm;
FOR #i := 0 TO 15 DO
IF #w.%X0 THEN
"DB_Motor".FirstOut := #i + 1; // 1 = %X0 (HS-01) … 16 = %X15 (M1 feedback)
EXIT;
END_IF;
#w := SHR(IN := #w, N := 1);
END_FOR;
END_IF;
// Clear only after every alarm has been reset
IF "DB_Alarm".Alarm = 16#0000 THEN
"DB_Motor".FirstOut := 0;
END_IF;
Because the register is written only while it is 0, later alarms never overwrite it, even if they have a lower bit number. Only when two alarms latch in the same scan does the lower bit win, which is acceptable at a 10 ms cycle. On the HMI, show FirstOut in a symbolic output field with a text list (0 = "No trip", 1 – 15 = the alarm texts HS-01 … SS-05, 16 = "M1 contactor feedback missing").
Not-ready reason (FC_MotorStatus, SCL)
// Same order as the permissive chain in FC_MotorM1 Network 1
IF NOT "DB_IO".HS_SafetyDoor_OK THEN
"DB_Motor".NotReadyReason := 1;
ELSIF "DB_Alarm".Any_Fault THEN
"DB_Motor".NotReadyReason := 2;
ELSIF NOT "DB_IO".Downstream_Ready THEN
"DB_Motor".NotReadyReason := 3;
ELSIF NOT "DB_IO".SS_AirPressure_OK THEN
"DB_Motor".NotReadyReason := 4;
ELSIF NOT "DB_IO".Auto_Mode THEN
"DB_Motor".NotReadyReason := 5;
ELSE
"DB_Motor".NotReadyReason := 0;
END_IF;
| Value | Text list TL_NotReady (shown on the HMI) |
|---|---|
| 0 | Ready to start |
| 1 | Waiting: guard door closed (HS-03) |
| 2 | Blocked: active fault – see alarm screen |
| 3 | Waiting: downstream conveyor ready |
| 4 | Waiting: compressed air pressure (SS-03) |
| 5 | Select AUTO mode |
On the panel, add the HMI tags DB_Motor_Ready, DB_Motor_Run_Cmd, DB_Motor_NotReadyReason and DB_Motor_FirstOut, then place a Ready lamp, a Running lamp and two symbolic I/O fields (mode Output) linked to the text lists. The screen-building method, object properties and animations are the same as in Build the same HMI screens in TIA Portal.
Interactive Start-Chain Simulator: Permissives, Interlocks and First-Out
Try the worked example live. Switch the field conditions, press START and STOP, trip faults while the motor runs and watch both ladder networks conduct in green. The panel shows the not-ready reason and the first-out fault exactly as the HMI would.
Hands-On Lab: Conveyor Motor Start Chain with Interlocks and First-Out Capture
Hands-on- TIA Portal with an S7-1200 or S7-1500 CPU, or PLCSIM
- The DB_IO / DB_Alarm project from the HMI alarm configuration lesson, or a fresh project with the same tags
- Simulation only; do not test on live equipment
- Estimated time: 60 minutes
Map the start-chain signals
Add Start_PB, Stop_PB_OK, Auto_Mode, Downstream_Ready and M1_Running to the PLC tag table and copy them into DB_IO in FC_InputMapping; create DB_Motor with Ready, Run_Cmd, NotReadyReason and FirstOut.
Build the permissive chain
In FC_MotorM1 write one network with five contacts in series driving DB_Motor.Ready: door closed, no Any_Fault, downstream ready, air pressure OK and auto mode.
Build the start/stop seal-in with interlocks
Put Start_PB and Ready in the start branch, Run_Cmd in the seal-in branch, and Stop_PB_OK and NOT Any_Fault in series after both; drive Motor_M1_Run from Run_Cmd in FC_OutputMapping.
Add the contactor feedback trip
Time Run_Cmd AND NOT M1_Running with a 2 s TON and latch the result into DB_Alarm.Alarm.%X15 with the same reset structure as the other alarms.
Add first-out capture and the not-ready reason
In FC_MotorStatus (SCL) store the first alarm bit into FirstOut and write NotReadyReason in the same order as the permissive chain.
Test cascade trips and reset
In PLCSIM or the simulator, trip air pressure, then the door, then the MPCB, and confirm FirstOut shows the air pressure fault and reset works only when every source is healthy.
The machine refuses to start with a named reason, the stop button and Any_Fault stop it at any time, trips are latched with the true first fault identified, and reset only works once the plant is actually healthy.
Frequently asked questions
What is the difference between a permissive and an interlock?
A permissive is checked before starting and blocks the start command. An interlock is checked continuously and stops a running machine when it fails.
Should interlocks be programmed in the standard PLC or a safety controller?
Process interlocks belong in the standard PLC. Personnel protection such as emergency stop, guard locking and light curtains belongs in a safety relay or fail-safe CPU with a certified architecture.
Why latch a trip instead of letting it clear itself?
So the reason survives long enough to be read. An unlatched trip can appear and clear within one scan, leaving a machine that stopped for no visible reason.
What is first-out detection?
Capturing which fault occurred first when a single event causes several trips, so fault finding starts at the cause rather than the consequences.
Where do permissives and interlocks go in a start/stop seal-in rung?
Permissives go in series with the start push button only, so they are checked once when starting. Interlocks such as the stop button and the collective fault go in the common path after the seal-in branch, so they are checked every scan while running.
How do I program first-out capture in TIA Portal?
When the first-out register is 0 and the alarm word becomes non-zero, store the number of the set bit, then hold it until the alarm word returns to 0 after reset. A short SCL loop over the 16 bits of the alarm word does this in a few lines.
How does the operator see why the machine will not start?
Write a NotReadyReason integer in the same order as the permissive chain and show it on the HMI through a text list, so the panel reads, for example, Waiting: downstream conveyor ready instead of a number.
What is a contactor feedback trip?
If the PLC commands the motor to run but the contactor auxiliary contact does not confirm within a set time, a timer trips the motor and latches an alarm. It detects a failed contactor, a tripped overload or an open control circuit.