Reading S7-1500 CPU Firmware Version in SCL Using GET_IM_DATA

David Krause16 min read
SiemensTIA PortalTutorial / 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

Reading the S7-1500 CPU Firmware Version in SCL with GET_IM_DATA

This technical reference explains how to read the firmware version of a SIMATIC S7-1500 CPU (including the S7-1517 used in the field case that motivated this article) directly from SCL code. The method is based on the standard library instruction GET_IM_DATA from the "SIMATIC; Identification & Maintenance" library, which is part of the TIA Portal default installation. The same approach applies to S7-1200 CPUs and ET 200SP / ET 200MP stations, with the caveat that the available IM (Identification & Maintenance) data slots vary by module type and firmware generation.

The driving use case is the function block IO2MOD and similar vendor libraries that change behavior at firmware cutover points (for example, behavior on an S7-1517 is stable from firmware V2.6.0 and up, while V2.5.x requires manual hardware-ID entry). Detecting the runtime firmware from SCL lets a program gate calls to such blocks and fall back to a user-supplied hardware identifier, avoiding hard faults caused by calling V2.6-only operations against a V2.5 CPU image.

Audience and scope. This document is written for automation engineers commissioning or maintaining TIA Portal V15.1 and later projects on S7-1500 / S7-1200 controllers. The code blocks are valid SCL (Structured Control Language) and can be pasted directly into a TIA Portal FC, FB, or OB. Where parameter values are CPU-family dependent, the table notes that explicitly.

1. Why Detect the CPU Firmware at Runtime?

Several scenarios force the engineer to query the live firmware version of a CPU at program runtime rather than relying on the offline project version:

  • Library version-gating. Blocks such as IO2MOD, motion-control FBs, OPC UA server FBs, and several diagnostic FBs advertise a minimum firmware version. Calling them on an older runtime produces a temporary error (for example, error code 0x8001 / "Internal error" on the STATUS output) that the application must evaluate.
  • Hot-spare / spare-part migration. When a CPU is replaced under a maintenance contract, the spare may be flashed to a different firmware than the original. Without runtime detection the application continues to call code paths that target the original firmware generation.
  • Centralized project templates. A multi-machine project template can be deployed across an entire fleet. Runtime firmware detection lets the same compiled program run on V2.5, V2.6, V2.8, and V2.9 CPUs without forcing the engineer to maintain per-firmware code branches offline.
  • Audit / lifecycle reporting. An HMI screen or web-server page can display the live firmware of the controlling CPU for documentation during FAT/SAT.

2. GET_IM_DATA Function Fundamentals

GET_IM_DATA is a standard instruction that reads the Identification & Maintenance (I&M) data records of a module. I&M data is non-volatile, manufacturer-written or user-writable metadata stored on the module itself; data record 0 (IM0) contains the module order number, serial number, hardware revision, and the firmware version of the module.

The instruction signature is:

// TIA Portal instruction block
"GET_IM_DATA" (LADDR := <hardware identifier>,
                IM_TYPE := <INT>,
                IM_DATA := <Array[*] of BYTE>,
                DONE => <BOOL>,
                BUSY => <BOOL>,
                ERROR => <BOOL>,
                STATUS => <WORD>,
                RD_ID := <DWORD>);
Parameter Type Direction Description
LADDR HW_IO (Word) Input Hardware identifier of the target module (CPU, head module, or I/O module).
IM_TYPE INT Input Index of the I&M data record to read (0..4 for I&M0..I&M4).
IM_DATA Array[*] of BYTE InOut Destination buffer; minimum 64 bytes for IM0/IM1, 128 bytes for IM2, 64 bytes for IM3, 54 bytes for IM4.
DONE BOOL Output Set for one cycle when the read completes successfully.
BUSY BOOL Output TRUE while the asynchronous read is in progress.
ERROR BOOL Output TRUE if the read finished with an error.
STATUS WORD Output Detailed status / error code; see Siemens standard library help.
RD_ID DWORD Output Internal job ID for the asynchronous record-read mechanism.

The instruction is asynchronous: it must be called cyclically (typically in OB1) until DONE or ERROR rises. Calling it once does not produce a result; the internal record-read job completes only after several OB1 cycles.

3. IM_TYPE Parameter Values and What Each Returns

The IM_TYPE input selects which I&M record the function reads. For firmware detection, IM_TYPE := 0 is the relevant value, because I&M0 is the only record that contains the module firmware.

IM_TYPE Record Size (bytes) Content Typical Use
0 I&M0 64 Manufacturer ID, Order number (MLFB), Serial number, Hardware revision, Firmware version, Revision counter Module identification, firmware version extraction.
1 I&M1 64 Plant identifier, Location identifier Asset tagging, location code.
2 I&M2 128 Installation date Audit trail.
3 I&M3 64 Descriptor (free text) User comments.
4 I&M4 54 Signature (optional, vendor-written) Tamper detection (not always populated).
I&M0 layout for the CPU. The first 10 bytes are the manufacturer ID ("SIEMENS"), the next 20 bytes the order number (e.g. 6ES7 517-3AP00-0AB0), bytes 30..31 the hardware revision, and bytes 32..33 the firmware version encoded as two unsigned 8-bit numbers: major (byte 32) and minor (byte 33). This is the same convention used by the TIA Portal "Online > Diagnostics > Module information" view, so a value of 02 06 at offset 32/33 decodes to V2.6, and 02 09 to V2.9.

4. Selecting the Correct Hardware Identifier for the CPU

TIA Portal exposes 11 system constants (and often more, depending on project configuration) under the CPU's "System constants" node. They are the symbolic HW identifiers used by the program. For GET_IM_DATA the LADDR must point to the CPU itself, not to a module in the backplane or a PROFINET device.

The typical system constants for an S7-1517 / S7-1518 CPU are:

System constant Type Meaning Use with GET_IM_DATA?
Local~PROFINET_interface_1 PROFINET IO system PN interface of the CPU No
Local~PROFINET_interface_2 PROFINET IO system Second PN interface (CPU variant dependent) No
Local~PROFIBUS_interface_1 PROFIBUS DP master DP master on the CPU No
Local~ (no further text) CPU (own station) The CPU itself Yes
Headmodule IM / head module Used for ET 200SP / ET 200MP stations Yes (only for distributed I/O)
Module 1, Module 2, ... I/O modules Backplane / slot modules Yes (read I&M of I/O)
Submodule 1 ... Submodules Channels, ports Rarely; record layout differs

The relevant constant for reading the CPU firmware is the one that resolves to the CPU's own hardware object. The simplest way to find it is:

  1. Open the project's PLC tag table or the FC/FB where the call will be made.
  2. Click into the LADDR input of GET_IM_DATA; the autocomplete shows all system constants of the assigned CPU.
  3. Select the constant whose name is just the local station name, e.g. PLC_1 or whatever the station was renamed to. In a default project this appears as the "Local~" entry without a trailing interface name.
Pitfall. If LADDR is set to a sub-module or an I/O module hardware identifier, GET_IM_DATA still returns successfully, but the bytes at offset 32/33 contain the firmware of that module, not the CPU. Always confirm by cross-checking the order number (offset 10..29) against the CPU's MLFB (e.g. 6ES7517-3AP00-0AB0 for the S7-1517).

5. Complete SCL Implementation

The following code is a self-contained FB that reads the CPU firmware version once at startup and exposes a tag containing major and minor version numbers. It can be dropped into a project to gate calls to firmware-dependent blocks.

FUNCTION_BLOCK "FB_FirmwareDetect"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      i_hwIdCpu        : HW_IO;          // LADDR: HW identifier of the CPU itself
      i_hwIdFallback   : HW_IO;          // LADDR: optional, last good LADDR for IO2MOD
   END_VAR
   VAR_OUTPUT
      o_major          : USINT;          // Firmware major (e.g. 2 for V2.6)
      o_minor          : USINT;          // Firmware minor (e.g. 6 for V2.6)
      o_isV2_6_OrUp   : BOOL;           // TRUE if firmware >= V2.6
      o_ready          : BOOL;           // TRUE once read succeeded
      o_error          : BOOL;           // TRUE if last read failed
      o_status         : WORD;           // STATUS output of GET_IM_DATA
   END_VAR
   VAR
      s_im0            : Array[0..63] of BYTE;   // Buffer for I&M0 (64 bytes)
      s_done           : BOOL;
      s_busy           : BOOL;
      s_error          : BOOL;
      s_status         : WORD;
      s_rdId           : DWORD;
      s_execute        : BOOL := TRUE;   // Trigger one-shot read at startup
   END_VAR
BEGIN
   // 1. Trigger a single I&M0 read on the first call. Reset the trigger
   //    after a successful or failed read so the call does not repeat
   //    every cycle.
   IF s_execute THEN
      "GET_IM_DATA"(
         LADDR   := i_hwIdCpu,
         IM_TYPE := 0,
         IM_DATA := s_im0,
         DONE    => s_done,
         BUSY    => s_busy,
         ERROR   => s_error,
         STATUS  => s_status,
         RD_ID   => s_rdId);

      IF s_done OR s_error THEN
         s_execute := FALSE;
         IF s_done THEN
            // 2. Decode major/minor from offset 32 / 33 per I&M0 spec.
            o_major  := s_im0[32];
            o_minor  := s_im0[33];
            o_isV2_6_OrUp := (o_major > 2) OR (o_major = 2 AND o_minor >= 6);
            o_ready  := TRUE;
            o_error  := FALSE;
         ELSE
            o_ready  := FALSE;
            o_error  := TRUE;
         END_IF;
         o_status := s_status;
      END_IF;
   END_IF;
END_FUNCTION_BLOCK

Calling pattern in OB1 (or another cyclic OB) once the FB has been instantiated in the project:

// OB1 — read CPU firmware once at start of cycle, then skip the call.
"iDB_FwDetect"( i_hwIdCpu      := "Local~",
                i_hwIdFallback := 0,
                o_major        => "stFwMajor",
                o_minor        => "stFwMinor",
                o_isV2_6_OrUp => "stUseIo2Mod",
                o_ready        => "stFwReady",
                o_error        => "stFwError",
                o_status       => "stFwStatus");

// Conditional call: IO2MOD only on V2.6+.
IF "stFwReady" AND "stUseIo2Mod" THEN
   "IO2MOD"( hwId := "Local~DI_1",
             ... );
ELSE
   // V2.5 path: engineer-supplied hardware IDs from a project constant.
   "IO2MOD_legacy"( hwId := "DB_Constants".hwIdUser[1],
                    ... );
END_IF;

6. Cyclic-Call Impact on the PLC Cycle Time

The original question raised in the field discussion is whether the cyclic call to GET_IM_DATA (or to IO2MOD) inflates the OB1 cycle time. The answer depends on how the call is made.

6.1 First read: 1 to 3 OB1 cycles per I&M record

The first invocation of GET_IM_DATA queues an asynchronous RDREC (read record) job internally. The job travels through the backplane or PROFINET, and the result is delivered in a later OB1 cycle. On an S7-1517 with a fully populated local backplane and a typical 2 ms OB1, expect 2 to 3 OB1 cycles from first call to DONE = TRUE when the LADDR is the CPU itself (the read is local; no PROFINET round-trip is involved). For a remote PROFINET device, allow 5 to 20 OB1 cycles depending on the device update time and PROFINET load.

6.2 Steady-state impact: zero

Because the FB in Section 5 sets s_execute := FALSE after the first read, GET_IM_DATA is not called on subsequent OB1 cycles. The block therefore contributes essentially zero steady-state cycle time. This pattern is the recommended one whenever a value is read once and cached.

6.3 What you should not do

  • Do not call GET_IM_DATA with the same IM_TYPE in every OB1 cycle. It generates one record-read per cycle, which on a CPU with many I&M0 reads can saturate the diagnostic buffer. Cache the result and only re-read on cold restart.
  • Do not place the call inside a fast OB (e.g. OB30 at 500 µs) without measuring the worst-case OB time first. The internal record read uses the same priority queue as PROFINET IO updates; on a heavily loaded CPU it can cost up to ~1 ms per call, which breaks a 500 µs OB.
  • Do not gate the call on a hardware identifier that does not exist. A wrong LADDR returns STATUS = 0x80C3 ("Resource not found") after several cycles; the block then has to time out, which inflates the cycle time during the error window.

7. IO2MOD and the V2.5 / V2.6 Firmware Boundary

IO2MOD is a vendor- or project-specific block that resolves symbolic slot positions to hardware identifiers. Behavior on the S7-1517 changes at the V2.6 cutover because the underlying system function for slot-to-HW-ID resolution was extended in firmware V2.6 to support additional slot addressing modes used by newer I/O modules (specifically, the F-modules with enhanced diagnostics introduced in V2.6).

The recommended practice for projects that must support both firmware generations with a single compiled program is:

  1. Use the FB from Section 5 to detect the firmware at startup.
  2. Expose stUseIo2Mod as an HMI tag so commissioning engineers can see the decision the code made.
  3. Maintain two SCL call sites: a V2.6 path that calls IO2MOD, and a V2.5 path that uses a project constant (DB_Constants.hwIdUser[1..n]) populated by the engineer at commissioning time.
  4. Force a fresh firmware read on every cold restart (OB100) by re-initializing s_execute := TRUE in the OB100 instance-DB preload.

8. Version-Comparison Logic Patterns

When the application must accept several firmware cutover points (for example, V2.5, V2.6, V2.8, V2.9), the simple >= check in the FB above is not sufficient. A clean pattern is to expose a function that returns an enumerated firmware generation:

TYPE "E_FwGen"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   : ( FW_UNKNOWN  := 0,
       FW_V2_5     := 250,
       FW_V2_6     := 260,
       FW_V2_8     := 280,
       FW_V2_9     := 290 );
END_TYPE

FUNCTION "F_GetFwGen" : "E_FwGen"
   VAR_INPUT
      i_major : USINT;
      i_minor : USINT;
      i_ready : BOOL;
   END_VAR
   VAR_TEMP
      t_num   : INT;
   END_VAR
BEGIN
   IF NOT i_ready THEN
      "F_GetFwGen" := FW_UNKNOWN;
      RETURN;
   END_IF;
   t_num := INT_TO_WORD(SHL(USINT_TO_WORD(i_major), 8)) + i_minor;
   // Simplification: distinguish only the four supported generations.
   IF t_num = 0) THEN // (USINT)2 * 100 + 5
      "F_GetFwGen" := FW_V2_5;
   ELSIF (USINT)2 * 100 + 6 THEN
      "F_GetFwGen" := FW_V2_6;
   ELSIF (USINT)2 * 100 + 8 THEN
      "F_GetFwGen" := FW_V2_8;
   ELSIF (USINT)2 * 100 + 9 THEN
      "F_GetFwGen" := FW_V2_9;
   ELSE
      "F_GetFwGen" := FW_UNKNOWN;
   END_IF;
END_FUNCTION

For ranges (any V2.6 or later), a single o_isV2_6_OrUp boolean — as produced by the FB in Section 5 — is sufficient and avoids the helper enumeration.

9. Firmware Update Procedure (Reference)

Whenever a runtime detection reveals that the CPU is below the required firmware, the corrective action is a firmware update via TIA Portal's "Online & Diagnostics" view. The reference procedure for S7-1200 (and S7-1500) is documented in the TIA Portal help and replicated here for field reference.

  1. In the project tree, open the CPU that corresponds to the online connected device.
  2. Right-click the CPU and select "Online & Diagnostics".
  3. In the Online & Diagnostics view, expand the "Functions" folder and click "Firmware update".
  4. Browse to the firmware update file (a .upd file supplied by Siemens; do not use .bin or .fwc for S7-1200/1500 updates — those are S7-300/400 formats).
  5. Select the target CPU in the "Accessible nodes" table; tick "Run firmware update after download" if you want a one-step update.
  6. Click "Execute update". The CPU goes to STOP, erases, programs the new firmware, and performs a restart. Allow 30 s to 3 min depending on the firmware size and CPU type.
  7. After the restart, verify in "Online & Diagnostics > Diagnostics > General" that the new firmware version is reported, and re-run the runtime detection FB from Section 5 to confirm that the application now takes the V2.6+ code path.
Source URL. The TIA Portal online help entry "Updating firmware" is available in the TIA documentation cloud at docs.tia.siemens.cloud — Updating firmware.

10. Verification and Commissioning Checklist

# Check Expected result
1 Download the project to a V2.5 CPU. Watch the HMI tag stUseIo2Mod on first scan. stUseIo2Mod = FALSE; legacy path executes.
2 Open "Online > Go online > Accessible nodes" and read the CPU's "Module information > Firmware" field. Matches stFwMajor.stFwMinor shown on the HMI.
3 Update the CPU firmware to V2.6 via Online & Diagnostics, then perform a cold restart. OB100 re-initializes the FB; on first scan stUseIo2Mod = TRUE.
4 Trigger a STOP/RUN on the CPU. Cached values are reset by the cold restart of OB100; runtime read is re-issued; final stFwReady = TRUE.
5 Force a deliberate wrong LADDR (point at an I/O module that is not installed) and download. FB returns o_error = TRUE, o_status = 0x80C3, o_ready = FALSE. Application does not enter the IO2MOD path.
6 Use the TIA Portal trace recorder to capture OB1 execution time before and after the firmware read. Increase during the first 2–3 OB1 cycles is visible; thereafter OB1 returns to baseline within measurement noise.

11. Troubleshooting Matrix

Symptom Likely cause Diagnostic Resolution
o_error = TRUE, STATUS = 0x80C3 LADDR points to a module that is not present in the configured topology. Compare online topology with the device configuration; verify the LADDR via autocomplete. Use the correct system constant for the CPU (the "Local~" entry without an interface name).
o_ready = TRUE, but o_major = 0 and o_minor = 0. The IM0 buffer was read but the wrong hardware identifier was used (an I/O module, not the CPU). I&M0 of head modules may report 0/0 for firmware. Decode s_im0[10..29] as the order number; verify it is the CPU's MLFB. Change LADDR to the CPU system constant; recompile.
OB1 cycle time jumps by ~3 ms after the FB is added. The block is being called every cycle (the one-shot trigger is missing). Cross-reference with online watch table; verify s_execute is FALSE after first read. Implement the one-shot pattern from Section 5; reset only on OB100 cold restart.
Firmware value does not match TIA Portal's "Online > Module information" view. Endianness / offset misread; sometimes modules report firmware as 4 ASCII digits in I&M0, not as binary major/minor. Compare raw buffer bytes [32..33] with the textual value shown in the diagnostic view. For S7-1500 CPUs use binary decode (this article); for older ET 200S modules verify against the module's I&M specification.
STATUS = 0x80B1 ("Indication that the read job is still being processed") persists for many seconds. Record read job queue is congested by other PROFINET diagnostics traffic. Open "Online > Diagnostics > Diagnostic buffer" and inspect for RDB job entries. Stagger diagnostic reads in time; do not trigger them from a fast OB.
Detection works offline in the simulator but fails on the real CPU. PLCSIM does not implement I&M0 record reads for the CPU in all versions; the result is an empty buffer. Test only on real hardware for the final acceptance. Mark the FB as a "hardware-only" block in the project documentation.

12. Standards and Reference Documentation

  • PROFIBUS Guideline Identification & Maintenance Functions (PNO order no. 3.502, version 1.2) — defines the I&M0 record layout used by GET_IM_DATA. Cross-reference the byte offsets used in Section 5 against this guideline when porting to non-Siemens controllers.
  • Siemens TIA Portal Online Help — built-in documentation for the GET_IM_DATA instruction, available in every TIA Portal installation under "Instructions > Extended instructions > Diagnostics > Identification & Maintenance".
  • S7-1500 System Manual (Siemens entry ID 109751826) — module information view and firmware update procedure for the S7-1500 family, including the S7-1517 used in the field case.
  • TIA Portal documentation cloud — Updating firmware in Online and Diagnostics.

FAQ

Which IM_TYPE value of GET_IM_DATA returns the firmware version of the S7-1500 CPU?

IM_TYPE := 0 reads the I&M0 data record, which contains the firmware at byte offsets 32 (major) and 33 (minor). For example, bytes 02 06 at those offsets decode to firmware V2.6.

How do I pick the right hardware identifier (LADDR) for the CPU itself?

Use the system constant that resolves to the local station / CPU — in a default project it appears as the Local~ entry with no trailing interface name. The constants for the PROFINET, PROFIBUS, or DP interfaces will read the wrong device. Verify by decoding the order number at bytes 10..29 of the I&M0 buffer.

Does calling GET_IM_DATA every OB1 cycle increase the CPU cycle time?

Each invocation queues an asynchronous record-read job. Calling it once and caching the result (as in the FB in Section 5) keeps the steady-state cost at zero; only the first 2–3 OB1 cycles are affected (≈1 ms each on an S7-1517). Avoid placing the call inside a fast OB30/OB35 cycle.

What STATUS codes indicate common GET_IM_DATA errors?

0x80C3 = resource (LADDR) not found; 0x80B1 = job still being processed (transient); 0x80A1 = negative acknowledgment from the module. The full mapping is in the TIA Portal built-in help for the block.

Can I use the same approach to detect the firmware of a remote PROFINET device?

Yes — pass the device's hardware identifier (e.g. Headmodule of an ET 200SP station) as LADDR. Allow 5–20 OB1 cycles for the read to complete, and gate subsequent behavior on the decoded firmware bytes the same way as for the CPU.

Back to blog