Cyclic FB Execution in TIA Portal: Continuous Motor Control

David Krause15 min read
SiemensTIA PortalTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview: From One-Shot to Continuous Cyclic Execution

A common first failure point for engineers moving from ladder logic to structured PLC programming is the assumption that a Function Block (FB) automatically repeats its internal logic. In Siemens S7-1200 and S7-1500 controllers running on TIA Portal, OB1 executes the user program cyclically at the configured scan cycle (or by interrupt-driven OBs for time-critical sections). The FB instance, however, only progresses through its internal state once per rising edge of its execute input. When the FB is wired such that its EN/EN0 input is dropped, or its Execute condition never re-asserts, the motor sequence appears to run exactly once and then sit in the last state forever.

This article explains why a directional motor FB stops after a single forward/reverse cycle, how to redesign the call interface so the cycle repeats, how to leverage the Siemens LAxisControl and LAcycCom application examples, and how to resolve a secondary fault where the drive fails to reach the target down position before reversing.

Applies to: S7-1200 (firmware 4.4 or higher, tested on 4.6), S7-1500 (firmware 2.9 or higher, tested on V3.0), TIA Portal V17/V18/V19. The pattern also applies to ET 200SP CPUs.

Cyclic OB1 Execution Model in S7-1200/1500 PLCs

OB1 is the main cyclic organization block in Siemens S7 controllers. The CPU reads inputs, executes OB1 from the first network to the last, writes outputs, and then immediately restarts the cycle. The cycle time is reported in the CPU diagnostics and is influenced by the user program length and any configured minimum cycle time or watchdog.

Parameter Path in TIA Portal Typical Value Notes
Scan cycle time CPU Properties > Cycle 1 ms to 60000 ms Watchdog default 6000 ms; OB1 overrun generates OB80.
OB1 priority class Fixed at 1 1 Cannot be changed; lower priority OBs may interrupt OB1.
Process image (PII / PIQ) CPU Properties > I/O Addresses Auto-update at OB1 start/end Inputs are consistent for the entire cycle.
OB35 / OB82 / OB121 Project tree > Add new OB Hardware / time / error interrupts Use OB35 for cyclic axes at fixed slice; OB82 for diagnostics.

Inside OB1 the FB is invoked with its instance DB as a parameter. Two boolean inputs are typically present: the EN enable (always TRUE if you want OB1 to drive the call) and the Execute (rising edge) which is the formal start trigger. The state of these inputs is what determines whether the FB begins, continues, or finishes its internal sequence.

Why a Function Block Stops After One Cycle

The user's described symptom - motor runs forward, runs reverse, then stops, executing the motion sequence only once - is almost always caused by one of three design errors:

  1. Single-shot Execute wired to OB1 scan. The Execute condition is a one-cycle pulse generated by a flank on a global start tag. After the FB finishes it goes to Done and never restarts because Execute stays FALSE.
  2. EN input tied to a sequencer flag. A common error is to put the busy flag on the EN input. As soon as the FB starts, Busy becomes TRUE, but Done is also asserted by the same path, so EN/EN0 toggles and the call is skipped on the next cycle.
  3. No state memory. The FB relies entirely on its local TEMP variables, which are reinitialised each call. Without a STAT field that records "I have already executed the reverse stroke" the FB cannot decide what to do next time Execute is pulsed.

The fix is to keep the EN input TRUE continuously and route the explicit start command to the Execute input. The internal logic of the FB must be written as a state machine that loops back from the last state to the first when both Done and a continuous-run flag are TRUE.

EN Input vs Execute Input: The Critical Distinction

Siemens blocks differentiate the enable line and the trigger line. The following table summarises the contract:

Input Function Edge sensitivity Recommended use
EN / EN0 Switches the call itself. If FALSE, the FB is not processed and outputs hold their last value (LAD/FBD) or are not assigned (SCL). Level-sensitive Permissives such as drive ready, safety circuit closed, controller in RUN.
Execute / REQ / Start Initiates a new job. A rising edge transitions the FB from idle to busy. Rising-edge sensitive Operator start pushbutton, recipe step transition, FB-internal state advance.

For a motor FB, the rule is: EN must be TRUE for every cycle in which you want the FB logic evaluated. The forward/reverse sequence is controlled by a state machine that internally pulses Execute to the next motion command. The outer call should look like this in SCL:

// OB1 - Main
IF "blockntw" AND NOT "disable_power" THEN
    "MotorInstance".EN := TRUE;
ELSE
    "MotorInstance".EN := FALSE;
END_IF;
"MotorInstance".Continuous := g_bRunContinuous;   // continuous-run flag
"MotorInstance".TargetTop   := g_rTargetTop;
"MotorInstance".TargetBot   := g_rTargetBot;
"MotorInstance"();            // call the FB

Notice the absence of an Execute wire to a one-shot pulse. The FB is responsible for sequencing its own motion jobs.

Designing a Bidirectional Motor State Machine

A four-state machine is sufficient for forward, reverse, stop and idle. The states and transitions are shown below.

IDLEstate=0 FORWARDstate=10 REVERSEstate=20 HOLDstate=30 start pos=target pos=target hold elapsed AND continuous continuous=FALSE

State transition table:

Current state Trigger Next state Action
IDLE (0) Start = TRUE FORWARD (10) Issue MC_MoveAbsolute to TargetTop
FORWARD (10) Done = TRUE AND Error = FALSE HOLD (30) Start dwell timer (e.g. 1 s)
HOLD (30) Dwell elapsed REVERSE (20) Issue MC_MoveAbsolute to TargetBot
REVERSE (20) Done = TRUE AND Error = FALSE IF continuous THEN FORWARD (10) ELSE IDLE (0) Loop or stop

Step-by-Step SCL Implementation in TIA Portal

The following SCL code implements the state machine inside a single-instance FB. Drop it into TIA Portal under Program Blocks > Add new block > Function Block > SCL.

FUNCTION_BLOCK "MotorCycleFB"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      EN            : BOOL;        // call enable - hold TRUE
      Continuous    : BOOL;        // TRUE = loop forever
      Start         : BOOL;        // rising edge starts sequence
      TargetTop     : LREAL;       // upper target position (LU)
      TargetBot     : LREAL;       // lower target position (LU)
      Velocity      : LREAL;       // mm/s or rpm per axis scaling
      DwellTime     : TIME;        // pause between strokes
   END_VAR
   VAR_OUTPUT
      Busy          : BOOL;
      Done          : BOOL;
      Error         : BOOL;
      ErrorID       : WORD;
      ActualState   : INT;
      ActualPos     : LREAL;
   END_VAR
   VAR
      State         : INT;         // STAT - survives the cycle
      DwellInst     : TON;         // STAT timer
      MC_Power_0    : MC_Power;
      MC_MoveTop    : MC_MoveAbsolute;
      MC_MoveBot    : MC_MoveAbsolute;
      Axis          : AXIS_REF;
      R_TrigStart   : R_TRIG;
   END_VAR
   VAR_STAT
      CycleCount    : DINT;
   END_VAR
BEGIN
    IF NOT EN THEN
        Busy := FALSE; Done := FALSE; Error := FALSE;
        ActualState := 0;
        RETURN;
    END_IF;

    // Power the axis continuously while EN is high
    MC_Power_0(Axis := Axis, Enable := TRUE, StartMode := FALSE);

    R_TrigStart(CLK := Start);

    CASE State OF
        0:  // IDLE
            ActualState := 0;
            Busy := FALSE; Done := FALSE;
            IF R_TrigStart.Q THEN
                State := 10;
                CycleCount := CycleCount + 1;
            END_IF;
        10: // FORWARD
            ActualState := 10; Busy := TRUE;
            MC_MoveTop(Axis := Axis,
                       Execute := TRUE,
                       Position := TargetTop,
                       Velocity := Velocity,
                       Done => , Busy => , Error => ,
                       ErrorID => );
            IF MC_MoveTop.Done THEN
                MC_MoveTop(Axis := Axis, Execute := FALSE);
                DwellInst(IN := FALSE);
                State := 30;
            ELSIF MC_MoveTop.Error THEN
                Error := TRUE; ErrorID := MC_MoveTop.ErrorID;
                State := 99;
            END_IF;
        20: // REVERSE
            ActualState := 20; Busy := TRUE;
            MC_MoveBot(Axis := Axis,
                       Execute := TRUE,
                       Position := TargetBot,
                       Velocity := Velocity,
                       Done => , Busy => , Error => ,
                       ErrorID => );
            IF MC_MoveBot.Done THEN
                MC_MoveBot(Axis := Axis, Execute := FALSE);
                IF Continuous THEN
                    State := 10;            // loop back to FORWARD
                ELSE
                    Done := TRUE; Busy := FALSE;
                    State := 0;             // stay IDLE
                END_IF;
            ELSIF MC_MoveBot.Error THEN
                Error := TRUE; ErrorID := MC_MoveBot.ErrorID;
                State := 99;
            END_IF;
        30: // DWELL
            ActualState := 30; Busy := TRUE;
            DwellInst(IN := TRUE, PT := DwellTime);
            IF DwellInst.Q THEN
                DwellInst(IN := FALSE);
                State := 20;
            END_IF;
        99: // ERROR - latch until reset
            ActualState := 99;
            // require rising edge on Start to clear
            IF R_TrigStart.Q THEN State := 0; Error := FALSE; ErrorID := 0; END_IF;
    END_CASE;

    // Read current position for HMI / diagnostics
    ActualPos := MC_Power_0.ActualPosition;
END_FUNCTION_BLOCK

Key points that make the cycle run continuously:

  • State is declared as a VAR (static) field, so it retains its value between OB1 cycles.
  • The transition from REVERSE to FORWARD or IDLE is decided by the Continuous input, not by an external signal.
  • EN is used as the only enable; Execute is generated internally inside the state machine.
  • MC_MoveAbsolute is held Execute = TRUE for the entire motion. Dropping Execute on Done is correct and prevents a new motion being requested when state loops back to 10.

Reusing the Siemens LAxisControl Library

For a fully pre-built solution, Siemens publishes the LAxisControl application example as a free download in the Siemens Industry Online Support. It contains:

Block Function Notes
LAxisControl Sequences jog, homing, absolute and relative moves through a unified command interface. Replaces hand-written CASE statements with a single command word.
LAxisControl_Com PLC side of the HMI faceplate. Receives commands from the WinCC Comfort/Advanced faceplate.
LAcycCom Cyclic drive parameter read/write over PROFIdrive acyclic channel. Useful for adjusting drive-side dynamic parameters at runtime.

To integrate, install the example library in TIA Portal via Options > Support Packages > Add and drag the blocks from the master copy library into your project. The continuous-loop behaviour is already implemented; the only parameters you need to set on the HMI faceplate are Continuous = ON and TargetPositionTop / TargetPositionBottom in LU units of the configured technology object.

Watch out: The library version that matches your TIA Portal version must be selected. The 109749348 entry provides versioned downloads for TIA V15.1, V16, V17, V18 and V19. Mixing a V17 library with a V19 project compiles but can change the behaviour of internal timers.

Resolving Position Accuracy Faults on the Down Stroke

The user reported that the motor returns from the down position before reaching it, then immediately reverses up. Three root causes are typical:

  1. Positioning window too tight. The default MC_Power/MC_MoveAbsolute behaviour uses the axis' configured positioning tolerance. If the tolerance is tighter than the actual mechanical resolution (backlash, encoder pitch, lead-screw pitch error), the FB never receives Done. Reduce the tolerance in the technology object under Position monitoring > Positioning tolerance or set Follow-up mode appropriately.
  2. Velocity / acceleration exceeds the drive's tracking capability. When the controller issues Done on the basis of the command position reaching the setpoint but the load has not yet arrived, the FB reverses and the actual position overshoots. Lower the velocity and the acceleration in the technology object or in the drive (SINAMICS p1120, p1121).
  3. Wrong direction sign on the down axis. If TargetBot is set to the same sign as TargetTop, the move finishes in one step and the FB appears to skip the down stroke. Confirm the unit and sign convention: 1 LU = 1 mm (or 1°) as defined in the axis configuration.

Diagnostic sequence to apply in TIA Portal online mode:

  1. Open the watch table AxisMonitor from the project library and observe ActualPosition, ActualVelocity and the status word SW1 / SW2 of the technology object.
  2. If SW1 bit 15 (PositioningComplete) never asserts, the drive never reports the axis as in position. Check drive-side telegram 1 bit 14 on PROFIdrive.
  3. Force Continuous = FALSE and run a single stroke. Capture the trace of ActualPosition vs. time to see whether the axis oscillates around the target (mechanical / control loop) or never reaches it (limit switch / wiring).

Block Interface Best Practices: STAT, INPUT, OUTPUT, IN_OUT

The original post mentions that the tags blockntw and disable_power are defined as STAT with default value 0. STAT is the right location for retentive internal state. The following checklist applies when designing a continuous-run FB:

Section Holds its value across cycles? Used for
VAR_INPUT No - set by caller each cycle Start command, targets, velocities, flags from the HMI.
VAR_OUTPUT No - written by FB Busy, Done, Error, current state, position feedback.
VAR_IN_OUT No - passed by reference AXIS_REF, large data blocks, or structs you want both sides to modify.
VAR (static, the default) Yes - retained in the instance DB State machine variable, edge detectors, internal flags, dwell timer instance.
VAR_TEMP No - reinitialised each call Loop counters, intermediate calculations.

Optimised access (S7-Optimized_Access = TRUE, the default in TIA Portal V17 and later) treats all instance variables symbolically. STAT values are placed in the optimised instance DB and are guaranteed to retain their value between OB1 cycles; TEMP values are placed on the local stack and start at 0 on every call.

Verification, Monitoring and Online Watch Tables

After downloading the project, run the following checks before the system is approved for production:

  1. OB1 scan time. Open Online & Diagnostics > Cycle / clock memory and verify that the worst-case OB1 time stays below 80% of the configured watchdog. The cyclic motor block should add at most a few milliseconds per cycle.
  2. State trace. In the online watch table, add the instance DB tags State, ActualPosition, Busy and Done. Set the trigger on State and confirm that the sequence reads 0 → 10 → 30 → 20 → 10 → 30 → 20 ... when Continuous = TRUE.
  3. Force / simulation. Use PLCSIM or PLCSIM Advanced to step through OB1 with a single-step task. The state machine must advance one state per scan when an MC_Move job returns Done.
  4. Error latch. Force the drive offline (pull the PROFIdrive plug). The Error and ErrorID outputs must latch. A new rising edge on Start must clear them and return the FB to IDLE.
  5. Retentivity test. Stop the CPU, power-cycle the controller and restart. The state should resume at IDLE (default 0), not mid-stroke, because the technology object will home again.

Diagnostic and Troubleshooting Matrix

Symptom Likely root cause Where to look Fix
Sequence runs once, FB latches in Done Continuous flag is FALSE or has been reset Instance DB tag Continuous Hold the operator tag TRUE, or move it to a STAT flag in the HMI tag set.
Sequence never starts EN is FALSE or the call is being skipped Watch EN and the call instance DB Wire EN to a TRUE constant inside OB1; verify the call DB is the same DB shown in the project tree.
Down stroke aborts early TargetBot unreachable - tolerance or wiring Technology object - position monitoring; drive telegram diagnostics Widen positioning tolerance or correct TargetBot sign.
OB1 watchdog trip (SF LED, OB80 entry) Scan time too long for OB1 budget CPU diagnostic buffer Move slow operations (logging, file I/O) to a lower-priority cyclic OB (OB35) or a separate task.
State variable resets every cycle Declared as TEMP or in a wrong instance DB FB interface Move the State to a STAT field in the FB instance DB.
MC_Power returns ErrorID 0x8001 Axis is not ready or encoder not configured Axis configuration, drive diagnostics Check the encoder telegram and PROFIdrive connection.
FB appears to hang in state 99 Error latched, Start rising edge missing Online watch table for Start Confirm Start is a momentary pushbutton, not a maintained switch.

Performance and Safety Considerations

When extending the pattern to multi-axis machines, mind these constraints:

  • OB priority. OB1 is class 1; a higher-priority cyclic OB such as OB35 (class 16) can interrupt OB1. Put coordination state machines in OB1 and time-critical axis processing in OB35 so they can be scheduled deterministically.
  • Multi-instance FBs. Where multiple motors share the same logic, place the cycle FB inside another parent FB and call it as a multi-instance. The state of each instance is then isolated in the parent DB.
  • Safety integration. When the FB is part of a safety function, place the motor enable directly under the Failsafe signal (F-Output) of the safety program, not under standard outputs. The standard FB can request motion, but the F-Output must be TRUE for the drive enable to be wired up.
  • Retain behaviour. In the technology object, set the axis to "retain" the actual position. Otherwise, after a CPU restart the position reference is lost and the first move should always start with MC_Home before the cycle runs.
  • CPU load. Each MC_MoveAbsolute in flight creates an internal axis job. Running the state machine in OB1 at 10 ms and ten motors in parallel is well within an S7-1516's capability; the same load on an S7-1214C is too high and you should move the cycle to a slower task (OB30 with 50 ms).

FAQ

Why does my motor function block run only once and then stop?

Most likely the Execute input is a one-shot pulse, or the Continuous input is FALSE. Wire the FB's EN input to a TRUE source for the full duration, keep Execute driven by the internal state machine, and set the operator tag Continuous = TRUE in the instance DB or HMI.

Should I use EN or Execute to start a Siemens motion FB?

EN is a level-sensitive call enable and must be TRUE for the FB to be processed at all. Execute is a rising-edge trigger that starts a new motion job. For a continuously running motor cycle, keep EN permanently TRUE and use a state machine inside the FB to generate Execute on the next MC block.

My motor reaches the top position but never reaches the down position. What should I check first?

Verify that TargetBot has the correct sign and unit (LU) for your axis. Open the technology object's online diagnostics and check the positioning tolerance, the drive's PROFIdrive status word bit 14 (PositioningComplete) and the actual velocity during the down stroke. If the position oscillates around the target, the tolerance is too tight relative to the mechanical backlash.

Can I use the LAxisControl library instead of writing the state machine myself?

Yes. The Siemens example 109749348 ships a ready-made LAxisControl block that includes jog, homing and absolute moves with a continuous-loop option. Install the support package that matches your TIA Portal version, drag the blocks into your project, configure the AXIS_REF and select Continuous = ON on the HMI faceplate.

How do I keep the FB state across CPU restart?

Declare the state variable and any required flags as STAT inside the FB so they are stored in the instance DB. Enable retentivity on the instance DB under the FB's Properties > Retain if you want the cycle counter and last state to survive a power cycle. Always re-home the axis after restart before resuming the cycle.

Back to blog