PRODAVE S7 Toolbox: MPI Communication Reference for S7-300/400

David Krause19 min read
Industrial NetworkingSiemensTechnical Reference
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. Overview of PRODAVE S7 and Siemens MPI

PRODAVE S7 is the Siemens toolbox that supplies a Dynamic Link Library (DLL) and static LIB interface for establishing data links between PCs / programming devices (PGs) and SIMATIC S7 PLCs over the proprietary Siemens Multi-Point Interface (MPI). The library exposes read and write access to PLC process data without requiring detailed knowledge of the underlying MPI frame handling, which lets developers concentrate on data processing rather than low-level bus mechanics.

Siemens MPI is a proprietary industrial networking protocol carried on an RS-485 physical layer at 187.5 kbit/s or 1.5 Mbit/s. It is used for programming, HMI, and peer-to-peer traffic between SIMATIC S7 CPUs, programming devices (PG 7xx), and operator panels sharing a common bus segment. PRODAVE wraps the MPI frame exchange and presents it as callable C / Pascal / Delphi / VB function calls.

The library supports MS-DOS, Windows 3.11, Windows 95, Windows 98, and Windows NT. The Windows NT/95 release ships as a 32-bit DLL compiled with Microsoft Visual C++ 5.0; the Windows 3.11 release is a 16-bit DLL compiled with Borland C++ 3.1. MS-DOS adaptors are delivered as MSC and Borland C large-model libraries. The PRODAVE functions divide into three groups:

  • Basic Functions — initialize/deinitialize the system (load_tool, unload_tool) and activate connections (new_ss).
  • S7-300/400 Data Transfer — process image, bit memory (flags), data blocks, timers, counters, and mixed access.
  • S7-200 Data Transfer — variable memory (V), special markers (SM), bit memory (M), process image, timers, and counters.

PRODAVE S7 is no longer the recommended path on modern systems; current Siemens-supported alternatives include the S7-communication / S7-Plus OPC UA server (e.g. SIMATIC S7-1500 / ET 200 CPUs) and the LibNoDave open-source library. The historical PRODAVE API is documented here because existing plant code, especially in VB 6, Delphi 7, and BC++ 3.1 applications, still depends on it.

2. Hardware and Software Prerequisites

Component Requirement
Supported PLCs SIMATIC S7-200, S7-300, S7-400, M7, C7
PC interfaces CP 5411, CP 5511, CP 5611, CP 5613, PC/MPI cable (USB-to-MPI adapter for legacy notebooks), COM-port PC/MPI cable
Operating system MS-DOS, Windows 3.11 (16-bit DLL), Windows 95 / 98 / NT (32-bit DLL)
STEP 7 install Required on the same PC; installs the supporting DLLs (w95_s7.dll / w95_s7m.dll) and the S7ONLINE access point
Compiler toolchains Microsoft Visual C++ 5.0 (32-bit), Borland C++ 3.1 (16-bit), Borland Delphi 32-bit, Visual Basic 6.0
Maximum active connections 4 under MS-DOS / Win 3.11, 16 under Windows 95 / NT

On modern Windows 10 / 11 installations, the legacy COM PC/MPI cable requires a virtual COM port driver and a virtualized 16-bit / 32-bit execution environment. CP 5611 / CP 5613 PCIe cards require the SIMATIC NET PC software stack (which is the modern successor to the STEP 7 bundled MPI drivers). For new development, prefer LibNoDave or the SIMATIC S7-PLCSIM / OPC UA path instead of PRODAVE.

3. Connection Parameter Reference

Every PRODAVE session begins with load_tool(). The connection is described by a device name (e.g. S7ONLINE) and a 5-byte address table. The address table layout is fixed across the C, Delphi, and Pascal adaptors:

Index Field Meaning Typical value (S7-300 MPI=2)
plc_adr_table[0] MPI address Node address on the MPI bus (0 = PG, 2 = default CPU) 2
plc_adr_table[1] Segment ID Reserved / segment routing field 0
plc_adr_table[2] Slot number CPU slot inside the rack 2
plc_adr_table[3] Rack number 0 = central rack, 1 = expansion rack 0
plc_adr_table[4] Reserved Must be 0 0

A second identifier used by some functions is the device string, passed as a null-terminated PChar. The default value S7ONLINE selects the MPI driver. Other drivers (e.g. TCPIP for S7 communication over Ethernet) were added in later PRODAVE versions, but the original 1.x / 2.x toolbox only supported MPI and the proprietary PPI / AS511 paths for S7-200.

4. Core API Functions

4.1 Basic Functions

C signature Delphi declaration Return Description
int load_tool(int nr, char* device, char* adr_table) function Load_tool(no:Byte; name:PChar; adr:PChar):Integer; stdcall; 0 on success, error code on failure Initialize the adaptor, verify driver loaded, build the parameterized address, activate the selected interface. nr = connection index (1..4 DOS/Win3.11, 1..16 Win95/NT).
int unload_tool(void) function Unload_tool:Integer; stdcall; 0 on success Deinitialize connections and the adaptor. Must be called before exiting the application.
int new_ss(int nr) (C only) 0 on success Activate a previously parameterized connection; equivalent to load_tool in single-connection apps.
int error_message(int Res, char* buf, int buflen) function Error_Message(Res:Integer):STRING; Length of text Translate a numeric error code into a human-readable string.

4.2 PLC Status

C signature buffer[0] value Meaning
int ag_zustand(void* buffer) 0 AG (CPU) is in RUN
1 AG is in STOP
1 (latched) AG is in RESTART (warm restart)
Note: In legacy PRODAVE documentation the buffer values 0/1 map to RUN/STOP; RESTART shares the buffer[0] = 1 state but is distinguished by transition. Sample the status twice with a 50-100 ms gap to differentiate.

5. Data Transfer Functions — S7-300 / S7-400

All access functions follow the same pattern: a starting index, an amount, and a buffer pointer. The buffer is interpreted in STEP 5 byte order (high byte first) unless the helper functions Swap() / ReadInt() are applied.

C function Area accessed Direction
a_field_read(int no, int anzahl, void* buffer) Outputs (process image, PA) Read
a_field_write(int no, int anzahl, void* buffer) Outputs (process image, PA) Write
e_field_read(int no, int anzahl, void* buffer) Inputs (process image, PE) Read
d_field_read(int dbno, int dwno, int* anzahl, void* buffer) Data block (DB) Read
d_field_write(int dbno, int dwno, int* anzahl, void* buffer) Data block (DB) Write
m_field_read(int no, int anzahl, void* buffer) Bit memory / flags (M / Merker) Read
m_field_write(int no, int anzahl, void* buffer) Bit memory / flags (M / Merker) Write
mb_bittest(int no, int bit) Single flag bit Test (returns 0 / 1)
mb_setbit(int no, int bit) Single flag bit Set to 1
mb_resetbit(int no, int bit) Single flag bit Reset to 0
t_field_read(int no, int anzahl, void* buffer) Timer words (T) Read
z_field_read(int no, int anzahl, void* buffer) Counter words (Z / C) Read
z_field_write(int no, int anzahl, void* buffer) Counter words (Z / C) Write
mix_read(int* anzahl, void* buffer) Mixed area (compound request) Read
mix_write(int* anzahl, void* buffer) Mixed area (compound request) Write

For d_field_read / d_field_write / db_read / db_write, dwno is the data-word offset (0-based). If anzahl exceeds the DB size the function silently trims it and returns the PRODAVE warning code 0x0303 (data length truncated). On DB-not-found the function returns a negative error code without modifying anzahl.

6. Data Transfer Functions — S7-200

S7-200 is supported through the as200_* family of functions. Memory map differences vs S7-300 are reflected in the symbol prefixes (V = variable memory, SM = special markers, M = bit memory).

C function Area accessed Direction
as200_a_field_read(no, anzahl, buffer) Outputs (S7-200 Q area) Read
as200_a_field_write(no, anzahl, buffer) Outputs (S7-200 Q area) Write
as200_e_field_read(no, anzahl, buffer) Inputs (S7-200 I area) Read
as200_vs_field_read(no, anzahl, buffer) Variable memory (V) Read
as200_vs_field_write(no, anzahl, buffer) Variable memory (V) Write
as200_m_field_read(no, anzahl, buffer) Bit memory (M) Read
as200_m_field_write(no, anzahl, buffer) Bit memory (M) Write
as200_sm_field_read(no, anzahl, buffer) Special markers (SMB / SMW) Read
as200_sm_field_write(no, anzahl, buffer) Special markers (SMB / SMW) Write
as200_mb_bittest(no, bit) Single flag bit Test
as200_mb_setbit(no, bit) Single flag bit Set
as200_mb_resetbit(no, bit) Single flag bit Reset
as200_t_field_read(no, anzahl, buffer) Timer words Read
as200_z_field_read(no, anzahl, buffer) Counter words Read
as200_z_field_write(no, anzahl, buffer) Counter words Write
as200_mix_read(anzahl, buffer) Mixed area Read
as200_mix_write(anzahl, buffer) Mixed area Write
Note: S7-200 communication in PRODAVE goes through the PPI / MPI hybrid port, not native MPI. To address an S7-200 from a PC, use the PPI-to-RS-232 adapter or set the S7-200 to MPI slave mode (default address 2, 187.5 kbit/s, 9 600 bit/s for PPI). The legacy PPI-only S7-21x CPUs (CPU 214, CPU 215, CPU 216) require a different access path.

7. Byte Order Handling — STEP 5 vs Intel

SIMATIC stores 16-bit values in STEP 5 notation: the high byte first, then the low byte. Intel (x86) processors store the low byte first. The functions below swap the two bytes for INT, DINT, and REAL data exchange:

Helper function Direction Purpose
function ReadInt(Word_:Word):Integer PLC → PC Swap and sign-extend a 16-bit word into an Integer.
procedure WriteInt(IntNr:Integer; var Word_:Word) PC → PLC Swap bytes before transmitting a 16-bit Integer.
function ReadDInt(Low_Word:Word; High_Word:Word):Longint PLC → PC Compose a 32-bit Longint from two PLC words, applying byte swap.
procedure WriteDInt(LongNr:Longint; var Low_Word, High_Word:Word) PC → PLC Decompose and byte-swap a Longint into two PLC words.
function ReadReal(Low_Word:Word; High_Word:Word):Single PLC → PC Compose a 32-bit IEEE-754 Single from two PLC words.
procedure WriteReal(FloatNr:Single; var Low_Word, High_Word:Word) PC → PLC Decompose and byte-swap a Single into two PLC words.

The implementation pattern (Delphi 32-bit, Pascal) is:

function ReadInt(Word_: Word): Integer;
begin
  if Swap(Word_) < 32767 then
    Result := Swap(Word_)
  else
    Result := Swap(Word_) - 65536;  // sign-correct for INT range -32768..32767
end;

procedure WriteInt(IntNr: Integer; var Word_: Word);
begin
  Word_ := Swap(IntNr);
end;
Caution: REAL values are IEEE-754 only on S7-300/400 with firmware >= certain versions and on all S7-1500 / S7-1200 CPUs. Older S7-300 CPUs (e.g. CPU 312 IFM / 314 IFM) store REAL in an alternative S5-format floating-point representation that cannot be exchanged with these helpers without conversion.

8. Error Code Reference

Every PRODAVE function returns 0 on success and a hexadecimal error code on failure. The Error_Message() helper translates the codes below:

Hex code Symbolic Plain-text meaning Likely root cause
0x00CA RESOURCE No resources available Driver exhausted handles / memory pool
0x00CB CFG Configuration error Bad plc_adr_table, invalid slot/rack
0x00CD ILLEGAL_CALL Illegal call Function used out of sequence (e.g. read before load_tool)
0x00CE NO_MODULE Module not found PLC not on bus, wrong MPI address
0x00CF NO_DRIVER Driver not loaded S7ONLINE not installed, STEP 7 missing
0x00D0 HW_FAULT Hardware fault CP 5611 / cable defective, bus termination wrong
0x00D1 SW_FAULT Software fault Driver internal inconsistency; reinstall STEP 7
0x00D2 MEM_FAULT Memory fault Insufficient process memory in 16-bit host
0x00D7 NO_MSG No message Internal queue empty
0x00D8 STORAGE_FAULT Storage fault DB does not exist or is write-protected
0x00DB TIMEOUT Internal timeout Bus response > 3 s
0x00E1 TOO_MANY Too many channels open Exceeded 4 / 16 active connections
0x00E2 INT_FAULT Internal fault Generic internal error; reboot PC
0x00E7 HW_FAULT2 Hardware fault CP self-test failed
0x00E9 SIN_SERV sin_serv.exe not started PRODAVE NT service not running
0x00EA PROTECTED Protected PLC in operation mode that blocks writes
0x00F0 NO_SCP_DB SCP DB file does not exist Missing S7 configuration database
0x00F1 NO_GLOBAL No global DOS storage 16-bit DOS allocation failed
0x00F2 TX_ERR Error during transmission Bus collision, no termination
0x00F3 RX_ERR Error during reception Checksum / framing error
0x00F4 NO_DEV Device does not exist Wrong device name in load_tool
0x00F5 BAD_SUB Incorrect sub-system Wrong protocol sub-layer
0x00F6 UNK_CODE Unknown code Driver version mismatch with STEP 7
0x00F7 / 0x00F8 BUF_SMALL Buffer too small Caller buffer < anzahl
0x00F9 BAD_PROTO Incorrect protocol PLC and PC disagree on protocol
0x00FB RX_ERR2 Reception error Sequence error in MPI handshake
0x00FC LIC_ERR Licence error PRODAVE licence not activated
0x0101 NO_CONN Connection not established / parameterised load_tool never succeeded
0x010A NAK_TO Negative ACK / timeout PLC did not respond within 3 s
0x010C NO_DATA Data does not exist or disabled DB unlinked, area not configured
0x012A NO_SYS_STORE System storage no longer available Driver memory exhausted
0x012E BAD_PARAM Incorrect parameter Range out of bounds
0x0132 NO_DPRAM No memory in DPRAM CP dual-port RAM exhausted
0x0201 BAD_IF Incorrect interface specified device string unknown
0x0202 MAX_IF Maximum amount of interfaces exceeded > 4/16 connections
0x0203 ALREADY_INIT PRODAVE already initialised load_tool called twice
0x0204 BAD_PARAM2 Wrong parameter Address table invalid

9. Delphi 32-bit Integration Example

The Delphi wrapper imports w95_s7.dll via the stdcall calling convention and uses Swap() for byte-order conversion. The unit shown below reproduces the canonical S7_DLL.PAS interface used in the field:

unit S7_DLL;
interface
uses SysUtils, Dialogs;

function Connect(no:Byte; name:PChar; adr:PChar):Integer; stdcall;
  external 'w95_s7.dll' name 'load_tool';

function DB_read(dbno:Integer; dwno:Integer; var amount:Integer;
  var buffer):Integer; stdcall;
  external 'w95_s7.dll' name 'db_read';

function DB_Write(dbno:Integer; dwno:Integer; var amount:Integer;
  var buffer):Integer; stdcall;
  external 'w95_s7.dll' name 'db_write';

function PLC_Status(var buffer):Integer; stdcall;
  external 'w95_s7.dll' name 'ag_zustand';

function Error_Message(Res:Integer):STRING;
function Disconnect:Integer; stdcall;
  external 'w95_s7.dll' name 'unload_tool';

function ReadInt(Word_: Word):Integer;
procedure WriteInt(IntNr:Integer; var Word_: Word);
function ReadDInt(Low_Word: Word; High_Word: Word):Longint;
procedure WriteDInt(LongNr:Longint; var Low_Word: Word;
  var High_Word: Word);
function ReadReal(Low_Word: Word; High_Word: Word):Single;
procedure WriteReal(FloatNr:Single; var Low_Word: Word;
  var High_Word: Word);

implementation

function Error_Message(Res:Integer):STRING;
begin
  if Res <> 0 then
  begin
    Result := 'ERROR: ' + Format('%x',[Res]);
    case Res of
      $00CA: Result := Result + ' No resources available';
      $00CB: Result := Result + ' Configuration error';
      $00CD: Result := Result + ' Illegal call';
      $00CE: Result := Result + ' Module not found';
      $00CF: Result := Result + ' Driver not loaded';
      $00D0: Result := Result + ' Hardware fault';
      $00D1: Result := Result + ' Software fault';
      $00D2: Result := Result + ' Memory fault';
      $00D7: Result := Result + ' No message';
      $00D8: Result := Result + ' Storage fault';
      $00DB: Result := Result + ' Internal timeout';
      $00E1: Result := Result + ' Too many channels open';
      $00E2: Result := Result + ' Internal fault';
      $00E7: Result := Result + ' Hardware fault';
      $00E9: Result := Result + ' Sin_serv.exe not started';
      $00EA: Result := Result + ' Protected';
      $00F0: Result := Result + ' Scp db file does not exist';
      $00F1: Result := Result + ' No global dos storage available';
      $00F2: Result := Result + ' Error during transmission';
      $00F3: Result := Result + ' Error during reception';
      $00F4: Result := Result + ' Device does not exist';
      $00F5: Result := Result + ' Incorrect sub system';
      $00F6: Result := Result + ' Unknown code';
      $00F7: Result := Result + ' Buffer too small';
      $00F8: Result := Result + ' Buffer too small';
      $00F9: Result := Result + ' Incorrect protocol';
      $00FB: Result := Result + ' Reception error';
      $00FC: Result := Result + ' Licence error';
      $0101: Result := Result + ' Connection not established / parameterised';
      $010A: Result := Result + ' Negative acknowledgement received / timeout error';
      $010C: Result := Result + ' Data does not exist or disabled';
      $012A: Result := Result + ' System storage no longer available';
      $012E: Result := Result + ' Incorrect parameter';
      $0132: Result := Result + ' No memory in DPRAM';
      $0201: Result := Result + ' Incorrect interface specified';
      $0202: Result := Result + ' Maximum amount of interfaces exceeded';
      $0203: Result := Result + ' PRODAVE already initialised';
      $0204: Result := Result + ' Wrong parameter';
    end;
    ShowMessage(Result);
  end;
end;

function ReadInt(Word_: Word):Integer;
begin
  if Swap(Word_) < 32767 then
    Result := Swap(Word_)
  else
    Result := Swap(Word_) - 65536;
end;

procedure WriteInt(IntNr:Integer; var Word_: Word);
begin
  Word_ := Swap(IntNr);
end;

function ReadDInt(Low_Word: Word; High_Word: Word):Longint;
var Rec: array[0..1] of Word;
begin
  try
    Rec[0] := Swap(High_Word);
    Rec[1] := Swap(Low_Word);
    Move(Rec, Result, SizeOf(Result));
  except
    Result := 0;
  end;
end;

procedure WriteDInt(LongNr:Longint; var Low_Word: Word; var High_Word: Word);
var Rec: array[0..1] of Word;
begin
  try
    Move(LongNr, Rec, SizeOf(LongNr));
    Low_Word := Swap(Rec[1]);
    High_Word := Swap(Rec[0]);
  except
    Low_Word := 0;
    High_Word := 0;
  end;
end;

function ReadReal(Low_Word: Word; High_Word: Word):Single;
var Rec: array[0..1] of Word;
begin
  try
    Rec[0] := Swap(High_Word);
    Rec[1] := Swap(Low_Word);
    Move(Rec, Result, SizeOf(Result));
  except
    Result := 0;
  end;
end;

procedure WriteReal(FloatNr:Single; var Low_Word: Word; var High_Word: Word);
var Rec: array[0..1] of Word;
begin
  try
    Move(FloatNr, Rec, SizeOf(FloatNr));
    Low_Word := Swap(Rec[1]);
    High_Word := Swap(Rec[0]);
  except
    Low_Word := 0;
    High_Word := 0;
  end;
end;
end.

10. C Adapter Reference Call-Sequence

A minimal C program that opens a connection, reads 32 words from DB 10, prints the result, and closes:

#include <stdio.h>
extern int load_tool(int, char*, char*);
extern int unload_tool(void);
extern int db_read(int, int, int*, void*);
extern int ag_zustand(void*);

int main(void)
{
  unsigned char adr[5] = { 2, 0, 2, 0, 0 };
  unsigned short buffer[64];
  int amount = 32;
  int rc;
  unsigned char plc_state;

  rc = load_tool(1, "S7ONLINE", (char*)adr);
  if (rc != 0) { printf("load_tool error 0x%04X\n", rc); return 1; }

  rc = ag_zustand(&plc_state);
  if (rc != 0) { printf("ag_zustand error 0x%04X\n", rc); return 1; }
  printf("PLC state = %d\n", plc_state);

  rc = db_read(10, 0, &amount, buffer);
  if (rc != 0 && rc != 0x0303) {
    printf("db_read error 0x%04X\n", rc);
    return 1;
  }

  for (int i = 0; i < amount; i++)
    printf("DB10.DBW%d = 0x%04X (%d)\n", i*2, buffer[i], buffer[i]);

  unload_tool();
  return 0;
}
Linker note: Link against w95_s7.lib (Win95/NT) or w31_s7.lib (Win 3.11) or the MS-DOS large-model LIB. Ship w95_s7.dll in the application directory or under %SystemRoot%\System32. On modern x64 Windows, the 32-bit DLL must live next to a 32-bit EXE (WOW64); a 64-bit application cannot load it.

11. Visual Basic 6 / VB.NET Migration Notes

When STEP 7 is installed, two relevant DLLs are registered:

  • komfort.dll — high-level wrapper exposing read/write of DB, M, I, Q areas with property-style access; recommended for VB 6.
  • w95_s7m.dll — additional MPI-direct functions for advanced uses (e.g. db_read, db_write); same calling convention as the C adaptor.

For VB 6: declare the functions with Declare Function ... Lib "komfort.dll" (Alias "db_read") and call them through the API. For VB.NET: PRODAVE is not directly callable across the managed/native boundary without a P/Invoke wrapper; instead, install an OPC server (e.g. the SIMATIC NET OPC server, the Softing S7-OPC server, or the open-source Sharp7 / libnodave bridge) and consume OPC DA 2.0 / 3.0 from .NET. The legacy PRODAVE path is preserved only for VB 6 maintenance scenarios.

12. Session Lifecycle — State Diagram

UNINITIALIZED load_tool OK CONNECTED (1..16) db_read / db_write a/e/m_field_* unload_tool DEINITIALIZED load_tool() rc=0 new_ss() read/write function call rc=0 app exit load_tool rc ≠ 0 → error code

13. Troubleshooting Matrix

Symptom Return code Likely cause Remediation
load_tool returns immediately with no bus traffic 0x00CF S7ONLINE driver not installed Install / repair STEP 7 or SIMATIC NET; verify "Set PG/PC Interface" points to S7ONLINE (MPI) or the correct CP
load_tool returns 0 but db_read returns 0x00CE 0x00CE Wrong MPI address Confirm PLC MPI address (default 2); set the same in plc_adr_table[0]
db_read truncates and returns 0x0303 0x0303 amount exceeds DB size Reduce anzahl; check DB length in STEP 7
Values look byte-swapped n/a STEP 5 vs Intel byte order Apply Swap() / ReadInt() / WriteInt() helpers
Intermittent 0x00DB / 0x010A after working hours 0x00DB, 0x010A EMI / bus termination missing Add 220 Ω termination at both ends; check cable shielding, baud rate 187.5 kbit/s
ag_zustand always returns 0 (RUN) even with PLC in STOP n/a Wrong slot in plc_adr_table[2] Use STEP 7 "Accessible Nodes" to find the actual CPU slot
z_field_write has no effect 0x00EA PLC key switch in RUN-PROTECTED Switch to RUN or RUN-P; counters are read-only when protected
Real values come back as garbage n/a S5-format floating point on old CPU Verify CPU supports IEEE-754; otherwise convert manually
Multiple connections fail with 0x00E1 0x00E1 Connection limit exceeded Stay within 4 (DOS/Win3.11) or 16 (Win95/NT) active connections
VB.NET runtime cannot find entry point n/a 64-bit process cannot load 32-bit DLL Build application as x86, or replace with OPC UA / Sharp7

14. Migration to Modern Siemens Paths

The recommended replacement for PRODAVE depends on the target system:

Modern path Use when Notes
SIMATIC NET OPC UA server on S7-1500 / ET 200SP New installation Native UA, no Windows dependency, encrypted
Sharp7 / libnodave (open-source) .NET / cross-platform modernization Drop-in for many PRODAVE functions, MIT-style license
SIMATIC S7-PLCSIM + Softing / Siemens OPC Test cells No real PLC required, supports DB/M/PA/PE access
PROFINET via S7-1200/1500 built-in OPC UA Brownfield with PROFINET Replaces MPI bus entirely

15. Notes on Field-Proven Caveats

  1. Always call unload_tool in a finally / __finally block. If the application exits via an unhandled exception without unloading, subsequent load_tool calls return 0x0203 until the PC is rebooted or the sin_serv.exe service is restarted.
  2. Do not mix komfort.dll and w95_s7.dll in the same process without coordination. Both bind the S7ONLINE device, and concurrent use leads to 0x00D2 memory faults.
  3. Bus scan order matters: with multiple CPUs, address them by their actual MPI addresses (set in STEP 7 hardware configuration). new_ss() re-activates the connection but does not change routing.
  4. For S7-200, always set the PPI/MPI mode switch on the CPU before scanning. PRODAVE does not auto-detect PPI vs MPI; it always speaks MPI.
  5. STEP 5 byte order on multi-word values: a 32-bit DINT is stored as word 0 = high word, word 1 = low word. Skipping the high/low swap yields values that are off by a factor of 65 536.
  6. REAL byte order inside a 32-bit word: the helper uses Move() after Swap(), which assumes a little-endian host. On big-endian platforms the helper must be inverted.

16. Quick-Start Checklist

  1. Install STEP 7 V5.x or SIMATIC NET on the engineering PC; confirm the S7ONLINE access point exists.
  2. Connect the CP 5611 / CP 5613 / PC-MPI cable; verify termination (220 Ω at both ends of the bus).
  3. Run "Set PG/PC Interface" → select the CP / cable → test connection with "Accessible Nodes".
  4. In the application, populate plc_adr_table with the PLC's MPI address (default 2), slot 2, rack 0.
  5. Call load_tool(1, "S7ONLINE", adr_table); check return = 0.
  6. Read/write using db_read / db_write or the byte-area functions, applying Swap() on every word.
  7. Always call unload_tool() before exit.
  8. Translate any non-zero return with Error_Message(); map to the table above.

What is the difference between Siemens MPI and the parallel-computing MPI?

Siemens MPI ("Multi-Point Interface") is a proprietary RS-485 industrial protocol running at 187.5 kbit/s or 1.5 Mbit/s on a bus shared between SIMATIC S7 CPUs, programming devices, and HMIs. The parallel-computing MPI ("Message Passing Interface") is an unrelated standard for inter-process communication on HPC clusters. They share only the acronym. PRODAVE S7 implements the Siemens variant.

Which PRODAVE return code indicates the PLC did not respond?

Return code 0x010A ("Negative acknowledgement received / timeout error") is the canonical timeout. The driver waits 3 s for an MPI ACK; if the CPU is in STOP with a cleared bus interface, or the cable is broken, the function returns 0x010A. A closely related code, 0x00DB, is the internal-driver-level timeout.

Why do my 16-bit integers come back reversed?

SIMATIC stores words in STEP 5 byte order (high byte first). Intel x86 stores them low-byte-first. Apply Swap() on every word before interpreting, or use the bundled helpers ReadInt, ReadDInt, and ReadReal. Forgetting the swap shifts the value by 8 bits (× 256) and corrupts negative numbers.

Can PRODAVE reach a S7-300 over Ethernet?

Yes, but only with the later PRODAVE versions (V6.x and newer) that expose the TCP/IP device string (e.g. "TCPIP"). The classic V1.x/V2.x toolbox described here is MPI-only. For modern Ethernet connectivity prefer the SIMATIC NET OPC UA server or the Sharp7 / libnodave libraries, which work without the legacy PC/MPI hardware.

How do I replace PRODAVE in a VB.NET application?

PRODAVE is a 32-bit unmanaged DLL; a 64-bit VB.NET process cannot load it directly. Replace it with an OPC DA / OPC UA server side and a managed .NET OPC client, or use the open-source Sharp7 library, which exposes equivalent DBRead, DBWrite, Read, and Write methods over TCP/IP and works on any CPU target.

Back to blog