Resolving Siemens S7-300 Area Length Error OB121 CP341 Modbus

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

1. Problem Overview

On a Siemens SIMATIC S7-319-3 PN/DP CPU running TIA Portal V11 with a CP 341 (RS485) configured as a Modbus master, the following diagnostic-buffer entry appears intermittently (typically every two to four hours) and stops all Modbus polling:

Area length error when writing
Global DB, double-word access, Access address: 180
Requested OB: Programming error OB (OB 121)
Priority class: 1

The error is non-fatal in the sense that OB 121 is installed, so the CPU does not enter STOP. However, the failing write instruction belongs to the scan that drives the Modbus request index, so once the error fires, the index stops incrementing and the CP 341 master appears to "freeze". The only field-level recovery is a CPU restart.

This symptom is a classic indirect-DB access overrun on S7-300/400, and the resolution path is fully documented in the Siemens support article How do you proceed if an area length error (16# 02:2523 or 16# 02:2522) occurs in the user program of the S7-1500 CPU? and in the Programming error organization block (OB 121) (S7-300, S7-400) reference.

2. Diagnostic Buffer Interpretation

Every entry the S7-300 CPU writes to its diagnostic buffer follows a strict schema. The four fields that matter for this fault are decoded below.

Field in buffer Value reported Meaning
Event ID 16#2523 Area length error when writing. This is the S7-300 equivalent of the S7-1500 16#02:2523 event.
OB OB 121 (Programming error OB) OB 121 is invoked synchronously in the same priority class as the faulting instruction. Installing OB 121 prevents STOP but the offending access is still rejected.
Area Global DB The faulting operand is inside a shared data block (DB), not an instance DB, FB local data, bit memory, or process image.
Access Double-word, address 180 A DWORD (4 bytes) is being written to byte offset 180, so bytes 180, 181, 182, and 183 are referenced. The DB must be at least 184 bytes long.

When the CPU detects a write outside the valid range of a global DB, it raises event 16#2523, sets the area length error when writing bit in OB121_RESERVED_1, and transfers the faulting block number and offset into the OB 121 local data. The exact byte layout is given in the next section.

3. OB 121 Error Code Reference (S7-300/400)

OB 121 contains a snapshot of the faulting instruction. Local data byte 8 (B#16#) is the error code. The relevant codes for the S7-319 symptom are summarised below; the full table is maintained in the TIA Portal OB 121 reference.

Local-data byte (B#16#) Meaning Typical cause
22 Area length error when reading Indirect pointer resolves below 0 or above DB length-1 on a read.
23 Area length error when writing Indirect pointer resolves below 0 or above DB length-1 on a write. The reported case.
24 Area length error when reading (bit access) Bit offset outside the byte boundary of the addressed byte.
25 Area length error when writing (bit access) Bit offset outside the byte boundary of the addressed byte.
28 Read access to a byte, word or double word at odd address Word/DWORD read on a non-aligned address (S7-300 only; S7-400 performs implicit byte-swap).
29 Write access to a byte, word or double word at odd address Word/DWORD write on a non-aligned address (S7-300 only).
Alignment check on S7-300: The 319-3 is an S7-300 family CPU. Accessing a DWORD on byte 180 is legal (180 is even) and properly aligned, so the error is purely a length error, not an alignment error. If the address were 181, code B#16#29 would be expected instead of B#16#23.

4. Root Cause Analysis

The Modbus master on a CP 341 is typically driven by a user-engineered scan block that walks through a list of slave nodes. The pattern in the source case is:

  1. A global DB holds the polling table (node number, function code, register range, timeout, retry count, last error, etc.).
  2. An index tag (DWORD or INT) in the same DB selects the current row.
  3. On each cycle the program reads the row at base_offset + index * row_size, issues a P_SND_RK / P_RCV_RK pair, and increments the index.
  4. When all rows are exhausted the index is wrapped to 0 and the scan repeats.

For an S7-300/400 with a global DB, the row size is most often 16 or 20 bytes. With 10 rows the table occupies 160 or 200 bytes. The reported access address is 180, which is in the gap between a 9-row table of 20-byte rows (180 bytes total) and a 10-row table (200 bytes). This strongly indicates:

  • The DB was sized for 9 entries (180 bytes), but the index counter has been allowed to advance to 10 before being wrapped, OR
  • The index is a DWORD that was previously a WORD and now carries upper bytes that push the computed offset past the end of the DB, OR
  • An edge condition (comm loss, retry, exception branch) skips the wrap-around statement L 0; T "DB_xxx".Index.

Each of the above paths produces the same observable: the calculated address 180, the area length error, the OB 121 call, and the freezing of the master scan because the index never updates again after the rejected write.

5. CP 341 Modbus Master Specifics

The CP 341 is shipped with the optional Modbus master/slave driver ("Modbus Master V3.x" or "Modbus Slave V3.x") which exposes two function blocks:

FB Name Role Notes
FB 7 MODBUS Master, half-duplex point-to-multipoint Classic MODBUS FB, parameterised via the instance DB; uses P_SND_RK / P_RCV_RK internally.
FB 8 MODBUS_2P Master, point-to-point with two-handshake Used for two-wire RS485 with RTS-controlled direction switching; the FB 8 instance is what is loaded on the CP 341 in this configuration.

User code in the S7-300 typically reads the STATUS output word of FB 7 / FB 8, drives the next request when DONE is set, and increments a poll index. The Modbus request structure REQ points to a data area in the user DB. The faulting DWORD write in the diagnostic buffer originates either in the user-defined scan block or in a hand-coded pre/post processing block that copies reply data into the table. In every case the access is indirect through the index, which is the precondition for the overrun.

6. Step-by-Step Diagnostic Procedure in TIA Portal V11

Use this procedure to localise the exact instruction that triggers 16#2523. It mirrors the workflow described in the Siemens Knowledge Base article 109975094, adapted for the S7-300/400 diagnostic buffer UI in TIA Portal V11.

  1. Establish an online connection to the CPU and select the device in the project tree.
  2. Open Online & Diagnostics and switch to the Diagnostics buffer view.
  3. Find the Area length error when writing entry, right-click and select Open in editor. TIA Portal V11 opens the block that was active when OB 121 was called, with the cursor positioned at the faulting network.
  4. Open a Watch table containing the global DB and the index tag. Add the computed offset using the formula: Offset = DBW_BaseOffset + Index * RowSize.
  5. Trigger a single scan with Monitor / Modify in single-step mode. Watch the index value just before the failing write; the value is the smoking gun.
  6. Right-click the block in the project tree and choose Call structure to confirm the full call hierarchy and the call depth recorded in OB 121 local data byte 7.
  7. Open the cross-reference (Ctrl+Shift+F) for the index tag and list every read and write. Any read that is not paired with a corresponding bounds check is a candidate root cause.

If the offending block cannot be opened from the buffer entry (older projects, blocks loaded without symbols), the same information is recovered manually from OB 121 local data:

OB 121 byte Content Value to look for
Byte 8 Error code (B#16#23) 0x23
Bytes 9..10 Block number (high/low) Number of the DB that was being written.
Bytes 11..12 Block type / area 0x0A = global DB.
Bytes 13..16 Reserved
Bytes 17..24 Faulting operand address / offset Byte 180 in this case.

7. Resolution: Code Corrections

Apply the following corrections in the order given. The goal is to make the index a bounded variable and to remove every path that can write a value larger than RowCount - 1.

7.1 Bind the index with explicit upper and lower limits

// STL snippet for the S7-319-3
L     "Poll".Index            // current value
L     0                       // lower bound
<I                             // must be >= 0
JC    ERR_UNDER
L     "Poll".Index
L     "Poll".RowCount          // upper bound (exclusive)
>=I                            // must be < RowCount
JC    ERR_OVER
// ...existing scan logic...
L     "Poll".Index
+     1
T     "Poll".Index            // increment

ERR_OVER: L 0
          T "Poll".Index        // wrap to 0
ERR_UNDER: BE

7.2 Resize the polling DB to the real row count

Open the DB in TIA Portal V11, switch to the data view, and confirm the declared STRUCT length. A DB sized at 180 bytes supports exactly 9 rows of 20 bytes. Either:

  • Add the missing row to the STRUCT, recompile, and download (preferred), or
  • Reduce the row count in the constant Poll.RowCount from 10 to 9, recompile, and download.
Download consistency: When you change a global DB on an S7-300 you must run Download to device > Software (all blocks), not a delta download, so that the actual length on the CPU matches the offline project. A length mismatch on a global DB is itself a source of 16#2523.

7.3 Replace the index with a modulo construct

For Modbus masters that scale the index dynamically (e.g. when slaves are added or removed at runtime), use a wrap-on-overflow form so that no exception branch is required:

L     "Poll".Index
L     1
+I
L     "Poll".RowCount         // base + 1, then mod row count
MOD
T     "Poll".Index

7.4 Install OB 121 with a safe local-data guard

OB 121 is already installed, but its local data should be copied to a diagnostic DB so that the post-mortem is recoverable. Create a small FC that reads OB121_SW_FAULT, OB121_RESERVED_1 and the address fields, and CALL it from the very first network of OB 121.

7.5 Re-download the project to the CP 341

If the CP 341 Modbus parameter assignment was changed, re-load the CP 341 configuration. The CP 341 retains its loaded Modbus driver in flash, so a power-cycle is recommended after the parameter download.

8. Verification Procedure

  1. Stop the CPU, download the corrected project (Software, all blocks), and perform a cold restart.
  2. Open the Watch table and force Poll.Index = 0. Confirm that Poll.Index now increments 0, 1, 2, ..., RowCount - 1, 0, 1, ... indefinitely.
  3. In Online & Diagnostics > Diagnostics buffer, confirm that no new 16#2523 entry is written over a 24-hour soak test.
  4. Use a Modbus slave simulator (for example a second CP 341 configured as a slave, or any third-party Modbus server) and verify that every entry in the polling table is actually queried at the configured cycle time.
  5. Disable the master scan, increment the index manually beyond RowCount - 1 in the Watch table, and confirm that the wrap branch resets it to 0 without raising an OB 121 event.
  6. Read the diagnostic buffer of the CP 341 (the CP 341 has its own buffer accessible via its online diagnostics) to confirm there is no companion CP-side fault such as 16#0A0A (frame error) that would mask the application fix.

9. Preventive Engineering Practices

Area-length errors on S7-300 global DBs are a structural risk in any project that uses indirect addressing. Adopt the following as project standards:

  • Single source of length. Define a CONST block (or DB of constants) holding DB_LENGTH and ROW_SIZE, and derive ROW_COUNT = DB_LENGTH / ROW_SIZE as a compile-time constant. Never hand-code ROW_COUNT.
  • Bounds-check every indirect access. Any instruction that uses an index in a DB pointer must be preceded by an explicit check on the index. A failing bounds check should write the index to 0 and set a status bit, never raise an error.
  • Symbolic-only addressing. Use the symbolic view of the DB in TIA Portal. The compiler will reject obvious overruns; the remaining overruns are the ones that occur only at runtime, exactly the case described here.
  • OB 121 always present. Although OB 121 prevents STOP, install it with a small diagnostic FC that timestamps the event into a ring buffer. The ring buffer gives a multi-hour back-trace that the diagnostic buffer does not.
  • DB length reconciliation on every download. Make it a rule that a global DB change is always downloaded as a full Software (all blocks) load, never as a delta. A stale DB on the CPU is a frequent second cause of 16#2523 events that look like application bugs.
  • Modbus master resilience. On the CP 341, set the Number of retries and Response timeout in the CP parameter assignment (HW Config > CP 341 > Parameter > Modbus Master) so that a transient slave failure does not starve the scan, which is the typical trigger for the index to fall out of its expected sequence.

10. Frequently Asked Questions

What does "Area length error when writing" (16#2523) mean on an S7-300?

It is event 16#2523 from the OB 121 reference: a write to a global DB has used an address that lies outside the declared length of the block. The S7-1500 equivalent is event 16#02:2523 covered by Siemens KB 109975094.

Why does my CP 341 Modbus master freeze after the 16#2523 event and not retry?

The faulting write is part of the scan block that updates the polling index. Once the write is rejected, the index is not updated, so the same node keeps being polled indefinitely and the scan appears frozen. A CPU restart clears the condition because the index is reinitialised to 0 on restart, but the underlying overrun will repeat unless the index is bounded.

My DB is declared as 200 bytes, why am I still getting the error at address 180?

Check that the project has been fully downloaded (Software, all blocks) and that the online view of the DB in TIA Portal V11 shows 200 bytes. A common cause is a delta download that changed the offline DB but left an older, shorter copy on the CPU. Open the DB in the online view and compare byte counts.

Is "Access address 180" a bit offset or a byte offset?

It is a byte offset within the global DB. With a double-word access, bytes 180, 181, 182, and 183 are referenced, so the DB must be at least 184 bytes long. If the access had been a bit access the buffer would have shown bit and byte components and the error code would have been B#16#25 instead of B#16#23.

Where in TIA Portal V11 do I find the call stack for the failing instruction?

In the Diagnostics buffer, right-click the 16#2523 entry and choose Open in editor. TIA Portal V11 opens the active block at the faulting network. To view the call hierarchy that led to it, right-click the block in the project tree and select Call structure; the depth recorded there matches the value in OB 121 local-data byte 7.

Back to blog