Siemens FB41 CONT_C PID on S7-300: OB35 Setup and SF Error Fix

David Krause13 min read
PID ControlSiemensTutorial / 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: FB41 CONT_C in the S7-300 / S7-400 PID Toolbox

The FB41 CONT_C block is the continuous-action PID controller distributed with STEP 7 V5.x in the Standard Library > PID Control Blocks (or stdlib > fb41 in some installer trees). It is the workhorse single-loop PID used on S7-300 CPUs such as the CPU 313, CPU 314, CPU 315-2 DP, and the entire S7-400 family. CONT_C is implemented as a function block (FB), not a system function block (SFB) — every call requires an instance data block (DB) that stores the controller's persistent parameters (setpoint, process value, tuning, integrator state, derivative state, outputs).

CONT_C is designed to operate as a fixed-point mathematical PID with the option to disable any of the three terms, giving you a usable P, PI, PD, or full PID configuration from a single block. Inputs and outputs are normalized to the floating-point range 0.0 ... 1.0 (or -1.0 ... +1.0 in bipolar modes), and the block assumes the upstream analog input module (e.g. SM331, SM332, or a CPU-integrated AI on the 31xC series) has already been scaled to that range.

The official Siemens application note for the FB41 family is documented in the Standard PID Control manual bundled with STEP 7 and in the Siemens SiePortal — PID FB41 CONT_C thread. A worked sample project with adaptation notes for S7-300 is referenced in Siemens SiePortal — FB41 PID example.

Prerequisites Before Calling FB41

  1. STEP 7 V5.x programming package with the PID Control Blocks library installed (FB41, FB42, FB43, FB58, FB59, plus their help PDFs).
  2. Hardware configuration containing an analog input (AI) and analog output (AQ) channel. On a CPU 313 with no on-board AI, you need an SM331 AI8 module and an SM332 AO2/AO4 module, or a CPU 31xC variant with on-board I/O.
  3. OB1 (main scan) and at least one OB35 (cyclic time-of-day interrupt) configured at 100 ms (default). The PID math MUST run at a deterministic interval — calling FB41 only from OB1 with a variable OB1 scan will cause integrator wind-up, derivative spikes, and unstable tuning.
  4. Instance DB for FB41 (auto-generated on first download, or pre-created manually). Symbolic name assignment is recommended so the integrator state can be monitored from the VAT table.
  5. Process-side hardware: a transducer (e.g. Pt100 + SM331 RTD module, or 4…20 mA temperature transmitter) for the PV, and a final control element (proportional valve, SCR power controller, VFD speed reference) wired to the analog output.
Critical: If you are on STEP 7 V5.1 or later and starting a new project, Siemens documentation recommends FB58 instead of FB41. FB41 is retained for legacy support and for customers migrating S5 code. Continue with FB41 only if you have existing code, training material, or plant standardisation reasons — otherwise jump to the Comparison with FB58 section.

FB41 Call Structure: OB35 + Instance DB

The standard pattern is to instantiate one FB41 per control loop, called from OB35 at a fixed 100 ms tick. OB35 is part of the S7-300/400 system resources and is always available — you simply set its phase offset and execution period in HW Config > CPU Properties > Cyclic Interrupts. The 100 ms default matches the recommended sampling period for slow thermal loops (temperature, level, slow pressure).

ST sample (OB35):

// OB35 - 100 ms cyclic interrupt
CALL FB41, DB41       // CONT_C PID controller
   PV_IN   := "Tank".PV_NORM      // REAL 0.0..1.0 (scaled PV)
   SP_INT  := "Tank".SP_VALUE     // REAL 0.0..1.0 (setpoint)
   MAN     := "Tank".MAN_VALUE    // REAL 0.0..1.0 (manual input)
   GAIN    := "Tank".Gain         // REAL e.g. 5.00
   TI      := T#2s                // Reset time (integral)
   TD      := T#1s                // Derivative time
   LMN_HLM := 100.0               // Manipulated value high limit %
   LMN_LLM := 0.0                 // Manipulated value low limit %
   PV_FAC  := 1.0
   PV_OFF  := 0.0
   SP_FAC  := 1.0
   SP_OFF  := 0.0
   DEADB_W := 0.0                 // Dead band width
   I_ITL_ON:= FALSE               // Initialise integrator on cold start?
   I_ITLVAL:= 0.0
   PULSE_TM:= T#0s                // Pulse output (unused, leave 0)
   CYCLE   := T#100ms             // MUST match OB35 period
   LMN     := "Tank".LMN_OUT      // REAL 0.0..100.0 (% manipulated value)
   LMN_PER := "Tank".LMN_PER      // REAL 0.0..1.0 (peripheral output)
   QLMN_HLM:=                      // BOOL high-limit reached
   QLMN_LLM:=                      // BOOL low-limit reached
   ER      :=                      // REAL effective error
END_CALL

Notes on the call:

  • CYCLE MUST be set to the same value as the OB35 period (T#100 ms by default). If the OB35 period is changed in HW Config, CYCLE must be updated.
  • The Instance DB (DB41 in this example) is created automatically on first download; assigning a symbolic name like Tank in the symbol table lets you monitor Tank.Gain, Tank.TI, etc. as if they were normal tags.
  • For a single-input / single-output temperature loop, you wire LMN (0…100 % engineering units) directly to your analog output channel via FC106 (unscale), or use LMN_PER (already normalised 0…1.0) and let the AO module scale it to 0…10 V or 4…20 mA.

Key FB41 Parameters — Reference Table

Parameter Type Range / Unit Purpose
PV_IN REAL (IN) 0.0 … 1.0 Process variable input. Already scaled by FC105/FC106 or by hardware scaling.
SP_INT REAL (IN) 0.0 … 1.0 Internal setpoint. Compare against PV_IN.
MAN REAL (IN) 0.0 … 1.0 Manual manipulated value, used when MAN_ON is TRUE.
GAIN REAL (IN) Typically 0.05 … 20.0 Proportional gain. Increase for faster response; decrease for stability.
TI TIME (IN) T#0s disables I Reset (integral) time. Smaller = faster integration.
TD TIME (IN) T#0s disables D Derivative time. Larger = stronger derivative action.
DEADB_W REAL (IN) 0.0 … 1.0 Dead-band on the error signal. Suppresses chatter on noisy PVs.
I_ITL_ON BOOL (IN) TRUE / FALSE If TRUE, integrator is initialised to I_ITLVAL on the next scan.
CYCLE TIME (IN) Match OB35 Sample time. MUST equal the OB35 period.
LMN_HLM / LMN_LLM REAL (IN) Engineering units % Manipulated value high/low clamp.
LMN REAL (OUT) 0.0 … 100.0 % Manipulated value in percent. Most common tag for scaling to mA/V.
LMN_PER REAL (OUT) 0.0 … 1.0 Manipulated value normalised for direct output to an AO channel.
ER REAL (OUT) Signed % Effective error after setpoint and PV scaling.
QLMN_HLM / QLMN_LLM BOOL (OUT) TRUE / FALSE Manipulated value has hit its clamp; useful for anti-windup logic.
LMN_P / LMN_I / LMN_D REAL (OUT, STAT) % Individual P, I, D contributions. Read-only diagnostics for tuning.

Wiring FB41 to a Temperature Loop

For the canonical single-input / single-output temperature loop on a reaction vessel, the signal chain is:

  1. Temperature transmitter (Pt100 or thermocouple with head transmitter) outputs 4…20 mA to SM331 channel 0.
  2. SM331 AI is configured for 4-wire RTD or ±10 V, and the raw integer word is read by FC105 (SCALE) which converts it to REAL engineering units, e.g. 0.0 … 200.0 °C.
  3. To feed FB41 you then re-normalise to 0.0 … 1.0 either with a second scale call or by using PV_FAC and PV_OFF on the block: PV_internal = PV_FAC * PV_eng + PV_OFF.
  4. The setpoint is held in a DB tag such as Tank.SP_ENG in °C and scaled to 0…1.0 the same way.
  5. FB41 outputs LMN in 0…100 %; you scale that to your analog output channel — e.g. 0…10 V valve actuator, where 0 V = closed, 10 V = fully open — with FC106 (UNSCALE).

Practical example — reaction vessel heating:

  • PV range: 0…200 °C, transmitter 4…20 mA
  • Setpoint: 80 °C
  • Control valve: 0…10 V proportional steam valve
  • Starting tuning: GAIN = 1.0, TI = T#60s, TD = T#0s (PI only for first pass)
  • OB35 period: 100 ms

Resolving the SF Software Error LED

The most common first-time fault on an FB41 program is the SF (System Fault) LED on the CPU, combined with a STOP or RUN-with-error condition. The root causes fall into three buckets:

Root Cause 1 — OB35 Not Configured or Not Loaded

If you compiled and downloaded a program that calls FB41 from OB1 (or you simply did not include OB35), the CPU will execute the block but the integrator will accumulate state inconsistently because the scan interval is non-deterministic. In some firmware revisions of the CPU 313 / CPU 314 this surfaces as an SF LED plus a diagnostic buffer entry "OB not loaded" or "OB35 missing".

Fix: Open HW Config > CPU Properties > Cyclic Interrupts. Set OB35 to a 100 ms execution period (default). Click Generate on the cyclic interrupt and confirm that OB35 appears under Program > Blocks in SIMATIC Manager. Re-download the entire program.

Root Cause 2 — CYCLE Parameter Mismatch

If you set OB35 to 200 ms but FB41's CYCLE input remains T#100ms, the integrator math runs twice per OB35 pass — not because the algorithm is wrong, but because FB41 treats CYCLE as the basis for its integrator update. Mismatch by itself usually does not throw an SF, but it does create tuning instability that later gets flagged if the CPU enters diagnostic interrupt (OB82) for other reasons.

Fix: Keep CYCLE and the OB35 period identical. For temperature loops, T#100ms is the standard Siemens recommendation; faster loops (flow, pressure) can drop to T#20ms via OB35.

Root Cause 3 — Block Version or Library Mismatch

FB41 shipped with STEP 7 V5.x is version-controlled. If you copy an old FB41 from an S5 project or a third-party archive that pre-dates your STEP 7 installation, the FUB signature can conflict with the Standard Library, and the CPU raises an SF "Parameter error in FB41" or "Block version conflict" on first OB35 pass.

Fix: Delete the imported FB41 from the project, open Libraries > Standard Library > PID Control Blocks, and drag FB41 fresh into Program > Blocks. Recompile and re-download. The version stamp should now match the installed STEP 7 service pack.

Diagnostic buffer inspection: Connect online with STEP 7, open the CPU's Diagnostic Buffer (PLC > Module Information > Diagnostic Buffer). The most recent fault entries decode the exact OB and stack pointer that raised the SF. This is the single fastest way to distinguish the three root causes above.

Verification — Step-by-Step Commissioning

  1. Monitor online: Right-click the FB41 instance DB, choose Monitor/Modify. Confirm PV_IN tracks the live scaled process variable and SP_INT matches your commanded setpoint.
  2. Open-loop check: Set MAN_ON := TRUE and force MAN := 50.0. Verify that the analog output on the field side reads 50 % of span (e.g. 12 mA on a 4…20 mA loop, or 5 V on 0…10 V). If the field value is wrong, the issue is in the AO module wiring, not in FB41.
  3. Closed-loop step test: Set MAN_ON := FALSE, pick a small setpoint step (e.g. 60 → 65 °C). Watch LMN_P, LMN_I, LMN_D in the VAT. A healthy loop shows an immediate LMN_P bump, a smooth LMN_I ramp, and (if TD > 0) a transient LMN_D spike on the step edge.
  4. Tuning pass: Use the Ziegler-Nichols closed-loop method — start with TD := T#0s, set TI to maximum (T#10000s), raise GAIN until the loop oscillates at a constant amplitude. Record the ultimate gain Ku and oscillation period Tu. For PI control, set GAIN = 0.45 * Ku, TI = 0.8 * Tu.
  5. Anti-windup check: Drive the output into a clamp (QLMN_HLM = TRUE) and confirm that the integrator stops accumulating. If LMN_I keeps growing while LMN is clamped, you have integrator wind-up; the fix is to feed QLMN_HLM / QLMN_LLM back into a custom anti-windup wrapper or to reduce TI.
  6. LED verification: After the loop is stable for one full minute, confirm the CPU's SF LED is OFF and the diagnostic buffer has no new entries.

Comparison: FB41 vs FB58 (When to Migrate)

FB58 (TCONT_CP, continuous PID with pulse generator) was introduced in STEP 7 V5.1 specifically to replace FB41 for new projects. Key differences:

Feature FB41 CONT_C FB58 TCONT_CP
STEP 7 minimum version STEP 7 V3.x (legacy) STEP 7 V5.1 SP3+
Operator interface None (manual VAT) Built-in faceplate on instance DB (double-click DB)
Auto-tuning No PID Self-Tuner support
Derivative filter Basic Improved PT1 derivative filter
Pulse output for heating/cooling No (use FB42 or FB43) Yes (built-in)
Manual / auto bumpless transfer Basic Improved, with tracking
Diagnostic interrupts on error Limited Extended, with structured error word
Recommended for new S7-300 designs No Yes

Migration path: copy FB41 instance DB contents into a new FB58 instance, then re-tune because the integrator and derivative algorithms are not bit-for-bit compatible. Plant downtime is typically 30–60 minutes per loop.

Tuning Notes for Temperature Loops

Temperature loops are dominated by large dead time and a slow first-order lag (the thermal mass of the vessel). Standard starting points:

Loop type GAIN TI TD
Jacket heating, water bath 0.5 – 2.0 30 s – 2 min 0 (PI sufficient)
Jacketed chemical reactor 0.2 – 1.0 1 min – 5 min 10 s – 30 s
Electric furnace (PWM) 1.0 – 5.0 20 s – 1 min 0–5 s
Heat exchanger, secondary side 0.5 – 3.0 15 s – 1 min 0–10 s
Safety: For an exothermic reaction, do not rely on a single PID loop for safety. Provide an independent over-temperature interlock (e.g. safety PLC, mechanical pressure relief, or hardwired thermostat) per IEC 61511 / IEC 61508 SIL requirements. The FB41 loop is a regulatory controller, not a safety instrumented function.

Locating PID Settings in an Existing Project

When you inherit an undocumented S7-300 program with many FBs, DBs and FCs and you need to identify the PID loop, the standard search procedure is:

  1. In SIMATIC Manager, choose Options > Cross References, then search for symbol FB41. This lists every block and network that calls CONT_C.
  2. Open each calling block (typically OB35 or OB1) and note the instance DB number paired with the FB41 call — that is your PID loop's tuning DB.
  3. Open the instance DB in Data View. Columns such as GAIN, TI, TD, SP_INT, PV_IN, LMN are now visible with their current values.
  4. If symbolic names were never assigned, you can assign them retroactively by opening Options > Symbol Table, locating the DB, and adding an entry like Tank_GainDB41.DBDxx (offset where GAIN lives).

FAQ

Why does the SF LED come on immediately after I download my FB41 program?

The three most common causes are: OB35 is not loaded on the CPU, the CYCLE input on FB41 does not match the OB35 period (it must be T#100 ms by default), or the imported FB41 block has a version stamp that conflicts with your STEP 7 installation. Open the diagnostic buffer to see which OB raised the fault, then fix the corresponding configuration.

Can I call FB41 from OB1 instead of OB35?

Technically yes, but it is not recommended. OB1 scan time varies with program size, so the PID integrator will accumulate state inconsistently and tuning will drift. Always call FB41 from OB35 at a fixed 100 ms tick for temperature loops, or from OB32/OB33/OB34 for faster loops.

What is the difference between LMN and LMN_PER?

LMN is the manipulated value in percent (0…100 % engineering units) and is what you normally scale to mA/V with FC106. LMN_PER is the same value already normalised to 0…1.0 and can be written directly to an analog output peripheral (AQW) without further scaling, which is slightly faster.

Should I use FB41 or FB58 on a new S7-300 project?

Use FB58 (TCONT_CP) on STEP 7 V5.1 SP3 or later. FB58 includes a built-in operator faceplate, an improved derivative filter, optional PID Self-Tuner support, and better bumpless manual/auto transfer. FB41 is still maintained for legacy code and S5 migration paths but is not the recommended choice for new designs.

How do I tune FB41 for a temperature loop on a reaction vessel?

Start with PI only (TD = T#0s), set TI to T#60s, and GAIN to 1.0. Run a closed-loop step test, then use Ziegler-Nichols: raise GAIN until the loop oscillates at constant amplitude, record the ultimate gain Ku and period Tu, then set GAIN = 0.45 * Ku and TI = 0.8 * Tu. Verify that the integrator does not wind up when the output clamps, and always pair the regulatory loop with an independent over-temperature safety interlock.

Back to blog