Overview: USB-MPI Communication with S7-300
The classic route into a SIMATIC S7-300 was the RS-232 PC Adapter (MPI) running through a serial COM port. When Siemens transitioned to USB-only workstations, the parallel bridge became the 6ES7 972-0CB20-0XA0 SIMATIC PC Adapter USB, a self-powered cable that exposes an MPI/PROFIBUS DP slave on the S7 side and a USB 1.1 device on the PC side. This same adapter also ships under the later designation 6ES7 972-0CB35-0XA0 with updated RS-232/TTY firmware. Both units are electrically identical and share a common driver stack, but only one software toolbox - PRODAVE MPI/DP - exposes the synchronous MPI read/write primitives that C# applications need when SIMATIC NET is not licensed or is intentionally bypassed.
This reference covers the full path: pin and protocol layer, the hardware versions, the PRODAVE MPI/DP API surface, a working C# wrapper, the configuration of the Set PG/PC Interface tool, and a troubleshooting matrix for the field problems you will hit (baud-rate lock, MPI address clash, PLC STOP on connect, missing DLLs, .NET platform target mismatch).
Hardware: 6ES7 972-0CB20-0XA0 PC Adapter USB
The PC Adapter USB is a single-piece cable assembly, 5 m long, terminating in a 9-pin sub-D male that connects to the MPI/DP port of an S7-300 CPU (or S7-200 PPI, S7-400 MPI, C7, M7). The cable contains an RS-485 transceiver, an isolated DC/DC converter, and a microcontroller that bridges between the PC USB port and the MPI/DP bus.
Order numbers and revisions
| MLFB | Revision | Notes |
|---|---|---|
| 6ES7 972-0CB20-0XA0 | ES 02 / FW 1.0.8 | Original release. RS-232 mode only. MPI up to 1.5 Mbps. |
| 6ES7 972-0CB35-0XA0 | ES 05 / FW 2.0.x | Successor. Adds TTY/20 mA mode and PROFIBUS DP up to 12 Mbps. |
| 6GK1 571-0BA00-0AA0 | CP 5711 | Replacement form factor (ExpressCard/PCIe). Same protocol stack. |
Electrical and protocol specifications
| Parameter | Value |
|---|---|
| PC interface | USB 1.1 Full Speed (12 Mbps), Type-A |
| PLC interface | RS-485 isolated, MPI / PROFIBUS DP slave |
| Connector | 9-pin sub-D, male, pinout per EN 50170 |
| MPI baud rate | 187.5 kbps (mandatory for S7-300/400 MPI) |
| PROFIBUS DP max baud rate | 1.5 Mbps (0CB20), 12 Mbps (0CB35) |
| Bus termination | Internal, switchable via DIP switch on housing |
| Power consumption | 200 mA max from USB, no external PSU required |
| Galvanic isolation | 500 V between USB and MPI bus |
| Operating temperature | 0 °C to 60 °C |
| Driver stack | Siemens USB-MPI-Driver, installs virtual COM port (VCP) + S7ONLINE access point |
LED and DIP switch behavior
Two status LEDs sit under the DB-9 shell: green indicates USB enumeration and PC communication, yellow indicates active token on the MPI bus. The 4-position DIP switch on the housing controls:
- SW1: Term - insert 220 Ω termination (only when the cable is the last segment).
- SW2: Mode - RS-232/TTY select on 0CB35, ignored on 0CB20.
- SW3: Baud - forces 19.2 kbps (PPI legacy); leave OFF for MPI 187.5 kbps.
- SW4: Test - reserved, must be OFF.
Software Stack: Why PRODAVE MPI/DP
The PC Adapter USB presents itself to Windows as two devices: a virtual COM port (used only for legacy S7-200 PPI passthrough) and a Siemens proprietary S7ONLINE access point. SIMATIC NET installs the S7ONLINE access point and can route OPC, S7 functions, and TCP/IP over it - but only when a SIMATIC NET license (Softnet-S7 Lean or higher) is present. Without a license, SIMATIC NET will not enumerate the cable.
PRODAVE MPI/DP is a separate toolbox, sold under MLFB 6ES7 964-2AA00-0AB0 (V6.2) or available in older V5.x variants. It installs its own MPI driver (typically named SIMATIC_MPI.DLL and W95S7API.DLL under %ProgramFiles%\Siemens\PRODAVE\MPI\) and exposes ~50 C-style functions through a single dynamic library: PRODAVE_MPI.DLL. C# callers use DllImport (P/Invoke) to bind to these functions; no separate COM interop is needed.
PRODAVE MPI/DP installed components
| File | Location | Purpose |
|---|---|---|
| PRODAVE_MPI.DLL | System32 (or app bin) | Core API surface |
| W95S7API.DLL | PRODAVE install folder | Internal driver shim to S7API |
| S7API.DLL | Windows\SysWOW64 | Kernel-level MPI frame handler |
| S7ONLINE access point | Registry: HKLM\SOFTWARE\Siemens\SINEC | Logical device the API binds to |
| Set PG-PC.exe | PRODAVE\Tools | Selects MPI bus and bus profile |
Set PG/PC Interface configuration
Before any C# code can connect, the S7ONLINE access point must be pointed at the PC Adapter. Open Set PG-PC Interface, pick PC Adapter (MPI) -> S7ONLINE, then click Properties:
- MPI address of PC: 0 (default, address 0 is reserved for the master/PG).
- Highest MPI address: 15 (or 31, depending on the bus scope).
- Transmission rate: 187.5 kbps.
- Timeout: 30 s.
On the S7-300 side, the CPU must have a free MPI slot (CPU 312-318 typically allow addresses 2..15 in addition to their default). Use STEP 7 -> PLC -> Properties -> MPI/DP Interface to confirm the address and baud.
PRODAVE MPI/DP API Reference
PRODAVE MPI/DP exposes three logical layers: connection, data-block, and bit-level. Functions return a 16-bit signed status code where 0 means OK and any other value maps to an MPI error class.
Connection management
| Function | Prototype | Returns |
|---|---|---|
| Load | short Load(void) |
0 on success, -1 if DLL not loadable |
| Unload | short Unload(void) |
0 on success |
| SetActiveConnection | short SetActiveConnection(short id) |
Connection handle |
| ActivateConnection | short ActivateConnection(int con) |
0 on connect |
| DeactivateConnection | short DeactivateConnection(int con) |
0 on disconnect |
| GetConnectionState | short GetConnectionState(int con) |
0 = idle, 1 = active |
Data block read/write (byte / word / dword)
| Function | Operates on | Length |
|---|---|---|
| db_read | DB (any number) | 1..2048 bytes |
| db_write | DB | 1..2048 bytes |
| mb_read | Merker (M), Input (PE), Output (PA) | 1..2048 bytes |
| mb_write | Merker, Output | 1..2048 bytes |
| z_read / z_write | Counter (C) | 2 bytes |
| t_read / t_write | Timer (T) | 2 bytes |
Bit-level access
Bit access functions (db_bit_read, db_bit_write, mb_bit_read, mb_bit_write) take a byte offset and a bit number 0..7. These calls are slow (each one is a full MPI transaction); prefer db_read of the whole word followed by in-memory masking when polling fast bits.
Status codes
| Code | Meaning |
|---|---|
| 0 | OK |
| 0x0001 | Connection not active |
| 0x0002 | Invalid connection handle |
| 0x0003 | PLC timeout (bus dead) |
| 0x0005 | Address area out of range |
| 0x0010 | PLC object does not exist (DB not loaded, etc.) |
| 0x0030 | Wrong DB length in CPU |
| 0x0040 | PLC is in STOP / protection |
| 0x0080 | Parity / framing - check bus termination |
| 0xFFFF | Driver not loaded - PRODAVE install broken |
C# Wrapper: PRODAVE_MPI.DLL via P/Invoke
PRODAVE MPI/DP is a C ABI library, so the entire surface maps cleanly onto [DllImport]. The following wrapper compiles against .NET Framework 4.8 or .NET 6 (with Windows TFM) and assumes the S7ONLINE access point is already configured to point at the PC Adapter USB.
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace S7UsbMpi
{
public sealed class ProdaveMpi : IDisposable
{
// -- connection management ----------------------------------------
[DllImport("prodave_mpi.dll", CharSet = CharSet.Auto)]
private static extern short Load();
[DllImport("prodave_mpi.dll")]
private static extern short Unload();
[DllImport("prodave_mpi.dll")]
private static extern short SetActiveConnection(short id);
[DllImport("prodave_mpi.dll")]
private static extern short ActivateConnection(int con);
[DllImport("prodave_mpi.dll")]
private static extern short DeactivateConnection(int con);
// -- data block I/O ----------------------------------------------
[DllImport("prodave_mpi.dll", EntryPoint = "db_read")]
private static extern short db_read(
int con, short dbNo, short startByte,
short length, byte[] buffer);
[DllImport("prodave_mpi.dll", EntryPoint = "db_write")]
private static extern short db_write(
int con, short dbNo, short startByte,
short length, byte[] buffer);
// -- merker / IO area I/O -----------------------------------------
[DllImport("prodave_mpi.dll", EntryPoint = "mb_read")]
private static extern short mb_read(
int con, short area, short startByte,
short length, byte[] buffer);
[DllImport("prodave_mpi.dll", EntryPoint = "mb_write")]
private static extern short mb_write(
int con, short area, short startByte,
short length, byte[] buffer);
// -- PLC state ----------------------------------------------------
[DllImport("prodave_mpi.dll", EntryPoint = "plc_status")]
private static extern short plc_status(
int con, ref short runStop, ref short fault);
// Area constants for mb_read / mb_write
public const short AREA_PE = 0x81; // process inputs (E / PE)
public const short AREA_PA = 0x82; // process outputs (A / PA)
public const short AREA_MK = 0x83; // merkers (M)
private int _conn;
private bool _loaded;
public ProdaveMpi(short mpiAddress = 2, int timeoutMs = 30000)
{
short s = Load();
if (s != 0) throw new InvalidOperationException(
$"PRODAVE Load failed: 0x{s:X4}. Install PRODAVE MPI/DP and verify S7ONLINE access point.");
_loaded = true;
// Create connection 1 -> target MPI address
short set = SetActiveConnection(1);
short act = ActivateConnection(mpiAddress);
if (set != 0 || act != 0)
throw new InvalidOperationException(
$"Cannot activate MPI connection. set=0x{set:X4} act=0x{act:X4}");
_conn = mpiAddress;
}
public byte[] ReadDb(short dbNumber, int startByte, int length)
{
var buf = new byte[length];
short s = db_read(_conn, dbNumber, (short)startByte, (short)length, buf);
if (s != 0) throw new InvalidOperationException(
$"db_read failed: 0x{s:X4} DB{dbNumber}.{startByte} len={length}");
return buf;
}
public void WriteDb(short dbNumber, int startByte, byte[] data)
{
short s = db_write(_conn, dbNumber, (short)startByte,
(short)data.Length, data);
if (s != 0) throw new InvalidOperationException(
$"db_write failed: 0x{s:X4}");
}
public byte[] ReadMerker(int startByte, int length)
{
var buf = new byte[length];
short s = mb_read(_conn, AREA_MK, (short)startByte,
(short)length, buf);
if (s != 0) throw new InvalidOperationException(
$"mb_read(M) failed: 0x{s:X4}");
return buf;
}
public PlcState QueryState()
{
short run = 0, fault = 0;
short s = plc_status(_conn, ref run, ref fault);
if (s != 0) throw new InvalidOperationException(
$"plc_status failed: 0x{s:X4}");
return new PlcState { Running = run != 0, Faulted = fault != 0 };
}
public void Dispose()
{
if (_conn != 0)
{
DeactivateConnection(_conn);
_conn = 0;
}
if (_loaded)
{
Unload();
_loaded = false;
}
}
}
public struct PlcState
{
public bool Running;
public bool Faulted;
}
}
Usage example
using (var mpi = new ProdaveMpi(mpiAddress: 2))
{
var state = mpi.QueryState();
Console.WriteLine($"PLC running={state.Running} faulted={state.Faulted}");
// Read first 20 bytes of DB10
byte[] db10 = mpi.ReadDb(dbNumber: 10, startByte: 0, length: 20);
// Write a counter preset into DB100.DBD0 (real)
byte[] payload = BitConverter.GetBytes(42.0f);
mpi.WriteDb(dbNumber: 100, startByte: 0, data: payload);
}
<PlatformTarget>x86</PlatformTarget> on .NET 5+. A 64-bit host process will fail Load() with 0xFFFF.Alternatives to PRODAVE MPI/DP
PRODAVE is paid commercial software and is being phased out in favor of TIA Portal and the libnodave / Snap7 open-source ecosystem. The PC Adapter USB works with both because they call into the same Windows driver installed by the PRODAVE / SIMATIC NET setup.
libnodave (open source, C)
libnodave talks MPI/PROFIBUS over the S7ONLINE access point or directly via the CP card. Use the IBHNet or libnodave-java binding from C# via a thin wrapper. Set dave.SetS7OnlinePoint('S7ONLINE') and dave.SetInterface(IFType.MPI, 0, 187.5). libnodave is GPL but can be statically linked into commercial code with a written exception from the author Thomas Hergenhahn.
Snap7 (open source, C#/.NET)
Snap7 targets Ethernet (S7-1200/1500 + CP343) and does not natively drive the PC Adapter USB. For S7-300 over USB-MPI it is therefore not a substitute for PRODAVE. If your S7-300 has a CP343-1 Lean installed, adding the CP and moving to Snap7 is the long-term-clean solution.
S7.NET (open source, .NET)
Same caveat as Snap7: works over Ethernet/IP only. Useful as a higher-level facade if you also need symbolic tag access, but for raw DB/M/E/A via USB-MPI you must drop back to PRODAVE or libnodave.
Step-by-Step Setup Procedure
- Install STEP 7 V5.5 (or STEP 7 V5.6) on the target PC. This installs the S7ONLINE access point skeleton.
- Plug in the 6ES7 972-0CB20-0XA0. Windows should auto-detect it and install the generic USB CDC device; if not, run the manual driver located on the PRODAVE CD under
Drivers\PC_Adapter_USB\or use the Siemens AUTOMATION_INSTALLER package. - Verify the cable shows up in Device Manager under Siemens AG - SIMATIC PC Adapter USB. The COM-port entry (e.g. COM5) is only used by S7-200 PPI tools; C# code via PRODAVE does not need it.
- Install PRODAVE MPI/DP V6.2 (MLFB 6ES7 964-2AA00-0AB0). Accept the default install folder.
- Open Set PG/PC Interface (start menu -> SIMATIC -> STEP 7 -> Set PG-PC Interface). Set PC Adapter (MPI) -> S7ONLINE. Click Properties: address 0, max 15, 187.5 kbps.
- Connect the DB-9 end to the S7-300 MPI port. Ensure termination: if this is the last node on the segment, set DIP SW1 = ON; otherwise OFF.
- Power-cycle the S7-300 CPU. The yellow LED on the adapter should blink once as the CPU grants the token.
- Build the C# wrapper project, target x86, set the working directory or PATH so
prodave_mpi.dllis resolvable at runtime. - Run a sanity-check program that calls
QueryState(). A successful response means the full stack (USB driver -> PRODAVE -> S7ONLINE -> MPI cable -> CPU) is wired up.
Verification Checklist
Before signing off, verify all of the following. Each item is a single point of failure that the wrapper cannot distinguish from a real PLC error.
| # | Check | Expected | Tool |
|---|---|---|---|
| 1 | Device Manager - cable present | Siemens SIMATIC PC Adapter USB, no warning triangle | Device Manager |
| 2 | S7ONLINE access point | PC Adapter (MPI) -> S7ONLINE, 187.5 kbps | Set PG/PC Interface |
| 3 | PRODAVE Load() | returns 0 | C# smoke test |
| 4 | plc_status() | returns 0, RUN flag = 1 | C# smoke test |
| 5 | db_read of DB10.0 / length 1 | returns 0, buffer populated | C# smoke test |
| 6 | Yellow LED on adapter | flickers during every call, then idle | Visual |
| 7 | STEP 7 accessible to the bus | Online -> Accessible Nodes lists the CPU | STEP 7 PG mode |
| 8 | MPI address uniqueness | PC = 0, CPU = 2, no other PG on bus with 0 | STEP 7 HW config |
Troubleshooting Matrix
| Symptom | Most likely cause | Fix |
|---|---|---|
| Load() returns 0xFFFF | PRODAVE not installed or 32/64-bit mismatch | Install PRODAVE V6.2, set PlatformTarget = x86 |
| ActivateConnection returns 0x0003 | PLC timeout - bus dead or wrong address | Confirm MPI address in STEP 7, replace cable, check 24 V on CPU |
| ActivateConnection returns 0x0004 | Baud rate mismatch | Force 187.5 kbps in Set PG/PC; verify CPU has not been set to 19.2 kbps PPI |
| db_read returns 0x0010 | DB does not exist in CPU at runtime | STEP 7 -> Blocks -> Download to CPU; check DB number matches HW config |
| db_read returns 0x0040 | CPU in STOP or password-protected | Use a PG to clear the password or restart in RUN |
| db_read returns 0x0030 | Requested length exceeds the DB length in CPU | Reduce length or extend the DB |
| Yellow LED never lights | Bus termination or reversed polarity | Set DIP SW1, swap DB-9 orientation, test on a known-good CPU |
| Intermittent 0x0008 / 0x0080 errors | EMI on long cable, missing shield ground | Add ferrite, ground DB-9 shield at PLC end only, shorten run |
| Only one PC can connect, second hangs | Two PGs with MPI address 0 | Reassign one PG to address 1 or higher in Set PG/PC |
| Works in STEP 7 but not in C# | Set PG/PC not pointing to S7ONLINE | Re-run Set PG/PC and pick PC Adapter (MPI) -> S7ONLINE |
| First call works, second fails | Connection not reactivated after Unload | Always ActivateConnection after Load(), DeactivateConnection before Unload |
| Bit read returns 0 but DB is non-zero | Byte/bit order reversed (Big-Endian on PLC) | Swap byte array before indexing bits; S7-300 stores bits in little-endian byte order |
| Performance < 5 read/s | Polling each byte individually | Batch into a single db_read of the largest required region |
Safety and Operational Limits
- The PC Adapter USB is rated for office/industrial environments, not for permanent installation in cabinets with high EMI from VFDs or welding inverters.
- Do not plug or unplug the DB-9 connector while the CPU is in RUN; the resulting bus glitch can drop other stations (drives, ET200S) into fault.
- Do not stack two MPI masters (PG + PRODAVE) on the same physical segment without verifying their bus addresses; collisions trigger SF on the CPU.
- The cable is hot-pluggable on the USB side only. Hot-unplug from the MPI side is forbidden by EN 50170.
Performance Notes
At 187.5 kbps with a 64-byte DB read, the round-trip latency through PRODAVE is 25-40 ms on a modern Windows 10/11 PC. The bottleneck is the half-duplex RS-485 turnaround, not the USB pipe. For polling loops, prefer a single db_read that fetches the entire block of interest, then parse in memory. Avoid sub-byte calls - each db_bit_read is a full token-pass cycle.
Reference Documents
- SIMATIC PC Adapter USB - Operating Instructions - official Siemens manual for the 6ES7 972-0CB20-0XA0 and 6ES7 972-0CB35-0XA0 cable.
- Siemens Industry Online Support - entry point for PRODAVE MPI/DP manual (article ID 21971420) and S7-300 CPU manuals.
- S7-300 CPU 31xC and CPU 31x Reference Manual - for the MPI interface parameter set on the CPU side.
FAQ
Can I use the 6ES7 972-0CB20-0XA0 with SIMATIC NET instead of PRODAVE?
No. SIMATIC NET softnet does not provide a channel for the PC Adapter USB. PRODAVE MPI/DP, libnodave over the S7ONLINE access point, or STEP 7 PG mode are the only supported paths.
My C# program throws "Load failed: 0xFFFF" on Windows 11 x64 - what is wrong?
PRODAVE_MPI.DLL is 32-bit. Set your project's PlatformTarget to x86 (AnyCPU with Prefer 32-bit on .NET Framework). A 64-bit host process cannot load the DLL even when the file is present on disk.
What baud rate do I need for S7-300 MPI?
Always 187.5 kbps. The CPU does not negotiate; the PG (or PRODAVE) must match. Setting 19.2 kbps forces PPI legacy mode and the S7-300 will reject the token.
How fast can I poll a 64-byte DB?
About 25-40 ms round-trip on a typical office PC at 187.5 kbps. Avoid bit-level calls - each one is a full token-pass cycle and is roughly 10x slower.
Does the PC Adapter USB work with S7-1200 and S7-1500?
No. The 6ES7 972-0CB20-0XA0 only speaks MPI/PROFIBUS. The S7-1200/1500 family uses PROFINET only and requires a CP card, IE-capable cable, or the native Ethernet interface.