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) |
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 |
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;
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;
}
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
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
-
Always call
unload_toolin a finally / __finally block. If the application exits via an unhandled exception without unloading, subsequentload_toolcalls return0x0203until the PC is rebooted or thesin_serv.exeservice is restarted. -
Do not mix
komfort.dllandw95_s7.dllin the same process without coordination. Both bind the S7ONLINE device, and concurrent use leads to0x00D2memory faults. -
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. - 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.
- 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.
-
REAL byte order inside a 32-bit word: the helper uses
Move()afterSwap(), which assumes a little-endian host. On big-endian platforms the helper must be inverted.
16. Quick-Start Checklist
- Install STEP 7 V5.x or SIMATIC NET on the engineering PC; confirm the S7ONLINE access point exists.
- Connect the CP 5611 / CP 5613 / PC-MPI cable; verify termination (220 Ω at both ends of the bus).
- Run "Set PG/PC Interface" → select the CP / cable → test connection with "Accessible Nodes".
- In the application, populate
plc_adr_tablewith the PLC's MPI address (default 2), slot 2, rack 0. - Call
load_tool(1, "S7ONLINE", adr_table); check return = 0. - Read/write using
db_read/db_writeor the byte-area functions, applyingSwap()on every word. - Always call
unload_tool()before exit. - 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.