Resolving S7-1214 Retain Memory Overflow with 50 CTUD Counters

David Krause15 min read
S7-1200SiemensTroubleshooting
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 Definition: 96% Retain Memory Saturation on S7-1214C

An S7-1214C DC/DC/DC (6ES7 214-1HG40-0XB0) running firmware V4.x is being used to count cars entering and leaving a multi-tenant parking lot. The application requires approximately 50 IEC CTUD counters - two per tenant (employee counter and visitor counter) - to track how many vehicles are currently inside each tenant's allotted zone. After wiring all 50 counter instances into the program, the TIA Portal online diagnostics report that the retainable memory area is filled to 96%, and the project refuses to download with the warning "Retain memory overflow". The PV (preset) values also disappear after a power cycle even though the user requested they be retained.

The CPU 6ES7 214-1HG40-0XB0 ships with the following memory budget per the SIMATIC S7-1200 Programmable Controller System Manual:

  • Work memory: 100 KB (data + code combined)
  • Load memory: 4 MB internal, expandable via SIMATIC Memory Card
  • Retain memory: 10 KB
  • Bit memory (M): 8 KB
  • Process image input/output: 1024 bytes each

With 96% of 10 KB consumed (≈9.8 KB), only 2 KB of retain space is left. The user cannot add a single additional CTUD instance, cannot set a new PV, and cannot enable retentivity on the PV tags. The objective is to implement 50 (or 100) counting channels without exceeding the 10 KB retain budget, while still preserving both the current value (CV) and preset value (PV) across power cycles.

Root Cause: Why IEC CTUD Consumes Excessive Retain Memory

Every IEC counter used as a standalone instance creates an Instance Data Block (DB) sized at roughly 80 to 150 bytes depending on the TIA Portal version and whether the counter is placed as a multi-instance inside a Function Block. Even when the user places all 50 counters into a single global DB by declaring tags of type CTUD, each tag still occupies the full CTUD structure footprint. The relevant fields inside the CTUD instance are:

  • CU, CD, R, LD (BOOL, packed bits)
  • PV (INT, 2 bytes)
  • CV (INT, 2 bytes, often DWORD-aligned to 4 bytes)
  • Q, QU, QD (BOOL outputs)
  • Internal status / padding / CV_Hex shadow

A single CTUD instance tag therefore consumes ≈12 to 18 bytes in the global DB. 50 instances × 14 bytes (average) = 700 bytes of user-visible structure. However, if each tag is marked "Set in IDB" as retainable, the entire structure is mirrored into the retain area. Adding the system overhead for the IEC counter state machine, the 96% figure becomes consistent with a misconfigured retain mask on a multi-instance FB containing 50 counters.

Engineering note: The Siemens S7-1200 retain memory is a battery-backed (or non-volatile, on newer firmware) SRAM region. Marking the entire CTUD instance as retentive copies every BOOL, every padding byte, and every shadow word of the IEC counter - not just the CV and PV. This is the single largest source of the retain overflow.

Memory Footprint Comparison: IEC CTUD vs. Hand-Written Counter

Approach Per-Counter Bytes (User Code) 50 Counters Retain Cost (50 cnt) % of 10 KB Retain
IEC CTUD instance, fully retentive ~80 B (full instance DB) ~4000 B 4000 B ≈39%
IEC CTUD as global DB tag, fully retentive ~14 B + padding ~700 B ~700 B ≈7%
Retentive INT array for CV only 2 B 100 B 100 B ≈1%
Retentive INT array CV + INT array PV 4 B 200 B 200 B ≈2%
Retentive DINT arrays (CV + PV) + BOOL flags 9 B 450 B 450 B ≈4.4%
Load-memory DB via WRIT_DBL (no retain) 0 B retain 0 B 0 B 0%

The simplest path to a 96% reading is the first row: 50 standalone CTUD instances with all sub-tags marked retainable. Even row 2 - the most compact native configuration - leaves no headroom for additional PV-only data the user wants to keep across power cycles.

Solution 1: Replace CTUD with ADD/SUB in a Retentive Global DB (Recommended)

The most efficient pattern for a 50-channel parking counter is to abandon the IEC CTUD instruction entirely and implement the count as an ADD/SUB on an INT (or DINT) value inside a single retentive global DB. The user's application triggers - one for "vehicle entered" and one for "vehicle left" - are simply mapped to + and - operations on a per-tenant index.

Step 1 - Declare a retentive global DB. In TIA Portal, add a new DB named DB_Parking. In the DB properties, tick "Enable retain for instance data" only for the count arrays, not the entire DB. Declare the following structure:

DATA_BLOCK "DB_Parking"
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : Eng
FAMILY : Parking
VERSION : 1.0
  STRUCT
    CV_Employee : ARRAY[1..50] OF INT;   // current cars in lot per tenant
    CV_Visitor  : ARRAY[1..50] OF INT;
    PV_Employee : ARRAY[1..50] OF INT;   // tenant capacity, set at commissioning
    PV_Visitor  : ARRAY[1..50] OF INT;
    FullFlag    : ARRAY[1..50] OF BOOL;  // derived: CV >= PV
    Overflow    : ARRAY[1..50] OF BOOL;  // derived: CV < 0 or CV > PV
  END_STRUCT;
END_DATA_BLOCK

Memory cost: 50 × 2 × 4 = 400 bytes for the four INT arrays, plus 100 bits = 13 bytes for the BOOLEAN arrays, plus 7 bytes of DB header overhead = ≈420 bytes. Marked as retain, that is 4.1% of the 10 KB budget - leaving 9.6 KB free.

Step 2 - Write the counter logic in SCL or LAD. In a Function Block FB_ParkingCounter (no instance DB needed; called once per cycle), the count-update for tenant i looks like this in SCL:

// Rising-edge detection on the entry / exit inputs
IF "IN_EnterEmp" AND NOT "Edge_EnterEmpOld" THEN
    "DB_Parking".CV_Employee[i] := "DB_Parking".CV_Employee[i] + 1;
END_IF;
IF "IN_LeaveEmp" AND NOT "Edge_LeaveEmpOld" THEN
    "DB_Parking".CV_Employee[i] := "DB_Parking".CV_Employee[i] - 1;
END_IF;

// Limit checks
IF "DB_Parking".CV_Employee[i] < 0 THEN
    "DB_Parking".CV_Employee[i] := 0;
    "DB_Parking".Overflow[i] := TRUE;
END_IF;
IF "DB_Parking".CV_Employee[i] > "DB_Parking".PV_Employee[i] THEN
    "DB_Parking".CV_Employee[i] := "DB_Parking".PV_Employee[i];
    "DB_Parking".Overflow[i] := TRUE;
END_IF;

// Full indicator
"DB_Parking".FullFlag[i] :=
    "DB_Parking".CV_Employee[i] >= "DB_Parking".PV_Employee[i];

Step 3 - Call the FB in OB1 with an index loop. For 50 tenants, use a FOR i := 1 TO 50 DO loop; map i to the physical input byte that contains the entry/exit signals for that tenant. If the wiring is not per-tenant in the field, use a multi-instance FB and pass the index as an input variable.

This pattern uses zero IEC counter instructions, zero instance DBs, and exactly 420 bytes of retain. The CV and PV are both retained because they live inside the retentive global DB.

Solution 2: Store Presets in Load Memory with WRIT_DBL / READ_DBL

If the user only needs to retain the PV values (which are commissioning data and rarely change) and is willing to restart CV at zero after a power loss, the preset values can be stored in the load memory - which is non-volatile on the SIMATIC Memory Card and effectively unlimited in size. The instructions to use are WRIT_DBL and READ_DBL from the TIA Portal Extended Instructions manual.

Step 1 - Create a non-retentive DB marked "Only store in load memory". In DB properties, disable the retain attribute and enable the "Only store in load memory" option. The DB can be much larger than the work memory; the PLC pages it on demand.

DATA_BLOCK "DB_Presets"
{ S7_Optimized_Access := 'TRUE';
  LoadMemoryOnly := 'TRUE' }    // TIA Portal V17+ property
  STRUCT
    PV_Employee : ARRAY[1..50] OF INT;
    PV_Visitor  : ARRAY[1..50] OF INT;
  END_STRUCT;
END_DATA_BLOCK

Step 2 - Write presets with WRIT_DBL at commissioning. From a commissioning HMI button or a one-shot startup trigger in OB100, call:

// Pseudo-call signature in SCL
"WRIT_DBL"(REQ := bWriteReq,
           DB := "DB_Presets",
           EXECUTE := bWriteReq,
           DONE => bDone,
           BUSY => bBusy,
           ERROR => bErr,
           STATUS => wStatus);

Step 3 - Read presets on startup with READ_DBL in OB100. In the warm-restart / cold-restart OB (typically OB100), call READ_DBL to copy the preset block from load memory back into work memory before OB1 starts the count logic. This guarantees that the PV values are restored even if the PLC is power-cycled for a year.

Critical: The SIMATIC Memory Card is mandatory for this pattern. The S7-1200 load memory is internal flash (4 MB) but write cycles are limited. Use a quality SMC (Siemens 6ES7 954-8LF02-0AA0 or larger) for reliable field operation. Spare card should always be kept on site.

Solution 3: HMI Recipe Data Records for Commissioning Values

If the project includes a TP700 Comfort or similar WinCC HMI, the recipe functionality is the cleanest way to store the 50 PV values. A recipe is a structured data record saved on the HMI's flash, transferred to the PLC at startup or on demand. The PLC never has to retain the values - the HMI does.

Workflow:

  1. In TIA Portal, create a recipe named TenantPresets with 50 rows of two INT fields each (employee PV + visitor PV).
  2. Add a recipe view to the HMI screen. The commissioning engineer enters the 50 PV values on the panel and presses "Save".
  3. On PLC startup, the HMI writes the recipe to the PLC's DB_Parking in one block transfer, then sets a "RecipeLoaded" bit.
  4. The PLC's OB1 simply reads DB_Parking.PV_* - no IEC counter, no retain needed for PV.

Recipe storage capacity on a Comfort Panel is in the tens of MB - 50 PV pairs are negligible. This is the preferred approach when the customer accepts an HMI dependency.

Solution 4: Remove Retentivity from CTUD Tags, Snapshot via Startup OB

If the user is committed to keeping the IEC CTUD instruction (perhaps because the code is already written and tested), the minimum-impact fix is to:

  1. Open every CTUD instance, uncheck the Retain attribute on the CV and PV sub-elements.
  2. Create a single retentive global DB DB_CounterMirror with two INT arrays: CV_Backup and PV_Backup, sized 50 each.
  3. In OB100 (startup), copy DB_CounterMirror into the CTUD instances before the first scan of OB1. In OB1, on each cycle, mirror the CTUD.CV and CTUD.PV back into the retentive array.

This is a workaround and not recommended because the IEC counter overhead remains in work memory. Use only if a quick patch is required to clear the 96% retain alarm while a proper Solution 1 / Solution 2 redesign is being prepared.

Step-by-Step Implementation: Parking Lot Counter on S7-1214C

Combining the recommended techniques, here is a complete drop-in implementation.

Prerequisites.

  • S7-1214C DC/DC/DC, 6ES7 214-1HG40-0XB0, firmware V4.4 or later (for optimized-DB features and modern WRIT_DBL handling).
  • TIA Portal V17 or later, with S7-1200 CPU HSP installed.
  • SIMATIC Memory Card (SMC), minimum 4 MB - 6ES7 954-8LC02-0AA0 or newer.
  • For HMI recipe: TP700 Comfort or similar panel on PROFINET to the S7-1200.

Step 1 - Build the retentive DB. As shown in Solution 1, create DB_Parking with the two CV arrays, two PV arrays, and the boolean flags. Enable retain on the whole DB. Compile and check the resource allocation - the retain area should be at most 5% full.

Step 2 - Pre-load PV at commissioning. From the HMI, or via the Watch Table in TIA Portal, write the initial tenant capacities into DB_Parking.PV_Employee[1..50] and DB_Parking.PV_Visitor[1..50]. These values are now retained across every power cycle because the DB is retentive.

Step 3 - Wire the count triggers. Map the entry and exit sensors (e.g., inductive loops at the gate) to digital inputs. In OB1, build a 50-iteration loop that updates the corresponding CV array element on a rising edge of the entry or exit signal.

Step 4 - Add the full/empty logic. For each tenant, light an LED or set a flag on the HMI when CV >= PV. This is the operator-visible "lot full" signal.

Step 5 - Persist operating hours to load memory (optional). Once per shift, call WRIT_DBL to back up the CV arrays to a load-memory DB. This protects against corruption of the SRAM retain area (rare, but possible after long downtime).

SIMATIC Memory Card Sizing and Firmware Constraints

The SIMATIC Memory Card (SMC) for S7-1200 is a special Siemens-format SD card, not a generic consumer SD. Recommended part numbers:

Article Number Capacity Use Case
6ES7 954-8LC02-0AA0 4 MB Small programs, sufficient for the WRIT_DBL use case above
6ES7 954-8LE02-0AA0 12 MB Medium projects with recipe and trace
6ES7 954-8LF02-0AA0 24 MB Large projects, firmware updates, full data logging
6ES7 954-8LL02-0AA0 256 MB Web server, long-term trend, multiple language projects

Firmware V4.2 and later is required for the WRIT_DBL / READ_DBL instructions to operate on optimized DBs. Earlier firmware requires the DB to be non-optimized (standard access), which uses a different offset-based addressing scheme. If the project is on firmware V4.0 or V4.1, either upgrade the CPU (free firmware update via the SMC) or use Solution 1 exclusively.

Verification and Commissioning Tests

After the redesign, run the following tests in TIA Portal with the PLC online:

  1. Retain memory utilization. In Online & Diagnostics > Diagnostics > Memory, verify that the retain area is below 10% used. The 96% alarm must be gone.
  2. Power-cycle test. Set DB_Parking.CV_Employee[1] := 17. Power off the PLC for 30 seconds. Power on. Read DB_Parking.CV_Employee[1] - must still be 17.
  3. PV persistence. Set DB_Parking.PV_Employee[1] := 75. Power cycle. Read back - must be 75.
  4. Count logic. Toggle the entry input for tenant 1 ten times. Verify CV increments by 10. Toggle the exit input five times. Verify CV decrements by 5.
  5. Overflow protection. Force PV_Employee[1] := 3. Trigger 5 entries. Verify CV clamps at 3 and the Overflow flag goes TRUE.
  6. Multi-tenant loop. Repeat for tenants 25, 50. Verify all 50 channels update correctly with no cross-talk (each index increments only its own array element).

Troubleshooting Matrix

Symptom Likely Cause Fix
Retain memory at 96% even after Solution 1 Other global DBs are also marked retentive (e.g., a recipe DB or a HMI tag DB) Audit Project tree > PLC > Program blocks > DBs; uncheck retain on non-critical DBs
PV values disappear on power cycle DB_Parking was created with retain disabled, or optimized-DB retain attribute is not set Open DB properties > Attributes > tick Retain; recompile; reload
WRIT_DBL returns status W#16#80B1 / 80B5 SMC not inserted, full, or write-protected Check the card slot; verify free space; ensure the slide lock is not in the read-only position
READ_DBL does not restore PV on startup OB100 was not used; the read happens after OB1 has already consumed the data Move the READ_DBL call into OB100 and add a Done-flag wait
CV goes negative when a sensor bounces Missing rising-edge detection on the input Use | rising-edge operator or the R_TRIG instruction
PLC download fails with SF LED on Retain area still too large for the new project Do a factory reset (MRES) on the CPU to clear the retain area; download again
Recipe values not transferred from HMI Connection interrupted or recipe control tag area is not configured Verify the HMI connection status; check the recipe's pointer to the PLC tag

Alternative Controllers and Migration Notes

If the S7-1214C memory budget becomes too tight for future expansion (e.g., the parking grows to 200 tenants), consider upgrading to the S7-1215C (6ES7 215-1AG40-0XB0). It has 125 KB of work memory and 12 KB of retain memory, which is enough for thousands of counters in the Solution 1 pattern. The S7-1217C doubles that again. The instruction set and DB model are identical, so the migration is a hardware swap and a device reconfiguration - no code rewrite is needed.

For plants already using a LOGO! 8 or a S7-200 SMART for similar counting, the same DB-based pattern applies, but the retentive memory on those platforms is even tighter (LOGO! has no retain beyond the variable table, S7-200 SMART has only 10 KB total retain). Offloading to the SD card becomes mandatory in those cases.

Field-Proven Engineering Caveats

  • Marking a single optimized DB as Retain copies the entire DB at power-off, including the 7-byte DB header. On a 10 KB budget, that is 0.07% - negligible. But on a 2 KB retain CPU (e.g., the S7-1211C), that same header is 0.3%.
  • Never tick the Retain box on the CTUD instance and on a global DB mirror that contains the same data. The retain is copied twice and the budget is wasted.
  • The S7-1200's non-volatile retain (firmware V4.4+) is implemented as a hidden file on the SMC. It survives a power cycle but not a CPU factory reset. For true long-term storage, use WRIT_DBL to a named file on the card.
  • Always include a watchdog on the Overflow flag. In a real parking lot, a faulty inductive loop can fire dozens of times per second, eventually saturating the CV. A software debounce (50 ms minimum) on the input is mandatory.

FAQ

How much retain memory does each IEC CTUD counter use on the S7-1214C?

A standalone CTUD instance consumes approximately 80 bytes when fully retentive; placed as a tag in a global DB it still occupies 12-18 bytes of structure plus retain. For 50 counters the total is 600 B to 4 KB, easily pushing the 10 KB budget over.

Can I store 50 PV values on the SIMATIC Memory Card and forget about retain memory?

Yes. Create a non-retentive DB marked "Only store in load memory" with a 50-element INT array. Use WRIT_DBL at commissioning and READ_DBL in OB100 at startup. The PLC's retain memory is untouched; the data is stored on the SMC.

Do I need a SIMATIC Memory Card for the retain to work at all?

No. S7-1200 firmware V4.4 and later implements a non-volatile retain area that survives power cycles without a card. However, an SMC is still recommended for firmware updates, recipe storage, and the WRIT_DBL pattern. The SMC is mandatory if you want to back up presets in load memory.

Why does my PV value reset to zero after a power cycle even though the DB is retentive?

The DB was likely created with the Set in IDB retain attribute off, or the PV was being written to a tag inside a CTUD instance that was not itself retentive. Verify in DB properties > Attributes that Retain is checked, and that the PV is stored in the global DB - not inside the IEC counter's instance DB.

Is the recipe function on a TP700 Comfort reliable for long-term PV storage?

Yes. Comfort Panels store recipes on industrial-grade internal flash rated for 100,000 write cycles minimum. With one save per commissioning visit, the panel can store PV values for decades. The PLC only needs to retain the CV (current value) arrays, which fits easily in the 10 KB budget.

What is the smallest firmware version that supports WRIT_DBL on optimized DBs?

Firmware V4.2 is the minimum. V4.4 and later adds non-volatile retain (NVRAM) which removes the need for an SMC-backed retain file. Recommended firmware for new projects is V4.6 or the latest available for the 6ES7 214-1HG40 hardware version.

Back to blog