Problem Description
A Step 7 Professional V5.5 project is calling the standard PID block FB41 "CONT_C" from a cyclic interrupt organization block OB35 configured at 100 ms. The instance DB2215 shows all inputs wired, the setpoint (SP_INT) is 30, the process variable (PV_IN) is fed from a scaled analog input, and the manipulated value (LMN) is monitored online. Instead of ramping toward saturation as a textbook PI controller should, LMN sits at a flat value equal to the error (ER) multiplied by the gain. Changing GAIN from 0.01 to 10 shifts LMN from 0.1606 to 1.606 — exactly the proportional-only formula LMN(t) = I_ITLVAL + GAIN · ER_NORM(t) documented in the Siemens Standard PID Control manual (page 4-41). No integration windup, no derivative action, and no movement despite a sustained error.
This is one of the most common FB41 field failures on S7-300/S7-400 CPUs, and the symptoms almost always trace to one of three root causes: the integrator and derivative paths are disabled through I_SEL/D_SEL, the COM_RST pulse never reaches the block long enough to initialize the integrator, or MAN_ON is latched forcing the output to follow MAN instead of the PID algorithm. The remainder of this article walks through each root cause, the exact procedure to recover control, and the verification checks that prove the controller is alive.
FB41 CONT_C Architecture Overview
FB41 "CONT_C" is a continuous-action PID controller with one analog setpoint input, one analog process-value input, one analog manipulated-value output, and a manual/automatic mode toggle. Internally it implements the block diagram published in the Standard PID Control manual:
- Setpoint branch:
SP_INT→ setpoint limiter → SP-format conversion - Process-value branch:
PV_INorPV_PER→ PV-NORM → CRP_IN range conversion - Error formation:
ER = SP_NORM − PV_NORM(with optional dead-bandDEADB_W) - Three parallel paths multiplied by select switches: P-path (always on), I-path (
I_SEL), D-path (D_SEL) - Integrator with
I_ITLVALpre-load,I_ITL_ONenable, andINT_HOLDfreeze - Differentiator with
T_Dtime andTD_FLTfilter - Output scaler with
LMN_FAC/LMN_OFF,LMN_HLM/LMN_LLMclamps, and finalLMN/LMN_P/LMN_I/LMN_Doutputs
The key equation that explains the observed behavior is the normalized proportional path:
LMN(t) = I_ITLVAL + GAIN · ER_NORM(t) (with I_SEL = 0 and D_SEL = 0)
When I_SEL = 0 the integrator is bypassed entirely and LMN collapses to the proportional-only result. When D_SEL = 0 the derivative path is bypassed. With PV_IN stuck at a constant and a constant setpoint, ER is constant, and the output is a flat number. This is mathematically correct behavior for a P-only controller — not a bug.
COM_RST, MAN_ON, or the integrator selector, monitor SP_INT, PV_IN, ER, LMN_P, LMN_I, and LMN_D in a VAT. If LMN_I never changes while ER is non-zero, the integrator is disabled or has been reset. If LMN follows MAN exactly, MAN_ON = TRUE is the cause regardless of what the integrator is doing.
Root Cause 1 — Integrator and Derivative Are Disabled
The single most common reason a "PID" block on FB41 behaves like a P controller is that the integrator and/or differentiator are turned off through the selector inputs. With I_SEL = 0 the I-term contribution LMN_I stays frozen at the pre-load value I_ITLVAL; with D_SEL = 0 the D-term stays at 0. The expected action — LMN ramping to saturation while a constant error exists — is impossible without an integrator.
Required Parameter Settings
| Input | Meaning | Value for Full PID | Value for PI | Value for P-only (current state) |
|---|---|---|---|---|
I_SEL |
Enable integrator | TRUE (1) | TRUE (1) | FALSE (0) |
D_SEL |
Enable differentiator | TRUE (1) | FALSE (0) | FALSE (0) |
GAIN |
Proportional gain | Process-tuned | Process-tuned | 0.01 (current) |
TI |
Integral time (s) | Process-tuned | Process-tuned | Ignored |
TD |
Derivative time (s) | Process-tuned | Ignored | Ignored |
To reproduce the expected "LMN ramps to 100 % with constant error" behavior described in the field report, set I_SEL = TRUE while keeping D_SEL = FALSE. The integrator will then accumulate (GAIN · ER) / TI every block call. At OB35 = 100 ms the block is called every 100 ms, so an integral time of 1000 s accumulates 0.01 % of the proportional output per call for a step error of 100 % — the textbook ramp behavior.
TI units. TI is in seconds, not milliseconds. A TI of T#1s is 1.0 s, while a value of T#0s disables integration internally (the Standard PID Control manual documents this division-by-zero guard). TI must be greater than 0 for any integrator action.
Root Cause 2 — COM_RST Pulse Never Reaches the Block
FB41 initializes its internal integrator, differentiator, and the displayed LMN pre-load only when the COM_RST input is TRUE at the start of a call. The Siemens FAQ "What should you watch out for when calling and assigning parameters to the controller functions (S)FB41, (S)FB42, and (S)FB43?" states explicitly that COM_RST must be TRUE for one (and only one) call to trigger the initialization. If it is held TRUE for the entire run-up, or never becomes TRUE at all, the block can remain in a partially initialized state where the output never reaches expected operating points.
The recommended field pattern is:
- Create
OB100(warm restart). InsideOB100, set aBOOLtag (e.g."InitPID") to TRUE. - In
OB1, call FB41 withCOM_RST := "InitPID"and at the very last network ofOB1reset"InitPID"to FALSE. - On a STOP→RUN transition the order of execution is:
OB100runs to completion first, thenOB1begins. WhenOB1reaches FB41 on its first scan,COM_RSTis TRUE, the block initializes, and the trailing network inOB1clearsCOM_RSTfor all subsequent calls.
This pattern is sometimes called the "single-pulse COM_RST" and is the only documented correct usage. Holding COM_RST TRUE permanently causes FB41 to re-initialize every scan, which prevents LMN from following the PID algorithm between resets and locks the integrator to I_ITLVAL. The field report's manual edit-and-download approach (open the instance DB, set COM_RST = TRUE, download) is not equivalent to a controlled single-pulse reset because the online write does not affect the static variables inside the multi-instance nor does it synchronize with the OB35 call timing.
Recommended Code Snippet
// OB100 - Warm restart
SET
S "InitPID" // COM_RST pulse flag
// OB1 - cyclic program
// Network 1: call PID
CALL FB41, DB2215
COM_RST := "InitPID"
MAN_ON := FALSE
I_SEL := TRUE
D_SEL := FALSE
SP_INT := 30.0
PV_IN := "ProcessValue"
GAIN := 0.5
TI := T#5s
TD := T#0s
LMN := "ActuatorOutput"
// ...
// Network 99: clear COM_RST pulse (LAST network in OB1)
A "InitPID"
R "InitPID"
Root Cause 3 — MAN_ON Latched to TRUE
If MAN_ON is TRUE, FB41 routes the value at input MAN directly to LMN and freezes the integrator at its current value. This is the manual-mode override and is the second most common cause of a stuck LMN. The block diagram shows a switch that selects between the PID output and the manual value; with MAN_ON = TRUE the switch stays in the manual position indefinitely until the user toggles it back to automatic.
Verify the MAN_ON state in a VAT and confirm it returns FALSE on every call. If the program logic drives MAN_ON from an HMI button or a sequence step, audit the tag that feeds it — a sticky HMI bit, a non-volatile flag, or a forgotten initialization in OB100 can leave the controller in manual across reboots.
OB35 Cycle Time Verification
The FB41 instance's CYCLE parameter sets the block's expected sampling time and is used for the discrete-time integration algorithm. The Siemens manual recommends that CYCLE match the actual call interval of the OB in which FB41 runs. The field report asks how to verify the OB35 cycle time — the answer is twofold:
-
Hardware configuration: open
HW Config, navigate to the CPU properties, and check the Cyclic Interrupts tab.OB35has its own period field. A value of 100 000 µs corresponds to 100 ms. Confirm this matches the program expectation. -
Runtime measurement: use a VAT to monitor the system clock or a counter incremented inside
OB35. A common pattern is:// OB35 L "OB35Counter" // DWORD + 1 T "OB35Counter" // counts callsRead
OB35Counteratt0, wait 60 s, read it again att1. The delta should equal 600 for a 100 ms period. Deviations above 5 % indicate the cyclic interrupt is being delayed by longer OBs (typicallyOB1in error or oversized) or by the CPU scan-time watchdog.
CYCLE in the FB41 instance is set to T#1s but the block is called every 100 ms, the discrete-time integral accumulates ten times faster than expected. The opposite mismatch (block called every 1 s but CYCLE = T#100ms) makes the integrator ten times slower. Always align CYCLE with the OB35 period in the instance DB at download time.
Step-by-Step Recovery Procedure
Use this procedure to bring a stuck FB41 instance back to a working PI/PID loop.
-
Online open the instance DB (
DB2215in the field report) and put the CPU in STOP if you intend to make structural changes. -
Open a VAT on
DB2215. Monitor the following addresses continuously during every test step:-
DB2215.DBD12—SP_INT -
DB2215.DBD16—PV_IN -
DB2215.DBD20—ER(calculated internally; visible at offset 22 per Siemens instance layout) -
DB2215.DBD68—LMN -
DB2215.DBD72—LMN_P -
DB2215.DBD76—LMN_I -
DB2215.DBD80—LMN_D
-
-
Confirm the formula: with the current parameter set (
GAIN = 0.01,I_SEL = 0,D_SEL = 0), verify thatLMNequalsER × GAINto four decimal places. If yes, the proportional path is healthy and only the integrator is missing. -
Enable the integrator by setting
I_SEL := TRUEin the instance and forcing the value online. Re-verify:LMN_Ishould now begin ramping in the direction ofER. -
Add the COM_RST pulse following the OB100/OB1 pattern. Download in STOP, restart, and confirm
LMN_Istarts fromI_ITLVAL(default 0.0) on the very firstOB35call after restart. -
Verify the OB35 period with the counter method above. Adjust
CYCLEin the instance if needed. - Confirm MAN_ON is FALSE at every call. If an HMI drives it, audit the button logic.
-
Force a step response: change
SP_INTonline by 20 %, observeLMNtracking with the expected integral ramp and eventual saturation atLMN_HLM/LMN_LLM.
FB41 Parameter Reference Table
| Parameter | Direction | Type | Default | Purpose |
|---|---|---|---|---|
COM_RST |
IN | BOOL | FALSE | Complete restart; TRUE for one call initializes the block |
MAN_ON |
IN | BOOL | TRUE | Manual mode toggle — TRUE routes MAN to LMN
|
SP_INT |
IN | REAL | 0.0 | Setpoint in normalized range (0–100 % typical) |
PV_IN |
IN | REAL | 0.0 | Process variable, normalized |
PV_PER |
IN | INT | 0 | Process variable, peripheral (raw ADC value) |
DISV |
IN | REAL | 0.0 | Disturbance variable for feed-forward |
INT_HOLD |
IN | BOOL | FALSE | Freeze integrator output |
I_SEL |
IN | BOOL | TRUE | Enable integrator |
I_ITL_ON |
IN | BOOL | FALSE | Use I_ITLVAL as initial integrator value |
I_ITLVAL |
IN | REAL | 0.0 | Initial integrator value (used when I_ITL_ON and COM_RST fire) |
D_SEL |
IN | BOOL | FALSE | Enable differentiator |
CYCLE |
IN | TIME | T#1s | Block sample time; must match the calling OB period |
GAIN |
IN | REAL | 2.0 | Proportional gain |
TI |
IN | TIME | T#20s | Integral time (reset time) |
TD |
IN | TIME | T#10s | Derivative time |
TM_LAG |
IN | TIME | T#2s | Derivative low-pass time |
DEADB_W |
IN | REAL | 0.0 | Error dead-band width |
PV_FAC |
IN | REAL | 1.0 | PV multiplication factor |
PV_OFF |
IN | REAL | 0.0 | PV offset |
LMN_FAC |
IN | REAL | 1.0 | Output scaling factor |
LMN_OFF |
IN | REAL | 0.0 | Output offset |
LMN_HLM |
IN | REAL | 100.0 | Output high clamp |
LMN_LLM |
IN | REAL | 0.0 | Output low clamp |
MAN |
IN | REAL | 0.0 | Manual manipulated value |
LMN |
OUT | REAL | — | Manipulated value output (real) |
LMN_P |
OUT | REAL | — | Proportional component |
LMN_I |
OUT | REAL | — | Integral component |
LMN_D |
OUT | REAL | — | Derivative component |
PV |
OUT | REAL | — | Process value (after PV_FAC/PV_OFF) |
ER |
OUT | REAL | — | Effective error signal |
STAT Variable Reference (Instance DB Layout)
The STAT section of the instance DB holds the integrator accumulator and the differentiator state. These are the addresses engineers usually want to inspect when FB41 behaves abnormally. The exact offsets depend on the FB41 source version; the values below correspond to the Standard Library FB41 shipped with Step 7 V5.5 and SCL/ STL calling convention.
| Symbolic name | Type | Purpose |
|---|---|---|
LMN_P |
REAL | Proportional contribution; equals GAIN · ER
|
LMN_I |
REAL | Integrator state. Watch this to confirm integration is alive |
LMN_D |
REAL | Derivative contribution; depends on d/dt of ER
|
PV |
REAL | Process value after CRP_IN scaling |
ER |
REAL | Error = SP_NORM − PV_NORM, after dead-band |
INT_HPOS |
BOOL | Integrator upper limit reached |
INT_HNEG |
BOOL | Integrator lower limit reached |
SP_NORM |
REAL | Normalized setpoint |
PV_NORM |
REAL | Normalized process value |
LMN_I first. The fastest way to determine whether FB41 is integrating at all is to put LMN_I in a VAT watch, hold a constant error of 30 % for 60 s, and verify that LMN_I moves in the expected direction. A flat LMN_I confirms that the integrator is disabled, the TI value is wrong, or the integrator was reset to I_ITLVAL and held there.
Verification with a VAT Table
The VAT (Variable Table) tool inside Step 7 is the only practical way to diagnose FB41 in real time. Build a single watch table that includes the following rows in monitor/modify format:
Address Symbol Display Modify value
DB2215.DBX0.0 COM_RST BOOL -
DB2215.DBX0.1 MAN_ON BOOL -
DB2215.DBX0.2 I_SEL BOOL -
DB2215.DBX0.3 D_SEL BOOL -
DB2215.DBD12 SP_INT FLOAT 30.0
DB2215.DBD16 PV_IN FLOAT -
DB2215.DBD68 LMN FLOAT -
DB2215.DBD72 LMN_P FLOAT -
DB2215.DBD76 LMN_I FLOAT -
DB2215.DBD80 LMN_D FLOAT -
DB2215.DBD84 ER FLOAT -
MW100 OB35Counter DEC -
Power-cycle the CPU so OB100 runs. Confirm the COM_RST pulse is observed for exactly one scan of OB1 (visible as a single rising edge in DB2215.DBX0.0). Apply a step setpoint change. Verify the time-domain response matches the expected first-order-plus-dead-time behavior of the plant.
Common Pitfalls and Field-Proven Caveats
- Calling FB41 in OB1 instead of a time-interrupt OB. OB1 scan time is variable on S7-300/400; the discrete-time integral will produce jittery control. Use OB32, OB33, OB34, or OB35 — the dedicated cyclic interrupt OBs whose periods are guaranteed.
-
FB41 multi-instance aliasing. If the project uses a multi-instance FB that calls FB41 internally, the
COM_RSTpulse must reach the inner instance. Place the reset in the calling FB, not in OB1 alone. -
Block call inside a conditional network. A FB41 call inside an
IFcondition that is not always TRUE effectively skips the integrator update on missed scans, causing windup or non-deterministic behavior. - OB35 priority conflicts. OB35 has priority class 12 by default. If OB1 is in RUN and an error OB (OB80–OB87) fires, OB35 may be delayed. Monitor the diagnostic buffer for OB80 "time error" events.
-
Spurious COM_RST from an HMI. If an HMI tag maps to
COM_RSTand the operator toggles a button, the integrator resets toI_ITLVAL. Use an HMI-tag-to-COM_RST path with a confirmed-clear after the single pulse. -
Watch the floating-point format. Inputs and outputs are
REAL(IEEE-754 single precision). A connection from anINTanalog input (such asPEW272) without first converting throughFC105"SCALE" or itsREAL-equivalent will feed nonsense intoPV_IN. -
CYCLE in instance vs. OB35 period. Step 7 V5.5 does not auto-update
CYCLEfrom HW Config. Set it manually to match the OB35 period or to a known fixed value for documentation. -
Watch for
LMN_HLMandLMN_LLMclamping. A symmetric ±100 % bipolar actuator setup needsLMN_HLM = 100.0andLMN_LLM = -100.0. The defaultLMN_LLM = 0.0will clip the output to unidirectional control and hide a negative error's effect onLMN_Iramp direction.
Cross-Reference to FB42 and FB43
The same COM_RST single-pulse rule applies to:
-
FB42 "CONT_S"— step-controller variant (used for servo-position control with integral-action pulse outputs) -
FB43 "PULSEGEN"— pulse generator used in combination with FB41 for three-step or analog-with-duty-cycle final-control elements
The Siemens FAQ on parameter assignment for the controller blocks covers all three. Apply the same OB100-pulse pattern whenever any of these three blocks is initialized in a project.
Documentation References
The authoritative references for FB41 behavior are:
- Siemens Standard PID Control manual (entry ID 388573) — defines the block diagram, normalized equations, and the integrator/differentiator internal structures
- Siemens FAQ "What should you watch out for when calling and assigning parameters to the controller functions (S)FB41, (S)FB42 and (S)FB43?" (entry ID 23923925) — documents the single-pulse COM_RST requirement
- Step 7 Professional V5.5 Online Help for FB41 — describes each input and output with default values
Always cross-check the parameter definitions against the Standard PID Control manual and the FB41/42/43 calling FAQ before commissioning a closed loop. The block is mathematically documented, but the operating-mode and initialization rules are field-tested and enforced by Siemens support.
Why does my FB41 LMN output stay flat at ER × GAIN even with a sustained error?
Because I_SEL = 0 in the instance DB disables the integrator branch and the controller collapses to a P-only controller. With a constant error and no integrator, the output cannot ramp — it is mathematically forced to remain at the proportional value. Set I_SEL := TRUE and ensure TI > 0 s to enable integration.
What is the correct way to issue COM_RST to FB41 in Step 7 V5.5?
Set a BOOL tag to TRUE in OB100, feed it into the COM_RST input of FB41 in OB1, and clear the tag at the last network of OB1. This produces a single-cycle TRUE pulse that initializes the integrator, differentiator, and the I_ITLVAL pre-load exactly once per restart. The Siemens FAQ entry ID 23923925 documents this pattern.
How do I verify that OB35 is actually running at 100 ms in my S7-300/S7-400 CPU?
Open HW Config, inspect the CPU's Cyclic Interrupts tab, and confirm OB35's period is 100 000 µs. Then implement a counter incremented inside OB35 and measure the count delta over a 60-second wall-clock interval. The expected count is 600 for a 100 ms period; deviations above 5 % indicate scan-time overruns or OB80 "time error" events.
What is the difference between LMN, LMN_P, LMN_I, and LMN_D in FB41?
LMN_P is the proportional component (GAIN · ER), LMN_I is the integrator accumulator state, LMN_D is the derivative component, and LMN is the final sum of all enabled contributions after scaling by LMN_FAC/LMN_OFF and clamping by LMN_HLM/LMN_LLM. Monitoring all four in a VAT is the fastest way to see which path is alive or stuck.
Why does my FB41 output follow MAN exactly and ignore the PID calculation?
Because MAN_ON = TRUE forces FB41 into manual mode and routes the value at input MAN directly to LMN, while the integrator is frozen. The controller stays in manual until MAN_ON is cleared. Audit any HMI tag or sequence step that drives MAN_ON, and confirm it returns FALSE on every scan except during operator-driven manual overrides.