S7-1200 TSEND_C and TRCV_C: Ethernet Data Transfer Configuration

David Krause12 min read
S7-1200SiemensTutorial / 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

1. Overview

The SIMATIC S7-1200 supports peer-to-peer Ethernet data exchange between two CPU 1214C (or any S7-1200/S7-1500 combination) controllers using the TSEND_C and TRCV_C instructions from the "Communication" palette in TIA Portal. TSEND_C/TRCV_C are compact versions of the older TUSEND/TURCV pair and internally handle the connection establishment (TCON), termination (TDISCON), and option-byte handling. The transport protocol is ISO-on-TCP (RFC 1006) by default, which provides acknowledged, connection-oriented, point-to-point data transfer over the PROFINET interface of the CPU.

This reference applies specifically to a two-CPU 1214C topology (TIA Portal V11 or later), an unmanaged switch, and a default firmware of the S7-1200 family. The article resolves two recurring field issues:

  1. The TSEND_C CONNECT input rejecting every data block with "incompatible data type".
  2. Values written from an HMI tag are not propagated to the partner PLC, while values written from the program ARE propagated.

2. Prerequisites

Item Specification
Controller A (active/client) CPU 1214C DC/DC/DC or DC/DC/RLY, FW 4.0 or higher recommended for TIA V11-V16 compatibility
Controller B (passive/server) CPU 1214C, same firmware family
Engineering TIA Portal V11 SP2 Update 5 or later (V13, V14, V15, V16, V17 supported with the same block interface)
Network Unmanaged 100 Mbit/s switch, CAT5e or higher, point-to-point works without a switch using a crossover or auto-MDI(X) cable
IP addresses 192.168.0.1 / 255.255.255.0 and 192.168.0.2 / 255.255.255.0 (must be in the same subnet)
Open communication connections CPU 1214C supports up to 8 active and 8 passive Open User Communication connections; this project uses 1 of each
Block library version TSEND_C V3.0 / TRCV_C V3.0 (auto-installed with TIA Portal)
Note: The S7-1200 PROFINET port is on the CPU itself. CPU 1214C has one integrated PROFINET interface; no CP module is required for ISO-on-TCP. If a second physical port is required (e.g. for a separate HMI network), add a CM 1243-1 or CSM 1277 unmanaged switch module.

3. Network Topology and IP Planning

PLC_A CPU 1214C 192.168.0.1 TSEND_C (active) Subnet: 255.255.255.0 Connection ID = 1 PLC_B CPU 1214C 192.168.0.2 TRCV_C (passive) Subnet: 255.255.255.0 Connection ID = 1 Switch 100 Mbit S7-1200 ISO-on-TCP Data Transfer Topology

Both controllers MUST reside in the same IP subnet. ISO-on-TCP uses port 0x1024 (decimal 1024) as TSAP for S7-1200; you may freely select local and remote TSAPs (16 bits each) provided that the active and passive sides mirror one another.

4. Configuring the Connection in TIA Portal

The most common beginner error is wiring the CONNECT input to a user-defined data block of the wrong structure. Siemens requires a TCON_IP_V4 System Data Type (SDT) data block. There are two ways to generate it:

  1. Right-click the CPU in "Devices & Networks" and add an "ISO-on-TCP connection" between the two PLCs. TIA Portal auto-creates the connection data block.
  2. Manually add a new global DB, declare a single CONNECT variable of type TCON_IP_V4 (V3.0), and fill the parameters.

Recommended path (Method 1):

  1. Open "Devices & Networks" view of PLC_A.
  2. Drag a connection line from the PROFINET port of PLC_A to PLC_B.
  3. Choose "ISO-on-TCP connection" from the popup.
  4. Click the connection line, go to Properties → General, and note the Connection ID (default = 1).
  5. In PLC_A's project tree, expand "Program blocks → System blocks → Additional system blocks". A new DB named SENDCONNECTION_1 (or similar) appears. This is the DB you wire to the TSEND_C CONNECT input.

5. TSEND_C Block Parameters

Input Data type Meaning PLC_A example
REQ BOOL Rising edge starts a send job SendTrigger (edge-detected)
ID CONN_OUC Connection reference from TCON 1 (from Devices & Networks)
CONNECT TCON_IP_V4 Connection description (auto-DB) "SENDCONNECTION_1".CONNECT
DATA VARIANT Pointer to send area (DB / M / I/Q) "DataDB".SendBuffer
LEN UINT Number of bytes to send 100
CONT BOOL Keep connection after send (TRUE = keep open) TRUE
Output Data type Meaning
DONE BOOL One-cycle TRUE after successful send
BUSY BOOL TRUE while job is in progress
ERROR BOOL TRUE if the job failed
STATUS WORD Status / error code (see diagnostics table)

6. TRCV_C Block Parameters

Input Type Meaning PLC_B example
EN_R BOOL Enable reception (TRUE = always ready) TRUE
ID CONN_OUC Connection reference 1
CONNECT TCON_IP_V4 Connection description "RCVCONNECTION_1".CONNECT
DATA VARIANT Receive area (must be large enough) "DataDB".RecvBuffer
LEN UINT Max bytes to receive (0 = accept any length) 0 (use 100 if you want fixed-length)
ADHOC BOOL Copy partial frames immediately TRUE

7. TCON_IP_V4 Connection Description

The "incompatible data type" error in the CONNECT input almost always means the user created a DB with the wrong UDT or used TCON_IP_V4 from a different version. The TIA Portal V11-V17 SDT contains:

TYPE TCON_IP_V4
VERSION : 3.0
STRUCT
   InterfaceId    : HW_ANY;       // PROFINET interface HW identifier, usually 64
   ConnectedMcId  : BYTE;         // Multicast ID, 0 = unicast
   LocalPort      : UINT;         // Local TSAP / port (e.g. 0x1024)
   RemoteAddress  : IP_V4_STRUCT; // 4 bytes + 2 bytes for port
   LocalAddress   : IP_V4_STRUCT; // optional, fill with 0.0.0.0
   ConnectionType : BYTE;         // 0x11 = TCP, 0x12 = ISO-on-TCP, 0x13 = UDP
   ActiveEstablished : BOOL;      // TRUE = active (client), FALSE = passive (server)
END_STRUCT
END_TYPE

Set ConnectionType = 0x12 for ISO-on-TCP. Set ActiveEstablished = TRUE on the TSEND_C side and FALSE on the TRCV_C side. The RemoteAddress must contain the partner's IP in network byte order (e.g. 192,168,0,2 + port 0x0000, port field stays 0 for ISO-on-TCP because TSAPs use LocalPort/RemotePort in the next fields).

8. Ladder / SCL Sample Code

PLC_A (sender, OB1 main scan):

// Edge-detect a "send now" trigger
A   M10.0            // Send request from HMI / program
FP  M10.1            // Edge memory bit
=   "SendTrigger"

// Call TSEND_C
CALL "TSEND_C_DB" , "TSEND_C_INST"
  REQ    := "SendTrigger"
  ID     := 1
  CONNECT:= "SENDCONNECTION".CONNECT
  DATA   := "DataDB".SendBuffer
  LEN    := 100
  CONT   := TRUE
  DONE   => "StatDB".SendDone
  BUSY   => "StatDB".SendBusy
  ERROR  => "StatDB".SendError
  STATUS => "StatDB".SendStatus

PLC_B (receiver, OB1 main scan):

// Always ready to receive
SET
=   "RecvEnable"

CALL "TRCV_C_DB" , "TRCV_C_INST"
  EN_R   := "RecvEnable"
  ID     := 1
  CONNECT:= "RCVCONNECTION".CONNECT
  DATA   := "DataDB".RecvBuffer
  LEN    := 0
  ADHOC  := TRUE
  DONE   => "StatDB".RecvDone
  BUSY   => "StatDB".RecvBusy
  ERROR  => "StatDB".RecvError
  STATUS => "StatDB".RecvStatus
  RCVD_LEN => "StatDB".RecvLen

9. Root Cause: HMI-Triggered Values Do Not Reach Partner PLC

This is the second and most common production symptom: a value written into SendBuffer by the PLC program is correctly transmitted to the partner, but a value written by the HMI is not. The reason is purely about REQ edge behavior.

TSEND_C is edge-triggered. The send job executes exactly once per rising edge on REQ. The CPU only sends the current content of DATA at that moment. Two scenarios occur in the field:

  1. HMI writes a new value, but REQ does not pulse — TSEND_C has no reason to fire, so the partner keeps the old data.
  2. Program logic only sets REQ when a "process event" occurs — a value change alone does not generate an edge.

Typical cause: the program uses a button-driven or event-driven REQ (e.g. M10.0 set when a sensor trips) but the HMI just writes to DataDB.SendBuffer directly, without pulsing any send trigger.

10. Fix: HMI-Side Change Detection / Cyclic Send

Three proven solutions, ordered from most elegant to most brute-force:

10.1 Trigger REQ on every value change (recommended)

Add a "send enable" or "send on change" tag. In PLC_A, compare SendBuffer to a shadow copy. If a difference is detected, pulse REQ:

// In OB1 of PLC_A
"Shadow".LastSent := "Shadow".LastSent OR 0;
IF "DataDB".SendBuffer <> "Shadow".LastSent THEN
    "Shadow".ChangeDetected := TRUE;
END_IF;

// Edge detect the change flag
IF "Shadow".ChangeDetected THEN
    "SendTrigger"(FP := "Shadow".EdgeMem);   // SCL one-shot
    "Shadow".ChangeDetected := FALSE;
    "Shadow".LastSent := "DataDB".SendBuffer;
END_IF;

With this block in place, an HMI write to DataDB.SendBuffer will automatically trigger a transmission on the next PLC cycle.

10.2 Use a polling / heartbeat send

Send the entire buffer on a fixed time base (e.g. every 200 ms using a clock bit from OB35 or a self-generated flasher). This guarantees eventual consistency regardless of HMI writes:

// Using CPU clock memory, byte 1000 - bit 5 = 2 Hz
// 2 Hz is too fast for ISO-on-TCP, scale to 0.5 Hz via TON
"Clock_2Hz"( TP := 200ms, Q => "HalfHz" );
IF "HalfHz" THEN
    "SendTrigger"(FP := "EdgeSend");
END_IF;

10.3 Make the HMI pulse the send trigger

Bind the HMI button (or "value changed" event of the input field) to set a dedicated tag such as HMI_SendRequest for one cycle. The PLC detects the edge and fires TSEND_C. This is the least preferred approach because the HMI must know about the trigger variable, coupling display logic to communication logic.

11. Common TSEND_C / TRCV_C Status Codes

STATUS (hex) Meaning Remediation
0x0000 No error —
0x7000 No job in progress (DONE/BUSY/ERROR all 0) Normal idle
0x7001 Job started, waiting for execution Normal
0x7002 Job running Normal
0x8085 LEN parameter invalid (0, negative, or > LEN of source area) Use UINT length matching buffer size
0x8086 ID parameter invalid (connection not configured) Re-create connection in Devices & Networks
0x80A1 Connection / port in use Check partner PLC is reachable, no duplicate connection IDs
0x80C3 All connection resources exhausted (CPU limit hit) Reduce Open User Communication count to 8 active / 8 passive
0x80C4 Temporary connection error (TCP RST, partner not ready) Check TSAP / IP, partner TRCV_C EN_R, partner CPU in RUN
0x80C7 Send data length exceeds local send buffer Reduce LEN
0x80D0 Connection was terminated by TDISCON or partner Check partner CPU RUN state, reset both controllers
0x80E0 Connection is currently being set up (BUSY) Wait for DONE or ERROR
0x80E9 Connection setup rejected by partner Check TSAP mismatch: ISO-on-TCP TSAPs must swap between partners
0x8181 Data length differs from LEN in receive Set LEN = 0 (length received with the frame) and inspect RCVD_LEN

12. Diagnostic Procedure

  1. Online → Diagnostics → Statistics in TIA Portal on the PROFINET interface of PLC_A: verify the partner IP appears as reachable.
  2. Open a watch table on PLC_A. Monitor StatDB.SendBusy, SendError, SendStatus. After pulsing REQ once, BUSY should pulse to TRUE for one cycle and DONE to TRUE on success.
  3. On PLC_B, monitor RecvDone and RecvLen. After a successful send, RecvDone = TRUE for one cycle and RecvLen = number of bytes transferred.
  4. If BUSY stays TRUE for > 5 s, STATUS will report a connection error (0x80C4, 0x80E9). Capture the hex and cross-reference Section 11.
  5. Open the S7-1200 "Diagnostics buffer" (online → Diagnostics buffer). The connection event includes the partner IP and the failing TSAP.

13. Verification Checklist

Step Expected Result Pass criteria
Compile & download both PLCs No compile errors, both in RUN OK / Pass
Online → Connections Connection ID 1 listed as "Established" Status green
Program-triggered send Partner value updates within 2 cycles RecvDone = TRUE
HMI-triggered write Partner value updates after change-detect logic fires RecvDone = TRUE within 1 scan of the change
Cold restart both PLCs Connection re-establishes within 5 s BUSY → DONE
Disconnect Ethernet cable for 10 s and reconnect STATUS reports 0x80D0 briefly, then DONE Auto-recovery to 0x0000

14. Field-Proven Caveats

  • Do not place TSEND_C in OB1 with REQ tied to TRUE — the CPU will send at line speed and exhaust the Open User Communication buffer. Always use a finite-edge trigger or a timer.
  • TRCV_C with LEN = 0 and ADHOC = TRUE is the most robust receive pattern: partial frames are copied immediately and RCVD_LEN reports the actual number of bytes received. Use this for variable-length messages.
  • ISO-on-TCP TSAPs are 16-bit. The S7 convention is to put CPU slot number in the second byte (e.g. 01.01 = rack 1 slot 1). For a CPU 1214C use 01.01; this avoids collisions if you later add a CM module.
  • Two TSEND_C blocks with the same Connection ID cause STATUS = 0x80A1. Always use unique connection IDs for each partner.
  • CPU 1214C FW 4.0 and earlier will accept only the V1.0 SDT TCON_IP_V4 structure. If upgrading the project to a newer TIA Portal, right-click the block → "Update to latest version" to remap the structure.
  • The same logic applies when the partner is a S7-1500. The block interfaces are identical; the only thing that changes is the maximum number of Open User Communication connections (S7-1500 supports far more).

15. Related Protocols

TSEND_C/TRCV_C are ISO-on-TCP only. If the requirement is to talk to a third-party device that does not support RFC 1006 (e.g. a SCADA system that expects raw Modbus/TCP or a generic TCP socket), use:

  • MODBUSCLIENT / MODBUSSERVER instructions for Modbus TCP on the same S7-1200.
  • TSEND / TRCV (the older, non-compact pair) for raw TCP without ISO-on-TCP header.
  • Open User Communication as UDP with TUSEND/TURCV for non-acknowledged broadcasts.

Why does TSEND_C reject every data block with "incompatible data type" on the CONNECT input?

The CONNECT input expects a variable of data type TCON_IP_V4 (V3.0 in modern TIA Portal). A user-defined DB created with the "Add new DB" wizard has the wrong structure. The fix is to let TIA Portal create the connection DB automatically: in "Devices & Networks", drag an ISO-on-TCP connection between the two PLCs and use the system-generated DB as the CONNECT source. This guarantees the right SDT version is used.

Values written from my program reach the partner PLC, but HMI writes do not. Why?

TSEND_C is edge-triggered on REQ. A value change alone does not transmit — a rising edge on REQ is required. The HMI is writing into the same data area, but no edge is being generated. Add a change-detection block in the sender PLC that compares the current value to a shadow copy and pulses REQ on difference, or trigger a cyclic send on a 200-500 ms heartbeat. This makes HMI writes propagate transparently.

What is the default TSAP and port for ISO-on-TCP on the S7-1200?

ISO-on-TCP on the S7-1200 uses TSAPs (Transport Service Access Points), not IP port numbers. The default S7-1200 convention is 01.01 for both local and remote (rack 1, slot 1). The TSAP is configured inside the TCON_IP_V4 structure. If both CPUs use slot 1, the configuration mirrors naturally — local TSAP on PLC_A equals remote TSAP on PLC_B and vice versa.

How many TSEND_C / TRCV_C connections can a CPU 1214C handle?

The CPU 1214C supports up to 8 active and 8 passive Open User Communication connections simultaneously (for ISO-on-TCP, TCP, and UDP combined). This is sufficient for a small multi-PLC network. If you need more, use a S7-1500 or a CM 1243-1 communication module on the S7-1200.

Status 0x80E9 "Connection setup rejected by partner" — how do I fix it?

The local and remote TSAPs do not match correctly. ISO-on-TCP requires the active side to point at the partner's TSAP, and the passive side to listen on a TSAP that matches. Open the TCON_IP_V4 structure on both PLCs and verify that the LocalPort on the active side equals the LocalPort on the passive side, and the RemoteAddress on the active side equals the passive side's local TSAP. Restarting both PLCs after the change is recommended.

Back to blog