S7-1200 CPU 1214: Storing 60 Sets of 4 Analog Values in a DB

David Krause11 min read
S7-1200SiemensTutorial / How-to
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 Definition and Engineering Scope

An S7-1200 CPU 1214C is exchanging four Real (32-bit IEEE-754) process values with a third-party controller (Allen-Bradley MicroLogix/CompactLogix via RSLogix) over OPC through PC Access. When the OPC link drops, the CPU must continue sampling the four analog inputs and buffer the last 60 valid sets locally in a Data Block (DB) so they can be re-played or analysed when the link is restored.

The storage requirement is fixed by the application:

Item Value Bytes
Channels per sample 4 Real (32-bit) 16
Samples retained 60 960
Total payload 240 Real 960
Index/control overhead 2 DInt + 1 Bool 9
Recommended DB size (rounded) 1024

960 bytes is well inside the load-memory and work-memory limits of the 1214C, even on firmware 1.0.2. The real engineering challenge is not capacity; it is the lack of a true pointer on early S7-1200 firmware and the need to index into the buffer on every sample tick without copying the entire 960-byte block.

2. Prerequisites and Compatibility Matrix

Pick the implementation that matches the tool chain you actually own. The instruction set available on the S7-1200 changed materially between TIA Portal V10.5 and V11.

Method TIA Portal CPU Firmware Indexed write? Block name (EN)
FieldRead / FieldWrite V10.5 SP2 (or later) 1.0.2 or later Yes (offset input) FieldRead / FieldWrite
MOVE_BLK V10.5 or later 1.0 or later No (linear copy) MOVE_BLK
POKE / POKE_BLK V11 or later 2.0 or later Yes (pointer) POKE / POKE_BLK
Array index + LOOP V10.5 or later 1.0 or later Yes (via DB_ANY) Variant + symbolic array

Authoritative references:

Hardware prerequisite: FieldRead/FieldWrite need firmware 1.0.2. If your CPU is still on 1.0.0 or 1.0.1, update it through the TIA Portal "Online > Accessible devices > Go online > Online & Diagnostics" path before commissioning the buffer logic.

3. Data Block Layout

Create one optimised DB named DB_AnalogBuffer with the following structure. Optimised block access is mandatory; the FieldRead/FieldWrite and POKE_BLK instructions are validated against symbolic, optimised access only on S7-1200.

DATA_BLOCK "DB_AnalogBuffer"
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : Prashant
FAMILY : Buffer
VERSION : 0.1
  STRUCT
    // ---- control ----
    bEnable       : BOOL;          // OPC link up = TRUE, FALSE = buffer
    iWriteIndex   : DINT;          // 0..59, next slot to write
    iReadIndex    : DINT;          // 0..59, next slot to read on replay
    iSampleCount  : DINT;          // number of valid samples (max 60)
    // ---- payload ----
    aSamples      : ARRAY[0..59, 0..3] OF REAL;   // 60 x 4 Reals = 960 B
  END_STRUCT;
END_DATA_BLOCK

Why the DINT indexes live in the same DB: the pointer variant of FieldRead/FieldWrite works only on DInt/Real/Byte, and keeping the index co-located with the payload means the entire 968-byte block is fetchable with a single symbolic reference.

4. Method A – FieldRead / FieldWrite (Recommended for V10.5 SP2)

FieldRead and FieldWrite were added in STEP 7 Basic V10.5 SP2 specifically to bring pointer-like indexed access to the S7-1200 line. They exist in the instruction tree, but Siemens hides them by default: they are not in the Instructions task card; they only appear when you type Field into an empty network placeholder.

4.1 Operation

  • FieldWrite writes a single Real at a calculated byte offset inside a DB.
  • FieldRead reads a single Real at a calculated byte offset inside a DB.
  • The INDEX input multiplies FIELD_SIZE by the index to compute the byte offset, eliminating manual pointer math in STL.

4.2 LAD snippet (write side)

      // --- every 100 ms, if bEnable = FALSE ---
      OPN   "DB_AnalogBuffer"                       // open the buffer DB
      L     "DB_AnalogBuffer".iWriteIndex           // 0..59
      ITD                                        // DINT
      DTR                                        // REAL, but use DINT scaling
      // easier: use INDEX input directly as INT

      // Network 1: write ch0
            EN            ENO
      "DB_AnalogBuffer".iWriteIndex  ->  FieldWrite.INDEX        // offset multiplier
      4                                  FieldWrite.FIELD_SIZE    // 4-byte Real
      16                                 FieldWrite.OFFSET        // base byte of row 0
      "AI_Word_0_Raw"                    FieldWrite.VALUE_IN      // source Real
      "DB_AnalogBuffer".aSamples         FieldWrite.DBNO          // destination DB
      

For the four channels of sample N:

Channel OFFSET (bytes) Source tag
Ch0 16 + N*16 + 0 AI_Word_0_Raw
Ch1 16 + N*16 + 4 AI_Word_1_Raw
Ch2 16 + N*16 + 8 AI_Word_2_Raw
Ch3 16 + N*16 + 12 AI_Word_3_Raw

The 16-byte base offset is the byte width of the control area (bEnable + iWriteIndex + iReadIndex + iSampleCount). With the optimised layout above, the array itself starts at DBB 16 (or whatever TIA Portal reports in the "Offset" column when you click the array in the DB editor – always trust the compiler-reported offset).

4.3 Edge cases

  • Wraparound: the writer must roll iWriteIndex from 59 back to 0 with a CTU or a simple IF iWriteIndex > 59 THEN iWriteIndex := 0; END_IF; in a cyclic OB.
  • Atomicity: writing 4 Reals as four separate FieldWrite calls is fine because the S7-1200 will not interrupt mid-instruction; however, if the HMI also reads the array, declare the DB as non-optimised only if you truly need to share it with PC Access through the S7-1200 OPC-DA server. PC Access against an optimised DB works through the symbolic name; raw byte access is not required.

5. Method B – MOVE_BLK (Sequential Shift Register)

MOVE_BLK is a non-indexed, bounded copy: source array -> destination array, N elements. It is useful only if you treat the buffer as a shift register (FIFO without explicit index) or if you pre-arrange 60 separate REAL tags and rotate them by hand.

5.1 LAD call

      // copy latest 4-channel snapshot into current slot
        MOVE_BLK
          SRC    :=  %DB5.DBX0.0 BYTE 4      // 4 Reals = 16 bytes
          DST    :=  %DB10.DBX0.0 BYTE 4
          COUNT  :=  4
          DONE   ->  

To implement a 60-deep ring buffer with MOVE_BLK alone you must update four DBs in a chain every cycle, which burns roughly 15 µs of OB1 time on a 1214C and is not recommended. Prefer Method A or C for a real ring.

6. Method C – POKE / POKE_BLK (TIA Portal V11+, FW 2.0+)

If you can move to TIA Portal V11 (STEP 7 Basic V11) the S7-1200 gains real POINTER and VARIANT handling, including the dedicated POKE and POKE_BLK instructions. POKE_BLK lets you write an arbitrary source area into an arbitrary destination area with a calculated pointer, which is functionally equivalent to a BLKMOV with destination indexing.

6.1 SCL example (V11)

// Cyclic OB1, executed while bEnable = FALSE
FOR i := 0 TO 59 DO
    IF "DB_AnalogBuffer".aSamples[i,0] = 0.0 AND
       "DB_AnalogBuffer".iSampleCount > 0 THEN
        // slot i is empty (init), fill it
        "DB_AnalogBuffer".aSamples[i,0] := "AI_Word_0_Raw";
        "DB_AnalogBuffer".aSamples[i,1] := "AI_Word_1_Raw";
        "DB_AnalogBuffer".aSamples[i,2] := "AI_Word_2_Raw";
        "DB_AnalogBuffer".aSamples[i,3] := "AI_Word_3_Raw";
        EXIT;
    END_IF;
END_FOR;

For high-speed bursts use a calc-pointer:

// POKE_BLK with pointer arithmetic
"DB_AnalogBuffer".iWriteIndex := ("DB_AnalogBuffer".iWriteIndex + 1) MOD 60;
pSourceArea := P#"DB_Live".DBX0.0;        // 4 Reals packed
pDestArea   := P#"DB_AnalogBuffer".aSamples["DB_AnalogBuffer".iWriteIndex,0];
POKE_BLK(src := pSourceArea, dst := pDestArea, count := 16);

7. Method D – Array Index Without Pointers (Firmware ≥ 1.0)

If you cannot update TIA Portal and are stuck on V10.5 without SP2, the entire ring buffer can still be implemented with a symbolic array of Real and a TAG index. The PLC does the index math, not the user.

// OB1 – scan cycle
IF NOT "DB_AnalogBuffer".bEnable THEN
    "DB_AnalogBuffer".aSamples["DB_AnalogBuffer".iWriteIndex, 0] := "AI_Word_0_Raw";
    "DB_AnalogBuffer".aSamples["DB_AnalogBuffer".iWriteIndex, 1] := "AI_Word_1_Raw";
    "DB_AnalogBuffer".aSamples["DB_AnalogBuffer".iWriteIndex, 2] := "AI_Word_2_Raw";
    "DB_AnalogBuffer".aSamples["DB_AnalogBuffer".iWriteIndex, 3] := "AI_Word_3_Raw";
    "DB_AnalogBuffer".iWriteIndex :=
        ("DB_AnalogBuffer".iWriteIndex + 1) MOD 60;
    IF "DB_AnalogBuffer".iSampleCount < 60 THEN
        "DB_AnalogBuffer".iSampleCount :=
            "DB_AnalogBuffer".iSampleCount + 1;
    END_IF;
END_IF;

Indexing into a Real array with a DINT tag is fully supported on S7-1200 from firmware 1.0; runtime overhead is ~3 µs per indexed access on a 1214C. This is the most portable of the four methods and is what most production machines end up shipping.

8. OPC / PC Access Replay Path

When the OPC link returns, PC Access (on the engineering PC) reads the buffer back through the S7-1200's built-in OPC-DA server. The server can only see the current value of each tag, not the array history. To make the 60 samples consumable, expose either:

  1. 60 individual Real tags – copy the array elements into a flat STRUCT of 60 Reals, and have PC Access poll the flat view; or
  2. An index tag + one current-sample tag – PC Access reads iReadIndex and aSamples[iReadIndex,0..3]; the AB side steps iReadIndex between polls.

Either path requires that the DB be marked non-optimised in older TIA Portal versions if PC Access uses absolute addresses; with TIA V13+ and PC Access V2.3+, symbolic access is supported and the DB can stay optimised.

9. Memory Sizing and Cycle Time

CPU 1214C variant Work memory Load memory Retentive 960 B DB fits?
1214C DC/DC/DC (6ES7214-1AE30-0XB0) 50 KB 2 MB 10 KB Yes
1214C DC/DC/RLY (6ES7214-1BE30-0XB0) 50 KB 2 MB 10 KB Yes
1214FC (fail-safe) 75 KB 4 MB 14 KB Yes

If you want the buffer to survive a power cycle, mark DB_AnalogBuffer as retentive under "Properties > Attributes > Retain". Ten kilobytes of retentive memory is more than enough for the 968-byte payload plus a few KB of control tags.

Cycle time impact on a 1214C with firmware 2.0:

  • Indexed array write (Method D): 12 µs per sample (4 Reals), so a 100 ms cycle has 99.99 % headroom.
  • FieldWrite (Method A): 18 µs per Real x 4 = 72 µs per sample.
  • POKE_BLK (Method C): 24 µs per sample including pointer setup.

10. Commissioning Verification

  1. Online > Watch table: create a watch table with iWriteIndex, iSampleCount, and the first 8 elements of aSamples; force bEnable := FALSE and force 4 different Real values into the source tags. After 60 samples, iWriteIndex should roll to 0 and iSampleCount should clamp at 60.
  2. Online > Monitor & force: confirm each sample row contains 4 valid IEEE-754 Reals (no NaN or Inf).
  3. OPC smoke test: in PC Access, add the buffer DB; drag each row's tag into a Microsoft Excel cell via the DataLogger and confirm 60 distinct time-stamped rows appear in the workbook.
  4. Replay test: re-establish the OPC link, step iReadIndex 0..59 from the AB side, and confirm the values are exactly the ones originally forced in step 1.
  5. Retain test: power-cycle the CPU. The buffer must come back populated. If it does not, the DB is not marked retentive.

11. Troubleshooting Matrix

Symptom Likely cause Fix
FieldRead/FieldWrite do not appear in the Instructions task card Not the right tool-chain level Drop an empty network box and type Field; switch to STEP 7 Basic V10.5 SP2 minimum.
Compiler reports "Invalid OFFSET" on FieldWrite OFFSET was hard-coded in STL and does not match the optimised DB layout Open the DB, click the array, copy the byte offset from the "Offset" column.
Values overwrite each other in unexpected rows iWriteIndex not incremented inside the same OB1 scan, or wraparound math missing Add the MOD 60 roll-over; confirm the index is on the same priority class as the write.
PC Access cannot see the array tags DB is optimised and PC Access uses absolute addressing Switch DB to "Non-optimised" access, or upgrade PC Access to a symbolic-aware version (V2.3+).
All 60 samples = 0.0 after power-cycle DB not marked retentive DB properties > Attributes > Retain = TRUE.
Sample ticks run even when OPC is up bEnable not driven from the OPC link state Use a TIA OPC_DA heartbeat tag, or have PC Access write a 1 Hz pulse into bEnable.
SF LED on, diagnostic buffer: "Area length error" Pointer arithmetic in Method C points past the DB end Wrap the POKE_BLK call in a TRY-CATCH (SCL) and decrement the index when the offset would exceed 968.

12. FAQ

Do I have to upgrade firmware to use FieldRead and FieldWrite?

Yes. FieldRead/FieldWrite require CPU 1214C firmware 1.0.2 or later and STEP 7 Basic V10.5 SP2 or later. Earlier firmware silently rejects the instructions and the network downloads as a syntax error.

How much memory does a 60 x 4 Real buffer actually consume?

960 bytes for the array plus 9 bytes of control tags. With optimised block access TIA Portal rounds the DB to the next 16-byte boundary, so allocate ~1024 bytes. Retentive memory budget on a 1214C is 10 KB – more than enough.

Can I read the 60 samples back from PC Access directly?

Yes, but the S7-1200 OPC-DA server exposes the current value of each tag. Either expose 240 individual Real tags (60 rows x 4 channels) or use an index tag that PC Access steps through 0..59, reading a single "current sample" tag.

Is there a pure-Array, no-pointer method that works on firmware 1.0?

Yes. Declare an ARRAY[0..59, 0..3] OF Real in a symbolic DB and use a DINT index tag. The S7-1200 supports indexed array access from firmware 1.0; the runtime cost is roughly 12 µs per indexed write.

Which method is best for a 100 ms sample rate on a 1214C?

Method D (symbolic array + DINT index) is the most portable and the fastest to commission, at ~12 µs per sample. Use Method A (FieldWrite) only when you need byte-level offsetting for legacy code, and Method C (POKE_BLK) only on TIA Portal V11+ where full pointer support is available.

Back to blog