S7-300 H-System Analog Output 0 mA: OB Local Data Stack Fix

David Krause16 min read
S7-300SiemensTroubleshooting
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

Problem Overview

When configuring redundant S7-300 analog output channels with the SM 332 module (order number 6ES7332-5HD01-0AB0) in an H-System (high-availability) project, an integrator may observe that the current loop reads 0 mA at the bottom of the scaled range instead of the expected 4 mA for a 4-20 mA live-zero configuration. The output reaches the upper end (20 mA at full scale) correctly, but any scale value below approximately 1% collapses to 0 mA. This pattern is reproducible across both channels of the redundant pair, even when wiring and termination have been independently verified with a calibrated multimeter.

The failure mode is not in the actuator, the loop wiring, or the analog output hardware itself. It is a software/runtime issue rooted in the way the S7-300 CPU allocates the local data stack (L-Stack) to the error and diagnostic organization blocks (OB 82, OB 83, OB 85) that drive the redundancy handshake. When the local data area assigned to those OBs is undersized, the redundancy firmware silently truncates the diagnostic payload used by the analog output channel switchover, and the channel is driven to its fail-safe 0 mA state until the next warm restart.

Hardware Identification: SM 332 6ES7332-5HD01-0AB0

The module referenced in the project is the SIMATIC S7-300 SM 332 analog output. The exact order number 6ES7332-5HD01-0AB0 identifies a 4-channel, 16-bit, isolated analog output module with the following key characteristics relevant to a 4-20 mA loop:

Parameter Value
Order number (MLFB) 6ES7332-5HD01-0AB0
Number of outputs 4 (voltage or current, configurable per channel)
Resolution 16 bits (including sign)
Output ranges ±10 V, 0-10 V, 1-5 V, ±20 mA, 0-20 mA, 4-20 mA
Galvanic isolation Yes (between channels and backplane)
Diagnostics supported Wire break, short circuit, overrange
Settling time 0.8 ms typical for resistive load
Load resistance (current output) Maximum 500 Ω at 20 mA
Redundancy capability Yes, with channel-pair configuration in HW Config

For a 4-20 mA output channel, the integer value written to the process image output word (PIQ) is encoded as follows:

Wire Current Decimal Hex Channel State
0 mA 0 0000 Output disabled / fail-safe substitute
4 mA 0 0000 Live-zero start (0% engineering range)
8 mA 6912 1B00 25% engineering range
12 mA 13824 3600 50% engineering range
16 mA 20736 5100 75% engineering range
20 mA 27648 6C00 Full scale (100%)
> 20 mA (overrange) 27649 - 32511 6C01 - 7EFF Overrange / substitute value
Open circuit / fault 32767 7FFF Wire break / invalid
Encoding note: At 4 mA live zero, the integer value written to the output word is also 0. The firmware path that drives "0 mA on the wire" versus "0 mA on the integer" must be distinguished before debugging. A 0 mA wire reading with a process image integer of 0 means the channel is in fail-safe / substitute state; a 0 mA wire reading with a process image integer of 0 would require the channel to be live. The symptom described here is the former case - the channel is being de-energized.

H-System Redundancy Architecture

An H-System (high-availability) is a Siemens topology built around two synchronized CPUs (in this case S7-300 CPUs such as CPU 315-2 DP or CPU 317-2 DP, or S7-400H CPUs) that share a common process image. The redundant analog output module pair is wired to the same field loop and is switched by either:

  1. Active/passive switchover controlled by the CPU redundancy firmware (most common with redundant S7-300 SM 332 channels wired as a pair).
  2. External redundancy couplers (e.g., 6ES7 195-7BF00-0XA0 for current outputs) used to merge the two 4-20 mA signals on the field side.

For the redundancy firmware to correctly determine which of the two analog output channels is "active" and which is "passive" at any moment, it must read the diagnostic data structures produced by the channel-pair FBs. These reads happen inside error and diagnostic OBs:

  • OB 82 - Diagnostic Interrupt OB. Triggered when a module reports a diagnostic event (e.g., wire break on the passive channel).
  • OB 83 - Insert/Remove Module Interrupt. Triggered during a hot-swap or when the redundancy link detects a channel swap.
  • OB 85 - Program Execution Error OB. Triggered when an I/O access fault occurs (e.g., reading from the passive analog output's process image during the swap window).

All three OBs execute in priority classes higher than OB 1 (the cyclic program). When the redundancy firmware is interrupted by one of these OBs, the temporary data of that OB - including its local variables and the diagnostic record buffer - is allocated on the local data stack (L-Stack) of the calling priority class.

Symptom Matrix: Reading 0 mA Instead of 4 mA

The user-observed failure mode is consistent across three independent axes:

Scale Input (HMI) Scaled Integer (PIQ) Expected Current Observed Current
0 0 4 mA 0 mA (channel de-energized)
25 6912 8 mA 0 mA - 8 mA intermittent
50 13824 12 mA ~12 mA after warm restart only
75 20736 16 mA 16 mA
100 27648 20 mA 20 mA
> 100 > 27648 Substitute / fault 0 mA

The "20 mA at full scale" reading is misleading - it occurs because the output driver latches a fixed PWM pattern when the integer value falls outside the diagnostic buffer's expected range. The 4 mA live-zero is the only value that requires the firmware to compute a non-trivial DAC code from the redundancy-aware diagnostic record. Therefore a failure in the diagnostic record read manifests first at the live-zero end.

Root Cause: OB Local Data Stack Exhaustion

The default local data area size assigned to OB 82, OB 83, and OB 85 in a fresh STEP 7 hardware configuration is 256 bytes per priority class. This default has been sufficient for decades of single-CPU projects because the diagnostic payload of an analog module's OB 82 record is on the order of 16-32 bytes.

However, an H-System redundancy configuration drags in additional FBs (FB 451 for S7-300 redundancy, plus the channel-pair glue logic, or the equivalent H-System runtime library for S7-400H). These blocks each consume local data within the calling OB. Specifically:

  • FB 451 (RED_IN) - approximately 84 bytes local data
  • FB 453 (RED_OUT) - approximately 96 bytes local data
  • FB 454 (RED_DIAG) - approximately 128 bytes local data (largest - runs inside OB 82 / OB 83)
  • Internal block for analog channel pairing - approximately 32 bytes local data

Sum: approximately 340 bytes of local data required inside OB 82 alone when redundancy is enabled. With the default 256-byte allotment, the STEP 7 runtime silently truncates the diagnostic record to fit, which means:

  1. The redundancy state byte (active/passive) is corrupted or zeroed.
  2. The analog output channel sees "no active channel" status.
  3. The output driver defaults to the fail-safe substitute value (0 mA for current channels).

For a 4-20 mA channel the substitute value is the disabled state, not the last valid current. This is why the wire reads 0 mA even though the scaled integer in the process image is correct. The same logic explains why exceeding the FC 106 range also forces the output to 0 mA - the integer written to PIQ falls outside the diagnostic buffer's expected range, the channel pair handshake fails, and the substitute value is applied.

FC105 vs FC106 Scaling Functions

The original project uses FC 106 to scale the HMI input. There is a function assignment correction that should be applied during the investigation:

Function Direction Inputs Outputs Use Case
FC 105 "SCALE" Real → Integer IN (real), LO_LIM, HI_LIM, BIPOLAR OUT (integer), RET_VAL Scaling a real (e.g., 0-100) to integer 0-27648 for AO write
FC 106 "UNSCALE" Integer → Real IN (integer), LO_LIM, HI_LIM, BIPOLAR OUT (real), RET_VAL Reading an integer AI value into a real engineering range

For an HMI input of 0-100 driving an analog output of 4-20 mA, the correct block is FC 105 with BIPOLAR = 0 (unipolar), LO_LIM = 0.0, HI_LIM = 100.0, and the resulting integer will map 0→0 and 100→27648. Using FC 106 in this direction will produce inverse scaling with the integer values written outside the valid 0-27648 range, which trips the channel into fault. Confirm the project is using FC 105 and not FC 106 for the write path.

Step-by-Step Resolution Procedure

The resolution is to increase the local data stack allotment for the affected OBs. In STEP 7 (Classic) for S7-300 / S7-400:

  1. Open the STEP 7 project and load the hardware configuration (HW Config).
  2. Double-click the CPU in the rack to open the CPU Properties dialog.
  3. Select the Memory tab.
  4. Locate the Local Data section, which lists the priority classes from 1 (OB 1) to 26 (high-priority OBs).
  5. For each priority class that corresponds to an error/diagnostic OB used by the redundancy stack, change the default value (typically 256) to a value that satisfies the largest block sum plus headroom. 512 bytes is the conservative, widely deployed choice.
  6. Reference table for the priority classes most commonly affected:
Priority OB Default Recommended for H-System
1 OB 1 (cyclic) 256 256
9 OB 10 (time-of-day) 256 256
12 OB 20 (delay interrupt) 256 256
24 OB 80 (time error) 256 256
25 OB 82 (diagnostic interrupt) 256 512
25 OB 83 (insert/remove module) 256 512
26 OB 85 (program execution error) 256 512
26 OB 86 (rack failure) 256 512
27 OB 121 / OB 122 (synchronous errors) 256 512

Note: The CPU enforces a total local data budget. Increasing multiple OB allotments consumes from that budget. If the CPU reports "Local data stack overflow" after the change, reduce non-critical OBs first. The CPU 315-2 DP has a 4 KB L-Stack, CPU 317-2 DP has 8 KB, and the S7-400H CPUs have 16 KB per subsystem.

  1. Save and recompile the hardware configuration. STEP 7 will offer to download the new system data to the CPU.
  2. Perform a warm restart (not a cold restart) of the CPU. A cold restart resets the L-Stack and may mask the issue until the next diagnostic event fills it again.
  3. Wait for both redundant CPUs to synchronize (R-Link LED green, no SF on either CPU).
  4. Force the analog output channel from STEP 7 to a known value (e.g., 0 for 4 mA, 13824 for 12 mA, 27648 for 20 mA) using PLC > Monitor/Modify > Force on QW 512.
  5. Measure the loop current with a calibrated multimeter in series with the load. Confirm 4 mA at integer 0, 12 mA at 13824, 20 mA at 27648.

Verification Procedure

After the change, validate in three stages:

  1. Static test: Force QW 512 = 0 (live zero). Expected: 4.000 mA ± 0.005 mA.
  2. Sweep test: Step QW 512 from 0 to 27648 in 256-integer increments. Plot the curve. A correctly configured SM 332 channel will exhibit a linear ramp. Calculate the loop transfer function: I_out = 4 mA + (PIQ / 27648) × 16 mA.
  3. Redundancy swap test: With the loop at 12 mA, disconnect the primary channel's backplane connector. The redundancy link should swap to the secondary channel within 100 ms. Loop current should remain at 12 mA. Reconnect the primary; verify the swap-back is bumpless.

If any of these stages fails, revisit the local data allotments and confirm the FBs listed earlier are actually being called. A missing call (e.g., FB 451 not called in OB 82) will produce the same symptom. Additionally, check the CPU diagnostic buffer (online > CPU > Diagnostic Buffer) for entries of the form "Local data stack overflow in OB 82" or "Error in OB priority class 25".

Diagnostic Troubleshooting Matrix

Observed Symptom Most Likely Root Cause First Diagnostic Step
0 mA at integer 0, 20 mA at integer 27648, single CPU Channel configured as 0-20 mA instead of 4-20 mA Check HW Config > Outputs > Output type
0 mA at integer 0, 20 mA at integer 27648, redundant pair OB 82 / 83 / 85 local data undersized Check CPU Properties > Memory > Local Data
Current value drifts ±0.5 mA under steady scale Load resistance outside 0-500 Ω range Measure load; SM 332 supports max 500 Ω at 20 mA
Current = 0 mA immediately after restart, recovers after warm restart Redundancy link not yet synchronized Check R-Link LED and CPU diagnostic buffer
Output stuck at last value, ignores new writes Substitute value enabled and channel in hold-last-state Check OB 122 / CPU Properties > Replace values
0 mA on one channel, correct current on the other (redundant pair) Passive channel not driven (correct) but active channel misconfigured Verify which channel is active via FB 453 RET_VAL
Current oscillates between 0 mA and correct value OB 83 firing repeatedly due to hot-swap or loose connector Check connector seating; review diagnostic buffer for OB 83 entries
SF LED on CPU lit, BF or SF LED on module lit Module diagnostic event not handled Read CPU diagnostic buffer; implement OB 82
Value scales correctly but wire reads 0 mA only at integer 0 Truncated diagnostic record in OB 82 Increase OB 82 local data to 512 bytes
Loop reads 0 mA only when FC 106 output exceeds 27648 Out-of-range write trips substitute value Clamp FC 105 output to [0, 27648] in user code
Loop reads 0 mA only after a STOP-RUN transition Substitute value applied during CPU startup Configure CPU Properties > Startup > Output substitute = 0 (intentional)
Both channels of redundant pair output correct current, but field device reads half-scale Redundancy coupler polarity reversed or load shared between channels Verify external coupler wiring; check for parallel-driving damage

Preventive Configuration for H-System Projects

When commissioning any new H-System project that uses redundant analog output modules, the following baseline should be applied from the start:

  1. Open HW Config > CPU Properties > Memory and set local data for priority 25-27 to 512 bytes before the first download.
  2. Install STEP 7's standard redundancy library on both CPUs and verify the FB call chain is identical across the pair.
  3. Use FC 105 for write direction (HMI real → AO integer), FC 106 for read direction (AI integer → HMI real). Verify polarity (BIPOLAR input = 0 for unipolar 4-20 mA).
  4. Configure the SM 332 channel as 4-20 mA in HW Config and enable "diagnostics" so that OB 82 events are raised.
  5. During commissioning, force QW = 0 and confirm 4 mA before any HMI scaling is wired in.
  6. Force QW = 27648 and confirm 20 mA. This validates the high end of the DAC range.
  7. Perform a redundancy swap test (disconnect primary backplane connector) and verify bumpless transfer within 100 ms.
  8. Document the local data allotments in the project function specification so that future maintenance does not silently regress the fix.

Cross-Reference: Current Measurement Range Encoding

The 0-20 mA and 4-20 mA encodings used by the S7-300 SM 332 follow the same convention as the S7-1200 analog input modules documented in the Siemens TIA Portal manual collection. The relevant reference values (per the Siemens S7-1200 analog signal module documentation):

System Current Range Decimal Hex
Unipolar 0-20 mA 0 mA - 20 mA 0 - 27648 0000 - 6C00
Unipolar 4-20 mA 4 mA - 20 mA 0 - 27648 0000 - 6C00
Overrange (both ranges) up to 23.5 mA 27649 - 32511 6C01 - 7EFF
Open circuit / fault N/A 32767 7FFF

The 4-20 mA range uses the same integer span as 0-20 mA (0 to 27648) but the live-zero is mapped to 4 mA. The S7-1200 family uses the identical encoding; see the Siemens TIA Portal manual collection: measurement ranges of the analog inputs for current (SB and SM) for the canonical encoding reference.

Edge Cases and Field-Proven Caveats

Several non-obvious situations can produce the same "0 mA at zero scale" symptom:

  • OB 122 (synchronous error) not loaded: When the cyclic program attempts to access a passive channel's PIQ during swap, OB 122 must exist to absorb the access fault. If OB 122 is missing, the CPU enters STOP, and after restart the channel is in substitute (0 mA) until warm restart completes.
  • CPU 315-2 DP vs CPU 317-2 DP L-Stack sizes: A CPU 315-2 DP with 4 KB L-Stack can run out of headroom quickly if multiple OBs are each set to 512 bytes. Audit the total: sum of all priority class allotments must not exceed the L-Stack. A CPU 317-2 DP (8 KB L-Stack) is the recommended minimum for redundant analog I/O.
  • Force vs Programmatic write: Force values bypass the redundancy handshake in some firmware versions. If "force QW 512 = 0" reads 0 mA but a programmatic write from OB 1 reads 4 mA, the issue is force-path related, not local-data related.
  • Field wiring polarity: A reversed polarity on the 4-20 mA loop will not produce 0 mA - it will produce negative current (clamped to 0 mA by the receiver). This is a quick multimeter check before deeper diagnostics.
  • HMI tag update rate: If the HMI tag is updated faster than OB 1 cycle time, intermediate values can pass through FC 106 with transient out-of-range integers. Clamp the FC 105 output to [0, 27648] with a LIMIT instruction before writing to PIQ.

FAQ

Why does my SM 332 output read 0 mA when the integer value is correct?

The SM 332 output channel is in fail-safe substitute state. The most common cause in an H-System redundant configuration is that OB 82 / OB 83 / OB 85 has insufficient local data stack allotment, causing the redundancy firmware to read a truncated diagnostic record. Increase the local data for those priority classes from the default 256 bytes to 512 bytes via HW Config > CPU Properties > Memory > Local Data, then perform a warm restart.

Which FC should I use to scale an HMI input of 0-100 to an analog output of 4-20 mA?

Use FC 105 "SCALE" (real → integer), not FC 106. Set BIPOLAR = 0, LO_LIM = 0.0, HI_LIM = 100.0. The output integer 0-27648 maps to 4-20 mA on the SM 332 channel. FC 106 is for the inverse direction (integer → real) and will produce out-of-range values in this use case, tripping the channel into fault.

What is the correct integer value for 4 mA live zero on a Siemens analog output?

The integer value 0 corresponds to 4 mA in 4-20 mA mode and to 0 mA in 0-20 mA mode. The integer encoding is identical; only the channel configuration in HW Config distinguishes the two ranges. Always force QW = 0 after configuration and measure the wire current to confirm which range is active.

How much local data do I need for OB 82 in an H-System?

Plan for at least 512 bytes. The redundancy blocks (FB 451, FB 453, FB 454 for S7-300) require approximately 340 bytes of local data when called inside OB 82. The default 256-byte allotment is not sufficient. For S7-400H CPUs the allotment can typically be set higher (e.g., 1024 bytes) without affecting the total L-Stack budget.

Will a cold restart fix the symptom temporarily?

Yes, a cold restart resets the L-Stack and the symptom disappears until the next diagnostic event fills the stack again (typically minutes to hours). A warm restart does not reset the L-Stack. The permanent fix is the local data allotment change plus a warm restart to load the new system data and re-trigger the OB initialization sequence.

What priority class is OB 82 and what is the default local data size?

OB 82 (diagnostic interrupt) runs at priority class 25 on S7-300 / S7-400 CPUs. The STEP 7 default local data allotment for priority 25 is 256 bytes. The same priority class also covers OB 83 (insert/remove module interrupt). For H-System projects, both should be raised to 512 bytes minimum to accommodate the redundancy FB call chain.

Back to blog