S7-1200 PID_Compact Runtime Parameter Switching with SCL
Switching PID_Compact gain, integral time, and derivative time on a Siemens S7-1200 during a live process is a common requirement when one controller must serve multiple load conditions (fan stages, heater banks, valve positions, product recipes). A typical field symptom is the PWM output locking at 100 % the instant a parameter is written, which is not a defect in the CPU 1212C, the SM 1231 RTD module, or the SM 1232 analog output module - it is a misuse of the PID_Compact technology object. This reference walks through the correct runtime structure, the SCL pattern that avoids PWM latch-up, the differences between Config and Retain data, and a PID_Temp fallback for pure temperature loops.
1. Problem Definition
Engineers routinely build systems where one physical actuator must be driven from one PID controller whose tuning depends on which loads are active. A 4-fan / 8-stage heater matrix is a canonical example:
| FAN1 | FAN2 | Process State | Desired Tuning |
|---|---|---|---|
| ON | OFF | Low forced convection | Higher gain, longer Ti |
| ON | ON | High forced convection | Lower gain, shorter Ti |
| OFF | OFF | Natural convection only | Highest gain, shortest Ti |
The naïve implementation writes the new Gain, Ti, and Td into the PID_Compact instance DB from an SCL CASE block. The block then either:
- Locks its PWM output ON (100 % duty cycle) and never recovers, or
- Responds as if it has just been commissioned and briefly restarts the pretune / fine-tune sequence,
Both behaviors come from the same root cause: the wrong sub-structure of the technology object DB is being modified, or the controller is being switched between Mode values without sequencing the I-part.
Config, Retain, and CycleTime. Only Retain.CtrlParams may be overwritten in runtime. Writing into Config at runtime does not take effect and may corrupt the technology object.2. Prerequisites
- CPU 1212C DC/DC/DC (6ES7212-1AE40-0XB0 or later -0XB0 variant). The four onboard outputs Q0.0 - Q0.3 source 24 V at 0.5 A and are TTL-compatible, suitable for the PWM signal into an SSR or solid-state relay.
- SM 1231 RTD module (6ES7231-5PD32-0XB0 or -5PF32-0XB0) for PT100/PT1000 feedback.
- SM 1232 analog output (6ES7232-4HD32-0XB0) if a continuous 4 - 20 mA or 0 - 10 V control signal is also required (optional when PWM is the sole actuator).
- TIA Portal V14 SP1 or later. V18 / V19 / V21 added additional PID_Compact help; the runtime structure described here is compatible across all of them because the technology object schema is firmware-defined, not project-defined.
- CPU firmware 4.2 or higher (PID_Compact became a technology object instead of a plain FB starting at firmware 4.0).
- One instance DB of type
PID_Compactadded to Technology objects > PID_Compact in the project tree.
Reference documentation:
- Technology object PID_Compact (S7-1200, S7-1500, S7-1200 G2) - the canonical reference for the PID_Compact DB schema and runtime behavior.
3. PID_Compact Data Structure (What You Can and Cannot Write at Runtime)
The PID_Compact instance DB is structured into these primary regions:
| Region | Path | Purpose | Writable at Runtime? |
|---|---|---|---|
| Input interface |
Setpoint, Input, Input_PER, ManualEnable, ManualValue, Mode
|
Per-cycle I/O mapping | Yes (every cycle) |
| Output interface |
Output, Output_PWM, SetpointLimit_H, SetpointLimit_L, InputWarning_H, InputWarning_L
|
Actuator drive and diagnostics | Read-only |
| Config |
Config.InputScaling, Config.OutputScaling, Config.PWM, Config.Retain.CtrlParams reference |
Commissioning-time scaling and limits | No - changes require reinitialization |
| Retain |
Retain.CtrlParams.Gain, Retain.CtrlParams.Ti, Retain.CtrlParams.Td, Retain.CtrlParams.TdFilt, Retain.CtrlParams.PZone, Retain.CtrlParams.DeadZone
|
Persistent tuning values | Yes - this is the runtime tuning area |
| Internal state |
InternalMode, IntegratorState, ControlLoopOffset
|
Live integrator and mode state | Never write from user code |
The single most common failure mode observed in the field is the following SCL fragment:
// INCORRECT - writes the engineering view, not the Retain area
"PID_Compact_1".Gain := 2.5;
"PID_Compact_1".Ti := 30.0;
"PID_Compact_1".Td := 0.0;
Those tags exist in the data view of the DB for engineering convenience, but they are aliases that only mirror the values loaded into Retain.CtrlParams at the end of each cycle. Writing them has no effect on the controller until the next cold restart, and during the cycle the integrator keeps the previous Gain active - producing the perceived "PWM stuck ON" symptom because the I-part saturates while the user thinks the P-only value has been applied.
The correct path is:
// CORRECT - writes directly to the runtime Retain area
"PID_Compact_1".Retain.CtrlParams.Gain := 2.5;
"PID_Compact_1".Retain.CtrlParams.Ti := 30.0;
"PID_Compact_1".Retain.CtrlParams.Td := 0.0;
4. Why the PWM Output Locks at 100 %
There are four distinct mechanisms that all manifest as "PWM output stuck ON" when parameters are modified at runtime. Diagnose in this order:
4.1 Integrator wind-up from a stale setpoint during a write
If the process value is far from the new setpoint when the controller is re-tuned with a smaller Ti, the integral action accumulates error faster than the plant can respond. The I-part saturates at OutputScaling.UpperPointOut (typically 100 %), and the PWM duty cycle is driven to its maximum. The user observes a "stuck ON" condition until the integrator drains. The fix is to clear the integrator on every parameter set transition:
// Reset integrator before loading new parameters
"PID_Compact_1".Mode := 4; // mode 4 = "inactive with reset"
"PID_Compact_1".Retain.CtrlParams.Gain := NewGain;
"PID_Compact_1".Retain.CtrlParams.Ti := NewTi;
"PID_Compact_1".Retain.CtrlParams.Td := NewTd;
"PID_Compact_1".Mode := 3; // mode 3 = "automatic"
ManualValue instead and re-enter automatic mode after the parameter write.4.2 Mode = 0 leaves the output at the last value
If the controller is being driven with Mode = 0 (inactive) during parameter writes, the PWM holds its last computed duty cycle. Users frequently interpret this as "stuck ON" when in fact the controller is simply not running. Verify with the online watch table that "PID_Compact_1".Mode is 3.
4.3 Pretune / fine-tune was triggered by an erroneous Mode write
Setting Mode to 1 or 2 starts pretune or fine-tune. These modes drive the actuator through a controlled excitation sequence to identify the plant. They will hold the output at extremes (0 % and 100 %) by design and will look exactly like a "stuck" output. Never write to Mode from user code while performing parameter switching.
4.4 Output scaling upper limit set to 100 with no headroom
If Config.OutputScaling.UpperPointOut is 100 and LowerPointOut is 0, the controller cannot produce negative correction - which is fine for heating. But if a downstream contactor or SSR has a minimum-on time longer than the PWM period (default 1.0 s), the output may appear latched. Use Config.PWM.MinimumOnTime / MinimumOffTime to enforce SSR-friendly switching.
5. The Correct Runtime Switching Method
The recommended pattern uses a single PID_Compact instance, an SCL function that owns the parameter bank, and an edge-triggered load to avoid writes on every cycle.
5.1 Define a parameter bank DB
Create a global DB (e.g. DB_PID_ParamSets) with eight parameter sets, one per process state:
TYPE "UDT_PID_ParamSet"
VERSION : 0.1
STRUCT
Gain : REAL; // proportional gain (Kp)
Ti : REAL; // integral action time in seconds (0 = off)
Td : REAL; // derivative action time in seconds (0 = off)
TdFilt : REAL; // derivative filter time constant in seconds
Setpoint : REAL; // engineering-units setpoint
PZone : REAL; // proportional band / deadband width
END_STRUCT;
END_TYPE
DATA_BLOCK "DB_PID_ParamSets"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
NON_RETAIN
STRUCT
ActiveSet : INT; // 1..8, mirrored from mode selector
ParamSet : ARRAY[1..8] OF "UDT_PID_ParamSet";
END_STRUCT;
END_DATA_BLOCK
5.2 Write the parameter-loading FC in SCL
The function executes once per OB1 cycle, but it only touches the technology object on a rising edge of ActiveSet:
FUNCTION "FC_PID_LoadParams" : VOID
VAR_INPUT
ModeBits : DWORD; // FAN1..FAN3 etc. packed here
END_VAR
VAR_TEMP
tSelectedSet : INT;
tOldSet : INT;
tParams : "UDT_PID_ParamSet";
END_VAR
BEGIN
// Determine selected set from mode bits
tSelectedSet := "FC_BitsToSetId"(ModeBits); // user function returning 1..8
tOldSet := "DB_PID_ParamSets".ActiveSet;
IF tSelectedSet <> tOldSet THEN
// Read selected parameter set into temp
tParams := "DB_PID_ParamSets".ParamSet[tSelectedSet];
// Place controller in inactive-with-reset to drain integrator
"PID_Compact_1".Mode := 4;
// Write the Retain.CtrlParams values - this is the only path that takes effect
"PID_Compact_1".Retain.CtrlParams.Gain := tParams.Gain;
"PID_Compact_1".Retain.CtrlParams.Ti := tParams.Ti;
"PID_Compact_1".Retain.CtrlParams.Td := tParams.Td;
"PID_Compact_1".Retain.CtrlParams.TdFilt:= tParams.TdFilt;
"PID_Compact_1".Retain.CtrlParams.PZone := tParams.PZone;
// Update setpoint in the same transition to avoid re-tune on stale SP
"PID_Compact_1".Setpoint := tParams.Setpoint;
// Return to automatic mode
"PID_Compact_1".Mode := 3;
"DB_PID_ParamSets".ActiveSet := tSelectedSet;
END_IF;
END_FUNCTION
5.3 OB1 invocation
// In OB1 (or a higher-priority OB if you want deterministic switching)
"FC_PID_LoadParams"(ModeBits := "DB_ModeBits".Word0);
"PID_Compact_1"(Setpoint := "DB_PID_ParamSets".ParamSet["DB_PID_ParamSets".ActiveSet].Setpoint,
Input := "DB_Process".PV_Engineering,
Input_PER := 0, // 0 = disabled when using Input
ManualEnable := FALSE,
ManualValue := 0.0,
// The following are read-only outputs, do NOT assign
Output => "DB_Process".Output_Pct,
Output_PWM => "Q0.0");
Three points make this pattern reliable:
-
Edge-triggered writes to
Retain.CtrlParamsprevent the integrator from being repeatedly disturbed each cycle. - Mode 4 reset drains the I-part before new parameters are applied, eliminating the wind-up saturation that produces 100 % PWM.
- Setpoint update in the same transaction prevents a brief PV-vs-SP excursion that would otherwise trigger an apparent fine-tune response.
6. PWM Output Configuration on the CPU 1212C
On the CPU 1212C, Output_PWM is a Boolean (0/1) signal wired directly to the bit address of a digital output. The PID_Compact block internally computes the duty cycle and toggles the bit during the configured PWM period. Configuration values live in the technology object editor under Configuration > Output > PWM:
| Parameter | Typical Value | Effect |
|---|---|---|
| PWM period (s) | 1.0 - 10.0 | One full cycle. For SSR-driven heaters use 1 - 2 s; for solenoid valves use 5 - 10 s. |
| Minimum ON time (s) | 0.05 - 0.1 | Prevents the SSR from chatter-dying. The Q0.0 source output of the 1212C supports up to 100 kHz, but mechanical SSRs typically need 50 ms minimum pulses. |
| Minimum OFF time (s) | 0.05 - 0.1 | Symmetric to ON time. Ensures coil / contactor release before re-energize. |
| Output value range | 0 - 100 % | Maps directly to duty cycle when Output_PWM = TRUE; 0 % maps to constant FALSE. |
7. PID_Temp Alternative for Heating Loops
When the controlled variable is strictly temperature and the actuator is a heating element, Siemens recommends PID_Temp rather than PID_Compact. PID_Temp:
- Provides built-in ramp limiting on the output (limits heater thermal shock).
- Supports a true derivative action on the PV rather than on the error (less setpoint-induced derivative kick).
- Exposes
Config.HeatPid.GainandConfig.CoolPid.Gaindirectly, allowing two completely independent parameter sets - one for heating and one for cooling - without runtime switching.
For the FAN-driven heating scenario in the source problem, where one heating element sees eight different cooling loads, PID_Compact with runtime switching remains the right choice. For a single heating/cooling valve pair, switch to PID_Temp.
8. Step-by-Step Implementation Procedure
-
Add the technology object. In the project tree: Technology objects > Add new > PID > PID_Compact. Name it
PID_Compact_1. The wizard creates the instance DB. - Configure input and output scaling. Under Configuration > Basic settings set InputScaling to match the RTD range (e.g. -50 to +400 °C for PT100) and OutputScaling to 0 - 100 %.
- Configure PWM. Under Configuration > Output > PWM, set the period, minimum on/off times, and select Output_PWM as the active output.
- Create the parameter UDT and DB. Use the snippets from §5.1.
- Create the loader FC. Use the snippet from §5.2. Mark the FC as SCL in the block properties.
- Wire the FC in OB1. Place the call before the PID_Compact call so the mode transition completes before the controller runs.
- Populate parameter sets. Either via the parameter view or by writing initial values into the DB; commissioning can also be done by exporting the DB to a CSV and re-importing per recipe.
- Compile and download. Include the technology object in the download set.
9. Commissioning and Verification
Use a watch table on the PID_Compact instance DB to confirm each transition:
| Watch Variable | Expected Behavior on Mode Change |
|---|---|
Mode |
Briefly 4 then 3 |
Retain.CtrlParams.Gain |
Updates within one cycle of ActiveSet change |
Retain.CtrlParams.Ti |
Updates within one cycle |
Setpoint |
Reflects the new parameter set value |
Output_PWM |
Drops to 0 for < one cycle then resumes variable duty cycle |
IntegralState (internal) |
Drained to 0 during mode 4 phase |
Errorbits |
No bit set, especially no Errorbits.%X5 (configuration error) and no Errorbits.%X6 (process value invalid) |
For step-response validation per parameter set:
- Force the load to the configuration for Set 1 (FAN1 ON, FAN2 OFF).
- Apply a 10 % setpoint step.
- Log PV, SP, Output_PWM for 3 × the longest
Tiof any set. - Compute ITAE and overshoot for the recorded trace.
- Repeat for Sets 2 - 8.
10. Troubleshooting Matrix
| Symptom | Likely Cause | Diagnostic | Corrective Action |
|---|---|---|---|
| PWM output 100 % continuously | Wrote to Config not Retain; integrator wind-up |
Watch Retain.CtrlParams.Gain - confirm it actually changed |
Switch to §5 SCL pattern; verify mode sequence 4 → 3 |
| PWM output 0 % continuously |
Input_PER wiring fault or RTD open |
Check Input_PER value and Errorbits.%X6
|
Repair RTD wiring; substitute 4-wire PT100 if 2-wire reads high-impedance |
| Output toggles randomly between two values | PWM period too short for actuator; SSR minimum-on violation | Measure actual Q0.0 with scope | Raise PWM period to 2 s; set MinimumOnTime/OffTime to 0.05 s |
| Output bounces every time ActiveSet changes | Writing parameters every cycle instead of edge-triggered | Cross-reference FC_PID_LoadParams call - confirm IF transition logic |
Implement edge trigger on tSelectedSet <> tOldSet
|
| Controller claims it is fine-tuning | Mode was accidentally set to 1 or 2 | Watch Mode tag in online mode |
Remove all Mode := 1/2 writes from user code |
| PWM correct but heater never reaches SP | PWM period too long for low-output regime; minimum-on time masks low duty | Check effective duty at small errors | Reduce PWM period to 1 s or use SM 1232 AO 4 - 20 mA control |
| Different tuning for each recipe but values identical | Parameter bank not loaded from DB - all reads return set 1 | Watch DB_PID_ParamSets.ActiveSet
|
Verify FC reads from correct DB index |
11. Common Pitfalls Beyond the PWM Issue
11.1 Optimized block access
With S7-1200 firmware 4.2 and later, all new data blocks default to optimized (symbolic) access. The Retain.CtrlParams absolute path is still valid as long as the block was generated by the technology object wizard. If you hand-create the DB or import from a CSV, the path will not exist and the write will fail silently.
11.2 Cycle time vs OB1 priority
If the loader FC runs in OB1 (priority 1) and the PID_Compact is also called in OB1, the parameter write and the controller execute in the same cycle - acceptable. If the loader runs in a higher-priority OB (e.g. OB35 cyclic interrupt at priority 16), the controller may read partially written values. Always run them in the same OB or insert a Mode = 4 fence for at least one full PID cycle before resuming automatic.
11.3 Retain after power cycle
Retain.CtrlParams persists across power cycles because it is backed by the CPU's retentive storage. The ActiveSet integer in DB_PID_ParamSets must be declared RETAIN or it will reset to 0 after power-down, causing the controller to start with the wrong parameter set on the next boot.
11.4 Firmware 4.0 vs 4.2 PID_Compact schema
CPU firmware 4.0 introduced PID_Compact as a technology object. Firmware 4.2 renamed Retain.CtrlParams from the original CtrlParams path and added TdFilt. If you upgrade an older project, the TIA Portal compiler will normally rewrite the path, but manual DB symbol renames after a failed migration can leave Retain empty.
12. Field-Proven Parameter Set Recommendations
For a heating system with 8 fan states (binary combinations of three fans), a typical starting point after one autotune run on each state is:
| Active Fans | Gain (Kp) | Ti (s) | Td (s) | PZone (°C) |
|---|---|---|---|---|
| 0 | 4.0 | 180 | 0 | 0.5 |
| 1 | 3.2 | 150 | 0 | 0.5 |
| 2 | 2.8 | 130 | 0 | 0.4 |
| 3 | 2.4 | 110 | 0 | 0.4 |
| 4 | 2.0 | 90 | 0 | 0.3 |
| 5 | 1.8 | 80 | 0 | 0.3 |
| 6 | 1.6 | 70 | 0 | 0.25 |
| 7 | 1.4 | 60 | 0 | 0.25 |
These are starting points only. Always run a per-set pretune (Mode = 1) on the actual plant to derive the real Gain and Ti; the table above gives a monotonic trend (more airflow → less gain, faster integration) that is useful for sanity-checking your autotune results.
13. Frequently Asked Questions
Why does my PID_Compact PWM output stick ON at 100 % after I change parameters?
The controller is most likely still using the previous parameter set because the write went to the wrong DB region (Config instead of Retain.CtrlParams), or the integrator has wound up during the parameter transition. Use the §5 SCL pattern: set Mode = 4, write Retain.CtrlParams.Gain/Ti/Td, then set Mode = 3.
Can I write to PID_Compact tags from HMI or another PLC without disturbing the controller?
Yes - as long as you write to Retain.CtrlParams.Gain, Retain.CtrlParams.Ti, and Retain.CtrlParams.Td. HMI writes to the symbolic top-level tags (the engineering view aliases) take effect only on the next CPU restart. Always toggle Mode through 4 → 3 when changing Ti significantly to drain the I-part.
Should I use PID_Temp instead of PID_Compact for a heater control?
If the loop is strictly heating/cooling on a single PV, yes - PID_Temp provides ramp limiting and derivative-on-PV. For multi-state systems like 8 fan-driven heater combinations, PID_Compact with runtime parameter switching is simpler because you only need one technology object and one PID instance.
How do I trigger the controller to re-tune at runtime?
Set Mode = 1 for pretune or Mode = 2 for fine-tune. The controller will drive the actuator through an excitation sequence and write the new Retain.CtrlParams values automatically. Do not start a tune from a recipe parameter bank write - let the controller perform a fresh identification for each new load condition.
What is the minimum CPU firmware for the runtime switching pattern shown here?
Firmware 4.2 on the S7-1200 CPU. Firmware 4.0 introduced PID_Compact but lacked TdFilt. The 1212C DC/DC/DC ships with 4.2 or higher as of mid-2018; older units may need a firmware update via the Siemens support portal.
Can I use the SM 1232 analog output instead of PWM on Q0.0?
Yes. Configure OutputScaling to a 0 - 10 V or 4 - 20 mA range, select Output as the active output in the technology object configuration, and wire the SM 1232 to a proportional SSR or thyristor. PWM is preferred for time-proportional SSRs that accept a digital input; continuous analog is preferred for SCR power controllers.