Initialization Patterns - Startup Task and ProgramCycle in AX

June 17, 2026 · simatic-axsiemensplc-programmingstartupprogramcyclestructured-textinitializationindustrial-automationcontrol-systems

Initialization Patterns - Startup Task and ProgramCycle in AX

In TIA Portal, the mental model is usually immediate: put one-time startup work in a startup OB, put normal control logic in the program cycle, and use a first-scan flag when startup-adjacent logic needs to live inside the cyclic program.

In SIMATIC AX, I would keep that same engineering split, but I would not translate it mechanically.

The important distinction is this:

  • Startup is the official AX task-library concept for one-time work when the CPU changes from STOP to RUN.
  • ProgramCycle is the official AX task-library concept for OB1-style cyclic execution.
  • A first-cycle pattern inside cyclic code is still useful, but it is not the same thing as a Startup task.

That last point matters because it changes how I would structure initialization in a real AX project.

The official mapping

The current Siemens SIMATIC Tasks documentation for @ax/simatic-tasks 11.0.2 documents Startup and ProgramCycle as named task types.

A startup-style configuration should look like this pattern:

USING Siemens.Simatic.Tasks;

CONFIGURATION Cfg
    TASK StartupTask : Startup;
    TASK MainCycle : ProgramCycle;

    PROGRAM StartupInit WITH StartupTask : StartupProgram;
    PROGRAM CyclicMain WITH MainCycle : MainProgram;
END_CONFIGURATION

That is the public pattern I would document for AX.

The official Startup documentation says the Startup task runs once during the STOP-to-RUN transition. It also states that process image input values are zero during Startup, Startup has no time limit, and ProgramCycle starts after the assigned Startup programs complete.

The official ProgramCycle documentation maps it to OB1/program-cycle execution. It is the lowest-priority cyclic task type, can be interrupted by other tasks, and starts after Startup has completed. The same docs describe the automatic PIP0 input update before the cycle and PIP0 output update after the cycle.

Sources are listed at the end, with links to the Siemens task pages used for this article.

Do not turn Startup into T#0ms

One pattern I specifically checked was this:

TASK StartupCandidate(Interval := T#0ms, Priority := 1);

In my local compiler probe, AX accepted that as generic task syntax. That is not enough evidence to call it a Startup task.

The current Siemens task-library documentation does not describe Interval := T#0ms as the Startup pattern. It documents:

TASK MyStartupTask : Startup;

So I would not publish Interval := T#0ms as an AX Startup-task mapping. At best, it is a compiler-accepted generic task declaration that still needs runtime and documentation proof before it belongs in a public pattern.

Where startup work belongs

I would use a Startup task for work that should happen once before the cyclic program begins:

  • Loading or copying startup configuration into application state.
  • Setting startup diagnostics.
  • Initializing non-cyclic control state that must exist before the main cycle starts.
  • Handling startup information such as retentive-data or real-time-clock loss when the project reads that startup information explicitly.

I would avoid relying on live process image input values in Startup, because the official Startup docs say those input values are zero during Startup.

I would also avoid scattering ordered startup work across multiple Startup tasks or multiple programs assigned to one Startup task. Siemens documents that sequence as not deterministic. If order matters, put the ordered calls inside one startup program and make the order visible in code.

Where first-cycle work belongs

A first-cycle pattern still has a place.

It belongs inside cyclic logic when the work is naturally part of the cyclic program and should be easy to unit test. For example:

  • Setting an application operating mode the first time cyclic logic runs.
  • Running initialization that depends on cyclic FB instance state.
  • Keeping the local unit-test path simple when the initialization belongs inside cyclic execution.

In the demo project, I used a small FirstCycleInitializer function block for that purpose.

Local cyclic task configuration

This screenshot shows the local demo configuration that compiled successfully with the cached AX SDK. It uses the compiler-proven generic cyclic configuration from the demo, while the official Startup and ProgramCycle task types are documented by Siemens.

Startup program body

Siemens documents Startup as the task type for code that should run once during the STOP-to-RUN transition. In this demo, the same initialization logic is also shown as a first-cycle fallback pattern, which was compiled and tested locally.

First-cycle initializer

This screenshot shows the reusable cyclic first-cycle pattern. It performs first-cycle work once, then continues updating cyclic state every call.

AxUnit test for first-cycle behavior

This screenshot shows the AxUnit test that checks the first call and second call behavior. The test passed locally from a no-spaces path copy of the demo project.

What I proved locally

The local demo project builds for the cached S7-1500 and LLVM targets with AX ST compiler V11.4.57.50967.

The AxUnit test for FirstCycleInitializer passes:

  • first call sets the first-cycle flag, cyclic flag, cycle counter, and operating mode;
  • second call increments the cycle counter without repeating the first-cycle initialization.

That proves the first-cycle pattern as local AX code. The official Startup and ProgramCycle task behavior comes from Siemens documentation, while the local proof covers the initialization logic and first-cycle fallback code that built and tested successfully.

My current rule

For AX initialization, I would use this rule:

Use Startup for true startup work.

Use ProgramCycle for normal cyclic execution.

Use a first-cycle function block inside ProgramCycle when the logic belongs to cyclic execution or needs straightforward unit testing.

Do not publish Interval := T#0ms as a Startup task unless you can prove it from current Siemens documentation or runtime behavior.

That is the cleanest AX version of the old TIA Portal instinct: separate one-time startup, cyclic scan logic, and first-scan convenience instead of letting them collapse into one vague initialization bucket.

Discussion on LinkedIn: Startup, ProgramCycle, and first-cycle initialization in SIMATIC AX.

Sources Used

Planning a new project? Message us to see how we can help.