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.
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 theSTATUSoutput) 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). |
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:
- Open the project's PLC tag table or the FC/FB where the call will be made.
- Click into the LADDR input of
GET_IM_DATA; the autocomplete shows all system constants of the assigned CPU. - Select the constant whose name is just the local station name, e.g.
PLC_1or whatever the station was renamed to. In a default project this appears as the "Local~" entry without a trailing interface name.
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_DATAwith the sameIM_TYPEin 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:
- Use the FB from Section 5 to detect the firmware at startup.
- Expose
stUseIo2Modas an HMI tag so commissioning engineers can see the decision the code made. - 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. - Force a fresh firmware read on every cold restart (OB100) by re-initializing
s_execute := TRUEin 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.
- In the project tree, open the CPU that corresponds to the online connected device.
- Right-click the CPU and select "Online & Diagnostics".
- In the Online & Diagnostics view, expand the "Functions" folder and click "Firmware update".
- Browse to the firmware update file (a
.updfile supplied by Siemens; do not use.binor.fwcfor S7-1200/1500 updates — those are S7-300/400 formats). - Select the target CPU in the "Accessible nodes" table; tick "Run firmware update after download" if you want a one-step update.
- 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.
- 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.
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_DATAinstruction, 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.