Configuring Freeport ASCII Serial Communication Between S7-300 (CPU 312C) and a Raspberry Pi in TIA Portal V13
Establishing a direct point-to-point (PtP) ASCII serial link from an S7-300 PLC to a Raspberry Pi is a common university and retrofit scenario, but it is constrained by the S7-300 hardware: the standard DB9 connector on a CPU 312C is hard-wired to MPI/PROFIBUS and cannot be reconfigured for freeport serial. You must add a dedicated communication processor (CP 340 or CP 341) in the RS-232 variant, configure it inside TIA Portal V13, and drive it from a PtP instruction block in your STEP 7 ladder program. This reference walks through the full project, from part selection to wiring to commissioning, with status codes, parameter tables, ladder snippets and a Python client.
1. Problem Definition and Constraints
The S7-300 CPU 312C family (6ES7312-5BE03-0AB0, 6ES7312-5BF04-0AB0) ships with exactly one integrated serial DB9 interface, and Siemens Industry Online Support documentation locks that port to MPI/DP at 187.5 kbit/s or 12 Mbit/s PROFIBUS. It is not software-reconfigurable to a generic UART, and the "freeport" or "point-to-point" mode taken for granted on the S7-200 (RS-485) and S7-1200 (RS-485/RS-232 via CM) is therefore not available on the CPU 312C native port.
To talk ASCII to a Raspberry Pi over RS-232 you must install a CP 340 or CP 341 in a free slot of the S7-300 rack, adjacent to the CPU. The CP is the only module on the S7-300 that Siemens ships with loadable drivers for ASCII, 3964(R), RK 512 and Modbus RTU master/slave protocols.
2. Hardware Selection Matrix
| Module | Order Number | Protocols | Recommended Use |
|---|---|---|---|
| CP 340 RS-232C (1 channel) | 6ES7340-1AH02-0AE0 | ASCII, 3964(R) | Lowest-cost ASCII freeport to Pi |
| CP 340 RS-422/485 (1 channel) | 6ES7340-1BH02-0AE0 | ASCII, 3964(R) | Differential/segmented bus |
| CP 341 RS-232C (1 channel) | 6ES7341-1AH02-0AE0 | ASCII, 3964(R), RK 512, Modbus RTU* | Recommended; future Modbus path |
| CP 341 RS-422/485 (1 channel) | 6ES7341-1BH02-0AE0 | ASCII, 3964(R), RK 512, Modbus RTU* | RS-485 multi-drop |
| CP 341 20 mA (TTY) | 6ES7341-1CH02-0AE0 | ASCII, 3964(R), RK 512 | Legacy TTY devices |
* Modbus RTU master requires the licensed driver 6ES7870-1AA01-0YA0; Modbus RTU slave uses 6ES7870-1AB01-0YA0. The product family is documented under CP 340 product support and CP 341 product support.
For a simple Pi↔PLC ASCII link, the CP 340 RS-232 is sufficient. The CP 341 is preferred because it shares the same wiring and pinout but also accepts the loadable Modbus RTU driver option, doubling as a future fieldbus gateway with no hardware change.
3. Prerequisites and Required Components
- S7-300 CPU 312C (any firmware ≥ V2.0 — 6ES7312-5BF04-0AB0 typical).
- CP 340 RS-232 (6ES7340-1AH02-0AE0) or CP 341 RS-232 (6ES7341-1AH02-0AE0) installed in a free slot of the rack, conventionally slot 4.
- RS-232 shielded cable, DB9 female ↔ DB9 female, null-modem crossed. Maximum cable length is 15 m at 9 600 bit/s, 10 m at 19 200 bit/s, 6 m at 38 400 bit/s per the SIMATIC S7-300 system documentation.
- Raspberry Pi (any model with USB, or — with care — GPIO UART).
- USB ↔ RS-232 adapter based on FTDI FT232 or Prolific PL2303. The Raspberry Pi GPIO UART operates at 3.3 V TTL and is not RS-232 level compatible — never wire the Pi's Tx/Rx directly to the CP front connector.
- TIA Portal V13 SP1 (Update 9 or later) with STEP 7 Professional installed.
- Raspbian / Raspberry Pi OS with the python3-pyserial package.
4. Electrical Wiring: CP 340/341 ↔ USB-RS232 Adapter
The CP 340/341 RS-232C front connector is a male DB9 (DTE). The USB-RS232 adapter on the Pi presents a male DB9 (also DTE). Two DTE devices must be cross-connected with a null-modem cable. Minimum connections to bridge:
| CP 340/341 DB9 (DTE) Pin | Signal | USB-RS232 Adapter DB9 (DTE) Pin |
|---|---|---|
| 2 | TxD | 3 (RxD) |
| 3 | RxD | 2 (TxD) |
| 5 | Signal GND | 5 (GND) |
| 1 + 4 + 6 (local bridge at CP end) | CD + DTR + DSR looped | — |
| 7 + 8 (local bridge at CP end) | RTS + CTS looped | — |
The CP 340 supports up to 19 200 bit/s; the CP 341 reaches 115 200 bit/s depending on firmware. Keep below 38 400 bit/s on a 10 m laboratory cable to guarantee error-free operation.
5. TIA Portal V13 Project Setup
- Open TIA Portal V13 and create a new project. Open Devices & Networks.
- Add new device → SIMATIC S7-300 → CPU 312C → select the exact order number (e.g. 6ES7312-5BF04-0AB0) and the matching firmware version. The CPU occupies rack slot 1.
- Open the device view of the rack. Slot 4 is the first usable CP slot on a standalone CPU 312C.
- From the hardware catalog, expand Communication → CP 340 → drag 6ES7340-1AH02-0AE0 onto slot 4. For CP 341 use 6ES7341-1AH02-0AE0.
- Compile the hardware configuration (right-click the CPU → "Compile and download hardware") and transfer to the S7-300 over the USB-MPI adapter.
- After successful download, the CPU switches to RUN and the CP's STATUS LED begins flashing until its protocol parameters are loaded in the next step.
6. CP 340 Port Parameterization in TIA Portal V13
In the device view, double-click the CP and open the Properties → Port tab. Match the parameters to the Raspberry Pi side:
| Parameter | Lab Example | Comment |
|---|---|---|
| Protocol | ASCII | CP 340 ASCII mode is freely programmable with no driver license |
| Baud rate | 9 600 bit/s | Safe default for a university lab |
| Data bits | 8 | Standard |
| Parity | None | Match pyserial settings on the Pi |
| Stop bits | 1 | Standard |
| End-of-receive delimiter | LF (0x0A) | Each telegram ends with line feed; configure LF as termination in the CP |
| Receive buffer size | 1024 bytes | Default; raise for long telegrams |
| Handshake | None (or RTS/CTS) | Enable hardware handshake only on long cables |
| Inter-character timeout | 4 character times | Closes the frame if the host stalls mid-message |
Compile and download the hardware configuration to the CPU. The CP's STATUS LED transitions from flashing to steady green when the parameters are accepted.
7. Ladder Logic: PtP_SND and PtP_RCV
After parameter download the CP exposes its serial interface as a hardware identifier (HW ID). In TIA Portal V13 open CP → Properties → System constants and copy the value (typical on slot 4 is W#16#100). The PtP blocks are in the Instructions palette under Communication → PtP Communication:
- PtP_SND (formerly FB 9 / SFB 9 on classic STEP 7) – transmits a buffer from a data block.
- PtP_RCV (formerly FB 10 / SFB 10) – receives into a data block and reports the byte count.
Create a shared DB ("PtP_DB") containing two byte arrays: SND_BUF : ARRAY[0..31] OF BYTE, RCV_BUF : ARRAY[0..63] OF BYTE, plus SND_LEN : INT, RCV_LEN : INT, STATUS : WORD, and Bool tags DONE, ERROR, NDR.
Sample send rung (REQ is fired by a tag SendTrigger):
Network 1 – Send "ON\n" to Raspberry Pi
A "SendTrigger" // Bool input from HMI / logic
= "PtP_DB".REQ
CALL "PtP_SND"
REQ := "PtP_DB".REQ
LADDR := W#16#100 // HW ID of CP 340 RS-232 interface
DB_NO := 100 // DB that holds the data
DBB_NO := 0 // Start at byte 0 of SND_BUF
LEN := 3 // "ON\n" = 3 bytes
DONE := "PtP_DB".DONE
ERROR := "PtP_DB".ERROR
STATUS := "PtP_DB".STATUS
NOP 0
Sample receive rung (polled once per OB1 scan):
Network 2 – Always poll receive
CALL "PtP_RCV"
EN_R := TRUE
LADDR := W#16#100
DB_NO := 101
DBB_NO := 0
NDR := "PtP_DB".NDR
ERROR := "PtP_DB".ERROR
STATUS := "PtP_DB".STATUS
LEN := "PtP_DB".RCV_LEN
NOP 0
Network 3 – Evaluate the first byte as a Bool
L "PtP_DB".RCV_BUF[0]
L B#16#31 // ASCII '1'
==I
= "PiSwitch" // Bool usable elsewhere in the program
The HW ID W#16#100 is illustrative; in your project the value comes from the CP's System constants. Common values on slot 4 are W#16#0100, W#16#100, or any other identifier TIA Portal assigns.
FP) on a pulse flag, or tie REQ := "PtP_DB".DONE so the next transmit fires automatically when the previous one completes.8. Raspberry Pi Python Client
Install pyserial on the Pi:
sudo apt update
sudo apt install python3-pyserial -y
ls /dev/ttyUSB* # confirm USB-RS232 adapter
Minimal Python program that toggles the "PiSwitch" Bool in the PLC by sending ASCII 1\n or 0\n:
#!/usr/bin/env python3
import serial, time
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1.0,
rtscts=False,
xonxoff=False
)
def send_state(state: str):
payload = (state + '\n').encode('ascii') # 0\n or 1\n
ser.write(payload)
print(f"TX {payload!r}")
try:
while True:
for s in ('0', '1'):
send_state(s)
time.sleep(2.0)
except KeyboardInterrupt:
ser.close()
The Pi receives nothing back unless the PLC is configured to reply. To verify the Pi→PLC direction, open TIA Portal online → "Monitor / Modify" and watch the PiSwitch tag flip in real time as the script alternates 0 and 1.
9. CP 340 / CP 341 LED Diagnostics
| LED | State | Meaning |
|---|---|---|
| SF (red) | On | Group error – inspect STATUS word of PtP_SND / PtP_RCV |
| STATUS (green) | Flashing | Parameters not yet loaded or backplane fault |
| STATUS (green) | Steady on | CP configured and idle |
| TXD (yellow) | Flickering | Bytes leaving CP toward the Pi |
| RXD (yellow) | Flickering | Bytes arriving at CP from the Pi |
10. STATUS Word Diagnostic Reference
The STATUS output of PtP_SND and PtP_RCV reports CP-internal error codes in the format 0xyy00 where yy is the failure class. Common ASCII values for CP 340/341:
| STATUS (hex) | Meaning | Remedy |
|---|---|---|
| 0x0000 | No error | — |
| 0x0700 | Receive-buffer overflow | Increase RCV_BUF size or poll PtP_RCV faster |
| 0x0800 | Parity / framing / break | Verify baud rate, parity, stop bits match on both ends |
| 0x0900 | Character timeout – telegram incomplete | Lengthen telegram timeout, or check delimiter byte |
| 0x0E01 | Hardware fault – CP not in RUN | Check STATUS LED, recompile and re-download HW config |
| 0x0F01 | Invalid LADDR | Cross-check HW ID under CP → Properties → System constants |
11. Troubleshooting Matrix
| Symptom | First Check | Likely Cause |
|---|---|---|
| STATUS LED stays flashing after download | Compare baud rate / parity between CP and Pi | Parameter set mismatched |
| SF LED on, STATUS = 0x0E01 | Re-trigger HW config download | CP not parameterized in TIA Portal |
| TXD blinks but Pi sees no bytes | Check null-modem wiring with multimeter | Tx ↔ Tx cross mis-wired |
| Pi sees bytes but PtP_RCV never sets NDR | Watch STATUS of PtP_RCV | End delimiter not LF or buffer overflow |
| Receive reads but first byte is corrupted | Confirm 8N1 on both ends | Parity or stop-bit mismatch |
| PtP_SND returns ERROR after first call | REQ held TRUE continuously | REQ must be a single-cycle pulse |
| CP reports 0x0F01 | Open CP → System constants | Wrong HW ID in LADDR |
| TIA Portal shows "Module does not support isochronous mode" | Remove isochronous assignment | CP 340/341 do not support isochronous operation |
12. Commissioning Verification
- Compile and download the hardware configuration. Confirm STATUS LED is steady green.
- Open a watch table in TIA Portal containing
PtP_DB.SND_LEN,PtP_DB.RCV_LEN,PtP_DB.STATUS,PiSwitch,PtP_DB.DONE,PtP_DB.NDR. - Pre-load
SND_BUFwith ASCII4F 4E 0A("ON\n") and trigger SendTrigger. - Verify DONE pulses high, ERROR stays low, STATUS = 0x0000.
- Start the Pi Python script. Verify RXD LED on CP flashes with each transition and
PiSwitchfollows the loop. - Disconnect the cable;
PiSwitchshould freeze on the last value without raising ERROR on the CP.
13. Migration Path to S7-1200 (Recommended for New Projects)
If the project can tolerate new hardware, the S7-1200 (CPU 1211C through 1217C) eliminates the need for an external CP. The onboard Ethernet port and the optional CM 1241 RS-232 (6ES7241-1AH32-0XB0) or CM 1241 RS-485 (6ES7241-1CH32-0XB0) provide freeport ASCII with the Send_P2P / Receive_P2P instruction family integrated into STEP 7 Basic in TIA Portal. Switching from RS-232 to TCP/IP further reduces cable cost and gives much higher data rate for the same programming effort. See the TIA Portal product page for compatible versions.
The legacy S7-200 alternative (CPU 224XP / 226 with RS-485 freeport) is viable for laboratory work but the family is discontinued and is not programmable in TIA Portal V13 — STEP 7 Micro/WIN V4 SP9 is required.
14. FAQ
Can I use the S7-300 CPU 312C's native DB9 connector for ASCII freeport?
No. The DB9 is hard-wired to MPI/PROFIBUS at 187.5 kbit/s or 12 Mbit/s and is not software-reconfigurable. You must install a CP 340 or CP 341 in an adjacent slot for ASCII / 3964(R) / RK 512 / Modbus RTU serial protocols.
Which CP variant should I order for ASCII communication with a Raspberry Pi?
Use CP 341 RS-232C (6ES7341-1AH02-0AE0). It supports the same ASCII and 3964(R) protocols as CP 340 but also accepts loadable drivers for Modbus RTU master and slave, giving you a future migration path without hardware change.
Do I need a null-modem cable or a straight-through cable?
Null-modem. Both the CP 340/341 RS-232 front connector and a USB-RS232 adapter on the Pi are DTE, so the TxD/RxD lines must be crossed and the handshaking pins looped back locally.
Why does my ladder receive STATUS 0x0700 immediately?
STATUS 0x0700 indicates a receive-buffer overflow. Either extend the destination array in the receive DB, poll PtP_RCV faster than telegrams arrive, or add an inter-character timeout so the CP closes the frame earlier.
Can I read the Pi's 3.3 V GPIO UART directly into the CP 340?
No. The CP 340/341 RS-232 driver expects ±3 V to ±15 V RS-232 levels. A direct connection will not function and can damage the CP. Use a USB-RS232 adapter on the Pi, or add a MAX3232 level translator between the Pi's UART pins and the CP.
How do I find the correct HW ID for the LADDR input?
Open the CP's Properties in TIA Portal V13 → System constants. The HW ID is listed for the PtP interface (commonly in the form Local~PROFIBUS_400~CP_340_Slave_0~PtP with a hexadecimal identifier). Copy that identifier into LADDR of PtP_SND and PtP_RCV.