Resolving Siemens CPU 319 OB121 Programming Error at Address 0

David Krause14 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

A Siemens CPU 319-3 PN/DP (6ES7318-3EL01-0AB0 and related variants in the S7-300 family) unexpectedly transitions from RUN to STOP immediately after a STEP 7 / TIA Portal download completes. The SF (Group Fault) LED illuminates, the RUN LED extinguishes, and the STOP LED turns on. The diagnostic buffer contains two linked entries generated by the CPU operating system:

  • Event ID 16#4562 — STOP durch Programmierfehler (OB nicht geladen oder nicht möglich, bzw. kein FRB vorhanden)
  • Event ID 16#2522 — Bereichslängenfehler beim Lesen, Instanz-DB, Bitzugriff, Zugriffsadresse: 0

The Event ID 16#2522 is the actual programming fault (area-length error on a bit access to byte/bit address 0 inside an instance DB). Event ID 16#4562 is the consequence: the CPU attempted to call OB 121 to report the fault, found it absent, and dropped to STOP. OB 121 is not the cause of the failure — it is the diagnostic vehicle the operating system uses to announce the failure. Treat the symptom (missing OB) and the cause (the underlying programming error) as two separate work items.

Engineering rule: On every S7-300/S7-400 CPU, the absence of OB 121 converts any user-program coding error into a hard CPU STOP. Installing OB 121 only suppresses the STOP reaction; it does not correct the code that produced the error.

Diagnostic Buffer Decoding

Open the CPU diagnostic buffer in STEP 7 V5.x via PLC → Diagnostic/Setting → Diagnostic Buffer, or in TIA Portal via Online & diagnostics → Diagnostics buffer. Translate the two leading events:

Field Event 10 — 16#4562 Event 11 — 16#2522
Meaning (EN) STOP due to programming error (required OB not loaded / not possible / no FRB available) Area-length error on read, instance DB, bit access, address 0
FB number 876 876
Block address 2750 (relative MC7 code offset) 2750
Previous operating state RUN —
Requested operating state STOP (internal) —
Requested OB — OB 121 (Programming Error OB)
Trigger timestamp 16:10:32.898 30.09.2010 16:10:32.895 30.09.2010

The two events are 3 ms apart and share the same FB 876 reference and the same block address 2750. The 3 ms delta reflects OB-call resolution time inside the scan. Event 11 (16#2522) is generated first; Event 10 (16#4562) follows because OB 121 is missing on the target CPU and the operating system escalates to STOP.

Block address interpretation: Block address 2750 is the offset (in bytes) of the failing MC7 instruction inside FB 876. It is not a Profibus diagnostic address, although similar numeric values occasionally appear in HW Config DP slave diagnostics — always validate against the FB source.

Technical Background: OB 121 and the S7 Error OB Family

The S7-300/400 operating system reserves a numbered set of error OBs that the CPU calls automatically when a synchronous fault is detected. Each OB is the user’s chance to react to a specific class of error and keep the CPU in RUN. The two OBs most often confused by maintenance engineers are:

OB Name Triggered by
OB 121 Programming Error OB Accessing a non-existent bit/byte/word/DWord, illegal type conversion, BCD error, range error on system functions
OB 122 I/O Access Error OB Direct I/O access to a missing or faulty module, or accessing I/O area outside the process image

Per the official Siemens TIA Portal reference Programming error organization block (OB 121) (S7-300, S7-400): “The CPU operating system calls OB 121 whenever an event occurs that is caused by an error related to the processing of the program.” If OB 121 is not loaded in the CPU, the operating system cannot hand control to user code, and the CPU transitions to STOP on the first programming error encountered in the scan cycle. This is the documented and expected behavior — it is not a hardware defect.

The same documentation states: “If OB 121 is not programmed, the CPU changes the operating mode from RUN to STOP.” S7 also provides SFC 36 / SFC 37 (MSK_FLT / UNK_FLT) so that user code can mask (suppress) specific error events from triggering OB 121 at all — a useful technique for legacy code segments that intentionally probe hardware states.

Root Cause Analysis

Event ID 16#2522 carries the structural information needed to localize the bug. The three fields that matter are:

  1. Object class — Instanz-DB: The faulting access is to an instance data block, not a shared (global) DB. Instance DBs are generated automatically by the compiler and mirror the VAR, VAR_TEMP, and VAR_IN_OUT declarations of the parent FB.
  2. Access type — Bitzugriff: A bit-level (A, AN, O, ON, S, R, =, X) read or write is being executed.
  3. Access address — 0: The address decoded is byte 0, bit 0 of the instance DB. In an S7 instance DB, address 0 is the first bit of the first VAR_INPUT or VAR element declared in the FB header.

Address 0 in an instance DB is normally a valid location — it is the LSB of the first static or input variable. The fact that the CPU raises a range-length error on it means that the actual instance DB currently loaded on the CPU is shorter than the FB 876 code expects. The most common cause: the FB 876 interface (the VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, or VAR block) has been edited — for example, a new variable was inserted at the top of the declaration table, or an existing variable was renamed and the offset shifted — while the corresponding instance DB was not regenerated. The compiler assigns new offsets during the build, but the runtime still holds the old, smaller DB image downloaded earlier.

Secondary causes that produce identical diagnostics include:

  • A multi-instance call (FB 876 instantiated as a static variable inside another FB) where the parent FB’s VAR section was modified but the parent’s instance DB was not recompiled.
  • An ANY-pointer or VARIANT input pointing at an instance DB that has been deleted and recreated with a different number, leaving a stale reference in FB 876.
  • A hand-edited DB layout (manual data view editing) that changed the offset of an existing BOOL element, but the FB source code in the project was not updated.
  • Cross-project copy/paste that re-numbered the FB (876 in this case) and the instance DB inconsistently.

Why the Temporary OB 121 Workaround Works

Loading a blank OB 121 shell into the CPU changes the operating-system reaction: when 16#2522 fires, the OS calls OB 121, executes an empty body, returns to the scan, and the CPU stays in RUN. The fault still happens on every cycle — only the system reaction is suppressed. This explains the three observable behaviors in the field:

  1. The CPU stays in RUN after OB 121 is installed.
  2. Output behavior of the affected machine is unpredictable, because the bit access at address 0 returns FALSE and any downstream logic depending on that bit is wrong.
  3. Removing the OB 121 shell — or downloading a new program without it — re-introduces the STOP, which is why the workaround feels like it has to be repeated every download.
Safety implication: Suppressing a programming error with OB 121 in a safety-relevant path is never acceptable. If FB 876 is in a SIL-rated path, treat the 16#2522 event as a hard fault and keep the CPU in the safe state until the code is corrected.

Step-by-Step Permanent Resolution

Prerequisites

  • STEP 7 V5.5 + SP4 / HF7 or TIA Portal V16 or later with the CPU 319 GSD/ HSP installed.
  • The current offline project (must match the FB 876 source already in the online CPU).
  • Read/write access to the CPU (PG/PC interface, online connection).
  • Backup of the CPU program (PG → Upload station to PG) before making changes.

Procedure (STEP 7 V5.x)

  1. Upload the current program from the CPU: PLC → Upload Station to PG (Software). This guarantees the offline and online versions of FB 876 are reconciled.
  2. Open FB 876 in the SIMATIC Manager → S7 Program → Blocks. Right-click the block and select Object Properties → General Part 2 to confirm the FB number and the timestamp.
  3. Open the interface of FB 876. Record the order and data types of every VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, and VAR element. Compare the order with the version stored in the CPU (right-click the online block → Compare).
  4. Locate the instance DB called by FB 876. From the call tree (Options → Reference Data → Program Structure) find the instance DB number. Double-click it.
  5. Recompile the instance DB: right-click the instance DB → Generate Instance DB. The compiler writes a fresh image whose length and offsets match the current FB 876 interface.
  6. For a multi-instance call, recompile the parent FB’s instance DB the same way. Confirm the parent FB’s static section still references FB 876 at the correct relative offset.
  7. Build a fresh OB 121 from the standard library (Libraries → Standard Library → System Function Blocks) and add it to the S7 program. Use SFC 6 / SFC 13 / SFC 17 inside OB 121 to write the fault information into a status DB so the fault is not silently swallowed.
  8. Compile and download the full Blocks container to the CPU. The CPU stays in RUN.
  9. Reset diagnostic buffer and run the machine for at least one full production cycle. Confirm no new 16#2522 entries appear.

Procedure (TIA Portal V16+)

  1. Online → Upload from device (software) to bring the live CPU program into the TIA project.
  2. Open Project tree → PLC_1 → Program blocks → FB [876].
  3. From Tools → Call structure, identify the instance DB for FB 876.
  4. Right-click the instance DB → Compile → Software (rebuild all blocks). TIA regenerates the instance DB from the current FB interface.
  5. Add OB 121 from Add new block → Organization block → OB 121 (Programming error). Optionally call WR_USMSG (SFC 17) inside OB 121 to log the fault via the diagnostic buffer of any HMI that subscribes to the PLC diagnostics.
  6. Download the entire program to the CPU. Use Consistent download if the project setting allows it.

Sample OB 121 Skeleton (SCL)

// OB121 - Programming Error Handler
// Reads the OB121 start info and writes a compact entry to DB9000
// so maintenance staff see one line per fault, not a 192-event buffer.

VAR_TEMP
    info : OB121_ERROR_BITS;
    blk  : WORD;     // Block number from OB121 header (local)
    ofs  : WORD;     // Block-relative offset (local)
    ret  : INT;      // Return code from WR_USMSG
END_VAR

IF "Diag".Enable = TRUE THEN
    info  := OB121_ERROR_INFO;
    blk   := info.BLKNR;
    ofs   := info.BLKOFFSET;
    "Diag".LastFaultFB    := blk;
    "Diag".LastFaultOffset := ofs;
    "Diag".LastFaultCode  := info.FLT_ID;
    "Diag".LastFaultTime  := RTM_TOD(0);   // current TOD
    ret := WR_USMSG(MSG_ID := 1001, EVENT := info.FLT_ID);
END_IF;

The exact field names of OB121_ERROR_INFO and OB121_ERROR_BITS depend on the TIA / STEP 7 version. In STEP 7 V5.5 the local tags are OB121_EV_CLASS, OB121_FLT_ID, OB121_PRIORITY, OB121_OB_NUMBR, OB121_BLK_TYPE, OB121_BLK_NUMBR, OB121_BLK_OFFSET, and OB121_FLT_REG. Reference the official OB 121 documentation for the complete local-data layout.

Instance DB Reconciliation Deep-Dive

When FB 876’s interface has been changed, three artifacts must move in lockstep: the FB source, the instance DB image, and any background DB that the FB touches via UDT. A reliable reconciliation procedure is:

  1. Compare online vs. offline on FB 876 first. The Block comparison tool in STEP 7 V5.x (or Compare → Online/offline in TIA) will surface interface drift.
  2. Delete the instance DB from the offline project.
  3. Compile all blocks in the S7 program. The compiler regenerates the missing instance DB from the current FB.
  4. Cross-check every call site of FB 876 in the program structure. If any caller passes an ANY parameter that points at the instance DB, verify the pointer’s DB number still matches.
  5. Download and clear the diagnostic buffer.
Anti-pattern: Editing the instance DB by hand in the data view. This breaks the contract between FB code and DB layout. Treat the instance DB as compiler output, not as user data.

Verification and Testing

After the recompile and download, perform the following verification sequence before returning the machine to production:

  1. Diagnostic buffer must be clean. After one hour of operation, no entries with IDs in the 16#25xx or 16#45xx ranges should appear. Tolerate no more than one 16#4562 entry on the first scan after download (this is the historical fault already cleared).
  2. Watchdog test. Force the original error back into the program (e.g. temporarily add a bit-access to address 0 of a short DB) and confirm that OB 121 fires, the status DB updates, and the CPU stays in RUN. This proves the OB 121 path is functional, not just present.
  3. Cold restart test. Perform a complete restart (MRES) to ensure the new blocks are persisted to flash and survive a power cycle.
  4. Compare reference data. Regenerate the program structure, cross-reference, and assignment lists. Save them under version control. This becomes the baseline for the next engineering change.

Troubleshooting Matrix

Symptom Diagnostic ID Likely cause Action
CPU goes to STOP on first scan after download 16#4562 / 16#2522 Missing OB 121 + area-length error in instance DB Install OB 121, recompile the instance DB
CPU stays in RUN but outputs toggle randomly 16#2522 in diagnostic buffer, no STOP OB 121 installed but instance DB still wrong; bit read returns 0 Recompile instance DB, do not rely on OB 121 suppression
STOP immediately after PG stop/cancel 16#4562 only Last download did not include OB 121 Add OB 121 to the project, not only to the online folder
STOP with block address in the 3000–4000 range 16#4562 / 16#25xx Multi-instance FB where parent instance DB is out of date Recompile parent FB’s instance DB
STOP with FLT_REG nonzero 16#2522 + FLT_REG = DB number Access to a deleted or re-numbered DB Recreate the referenced DB or fix the ANY pointer
STOP on FBs that are not in the project 16#4562 + FB number 0 Compiler generated a stub and the system has no call target Rebuild all blocks from source

Preventive Engineering Practices

  • Always ship OB 121 (and ideally OB 122) with every S7-300/400 program. Treat them as mandatory system blocks, not optional ones. Even a no-op OB 121 is better than a missing one.
  • Add a permanent status DB updated by OB 121/122. Maintenance crews reading the HMI diagnostic page can identify the FB and offset of the last programming error without connecting a programmer.
  • Version-control the S7 project at the source level (TIA Portal multi-language or STEP 7 V5.x source files exported via Source files). This is the only way to detect FB-interface drift between two stations that should have identical code.
  • Use UDTs for any structured instance data that more than one FB shares. A UDT change regenerates every dependent DB automatically.
  • Reserve OB 80, OB 85, OB 86, OB 87, OB 121, OB 122 from the start. A CPU with all error OBs installed will degrade gracefully through nearly every common fault class (time error, module failure, rack failure, communication failure, programming error, I/O error) without dropping to STOP.
  • Run a periodic diagnostic-buffer sweep. A small script that logs the buffer to a CSV file once per shift catches latent 16#25xx events that OB 121 is silently absorbing.

FAQ

Does installing OB 121 fix a CPU 319 STOP fault?

No. OB 121 only changes the operating-system reaction to programming errors. If the CPU drops to STOP with Event ID 16#4562, installing OB 121 keeps the CPU in RUN, but the underlying bit-access fault at address 0 of the instance DB is still present and must be corrected by recompiling the affected FB’s instance DB.

Why does Event ID 16#2522 point at address 0 of an instance DB?

Address 0 in an instance DB is the first bit of the first declared variable. An area-length error on address 0 means the instance DB loaded on the CPU is shorter than the FB expects, almost always because the FB interface was edited and the instance DB was not regenerated.

What is the difference between OB 121 and OB 122?

OB 121 handles programming errors (bad access to a DB, type conversion errors, BCD errors, range errors on system functions). OB 122 handles I/O access errors when a direct read or write targets a missing, faulty, or powered-down module. Both should be installed in any production S7-300/400 program.

How do I permanently add OB 121 to my STEP 7 project so I do not have to copy it after every download?

Open the offline S7 program in SIMATIC Manager or TIA Portal, right-click the Blocks container, choose Insert New Object → Organization Block, and select OB 121. Compile the project and download the full Blocks container. From that point on, OB 121 is part of every download.

Can I mask specific programming errors so OB 121 is never called?

Yes. SFC 36 MSK_FLT masks synchronous errors of a specific class so the operating system no longer triggers OB 121 for them, and SFC 37 UNK_FLT unmasks them. Use masking sparingly: it is appropriate for legacy probe code that intentionally inspects module presence, not for hiding real bugs in production logic.

Back to blog