Problem Overview
An S7-1200 CPU is configured as a Modbus RTU master polling multiple S7-1200 slaves over RS-485 using a CM 1241 (or SB 1241) communication module. The MB_MASTER instruction is sequenced to read six or seven remote PLCs in a round-robin schedule. When every slave is online the system works correctly.
The failure mode appears the moment a single remote PLC is powered down, disconnected, or has its RS-485 transceiver enter a high-impedance fault. MB_MASTER.BUSY latches in the TRUE state, DONE never sets, ERROR may or may not set depending on the wiring topology, and the remaining online slaves are no longer polled. Recovery requires either a CPU stop/run transition or a MB_COMM_LOAD re-trigger; simply changing the MB_ADDR input has no effect because the block is locked in the internal "waiting for response" state.
The same lockup pattern is reported on other Modbus RTU masters (e.g. EGX100 gateways) where one silent slave on a multi-drop bus freezes the entire master port. The root cause is identical: the master does not implement a bounded per-slave turnaround watchdog, so the blocking transaction is never released.
System Architecture & Prerequisites
Reference topology for the scenarios discussed below:
Hardware and software prerequisites:
- S7-1200 CPU (1211C, 1212C, 1214C, 1215C, 1217C) firmware V4.0 or higher; V4.2+ recommended for full Modbus RTU master capability. Confirm the firmware under Online → Diagnostics → CPU Information.
- RS-485 communication module or signal board:
CM 1241 RS485(6ES7241-1CH32-0XB0) orCB 1241 RS485(6ES7241-1CH30-1XB0). The RS232 variants do not drive a multi-drop bus and must not be used for this architecture. - Each slave S7-1200 must run a Modbus RTU server. Use
MB_SLAVEfrom the same library; configure the slave address in theMB_SLAVEinstance DB. - TIA Portal V15.1 or later. The legacy
MB_COMM_LOAD/MB_MASTERpair lives in the Libraries → MODBUS (RTU) - S7 1200 global library. - Belden 3105A or equivalent twisted-pair shielded cable, daisy-chained. 120 Ω termination at both physical ends, 10 kΩ bias resistors only at the master end (or on a powered slave if the master lacks them; the CM 1241 RS485 does not include internal bias).
- Configuration tool: TIA Portal → Devices & Networks → CM 1241 → Properties → Port Configuration.
Verify the CM 1241 port is configured for "Half-duplex (RS485) 2-wire mode" with bit timing matching the slaves: 9600 bit/s, 8E1 is the recommended starting point for cable runs under 200 m; drop to 19200 or 38400 only if all slaves are synchronised.
MB_MASTER Instruction Reference
The MB_MASTER instruction (FB 1217 in the S7-1200 MODBUS library) implements a single Modbus RTU transaction per rising edge of REQ. The block owns the serial port for the duration of the call; another MB_MASTER on the same port is illegal while BUSY = TRUE. Key I/O is summarised below.
| I/O | Type | Description |
|---|---|---|
| REQ | BOOL (in) | Rising edge starts one transaction. The edge is latched internally; the input can be cleared immediately after the edge is recognised. |
| MB_ADDR | USINT/UINT (in) | Modbus slave address 1…247. Modifying it after BUSY has set does not abort the active transaction. |
| MODE | USINT (in) | 0=FC01 read coils, 1=FC03 read holding, 2=FC15 write coils, 3=FC06 write single, 4=FC16 write multiple, 5=FC05 write single coil, 6=FC02 read discretes, 7=FC04 read input regs. |
| DATA_ADDR | UDINT (in) | Modbus register/coil start address (0-based). |
| DATA_LEN | UINT (in) | Number of elements; <= 2000 for FC03/FC04, <= 1968 for FC16. |
| DATA_PTR | VARIANT (in/out) | DB or M area pointer; length must equal DATA_LEN × bytes-per-element. |
| DONE | BOOL (out) | One-cycle TRUE on successful completion. |
| BUSY | BOOL (out) | TRUE from REQ edge until DONE, ERROR, or internal timeout. |
| ERROR | BOOL (out) | TRUE for one cycle on error, with STATUS providing the cause. |
| STATUS | WORD (out) | Modbus exception code (0x0001…0x000B) or library error code (0x0Exx). See table below. |
MB_MASTER STATUS codes relevant to slave offline diagnostics:
| STATUS (hex) | Class | Meaning | Typical cause |
|---|---|---|---|
| 0x0004 | Modbus | Slave Device Failure | Target reports an internal fault. |
| 0x000B | Modbus | Gateway Target No Response | Gateway upstream; rare on direct RTU. |
| 0x0E01 | Library | CRC error | Noise, wrong parity, baud mismatch. |
| 0x0E02 | Library | Response timeout | Slave absent, wrong address, break in cable. |
| 0x0E03 | Library | Parity / framing error | Bit timing, ground shift, line short. |
| 0x0E04 | Library | Receive buffer overflow | DATA_LEN too large for response window. |
| 0x0E05 | Library | Negative Acknowledge | Slave rejected request. |
| 0x8001 | Library | Wrong MODE / length | Programmer error; non-zero STATUS without ERROR. |
BUSY = TRUE indefinitely with no ERROR pulse, the REQ bit is being held high. The block is doing its job — it is waiting for the REQ edge to start the next transaction, and your application logic never finished the previous one.Root Cause: Why BUSY Locks When a Slave Drops
Three mechanisms are commonly misdiagnosed as "MB_MASTER broken":
-
REQ held continuously. The most common cause. If a programmer latches
REQ = TRUEuntilDONEarrives, the very firstBUSYrising edge is fine — but the instant a slave is offline,DONEnever sets, the latchedREQstays asserted, and the next poll cycle tries to re-transmit on the still-busy port. The instruction does not internally reset on its own; it remains in the "request pending" state until the watchdog expires or the CPU is restarted. -
REQ pulsed, but MB_ADDR never changed. The user's first instinct is to point the existing call at the next slave. As long as the FB is mid-transaction, modifying
MB_ADDRsimply rewrites an input the engine has already captured. The block must return to idle (BUSY = FALSE) before a new transaction can begin. -
No application-side watchdog. The library does offer a response_timeout parameter on
MB_COMM_LOAD, but it controls only how long the master waits for the bytes to come back. When set aggressively (<100 ms), the block will produceERROR+STATUS = 0x0E02in a few hundred milliseconds and clearBUSYon its own. When set loosely (default 1 s, or 5–10 s for slow RF modems), a single silent slave can hold the bus for that entire window and theBUSYlockup appears to be permanent.
The correct fix is to wrap MB_MASTER in a deterministic state machine that owns the REQ edge, a per-slave timeout, and a clean transition to the next address.
Solution Architecture: Polling State Machine
The pattern below runs in OB1 and sequentially addresses a configurable list of slaves. Each slave gets a bounded turnaround budget. If the budget elapses without DONE or ERROR, the state machine force-clears the request signal, logs the timeout, and moves on. The remaining online slaves continue to be polled every cycle.
Key design rules:
- Generate
REQas a one-scan pulse with rising-edge detection. Do not latch it. - Update
MB_ADDRonly whenBUSY = FALSEand the previous DONE/ERROR has been acknowledged. - Insert a minimum inter-frame delay of 3.5 character times between transactions (T#20 ms at 9600 bit/s; T#5 ms at 19200).
- Run a per-slave
TONwith a preset that exceeds the library's response_timeout by at least one full second. Library value defaults to 1000 ms; the application watchdog can be set to 2500 ms to be safe. - On watchdog expiry, force
REQ := FALSE, log the slave number, and advance the index. The next IDLE cycle will re-attempt the same slave; the rest of the array continues to be polled.
Step-by-Step Implementation in TIA Portal
-
Add the CM 1241 to the device configuration. Drag CM 1241 (RS485) - 6ES7241-1CH32-0XB0 to the right of the CPU in the device view. The hardware catalog lists it under Communication modules → CM - Point-to-Point → CM 1241. The module's HW ID (e.g. 271) is required by
MB_COMM_LOAD. - Configure the port. Open Properties → Port Configuration. Set Transmission mode to Half-duplex (RS485) 2-wire. Set baud, parity, and data bits to match every slave; mismatched slaves are the second most common cause of false lockups because they generate CRC errors that the master silently discards.
-
Insert the MODBUS library. In the project tree, right-click the CPU's Program blocks → Open the library → expand Global libraries → MODBUS (RTU) - S7 1200. Copy
MB_COMM_LOAD(FB 1215) andMB_MASTER(FB 1217) into the project. -
Create the configuration DB. Add a global DB, e.g.
DB_CommConfig, with a single tagMB_Load_DBof typeMB_COMM_LOAD. The REQ input is normallyTRUEfor the lifetime of the CPU; MODE = 0 selects the legacyMB_MASTERprotocol. BAUD, PARITY, FLOW_CTRL, and RESP_TO (response timeout) are critical; set RESP_TO to 1000 (1 s) for 9600 bit/s and increase to 2000–5000 for slower line drivers. -
Create the master instance DB. Add a global DB, e.g.
DB_ModbusMaster, and drop oneMB_MASTERinstance namedMasterinto it. The DB must be non-optimised (remove Optimised block access on the DB's attributes) because theDATA_PTRuses absolute addressing. -
Create the data image DB. Add
DB_SlaveDatawith one array per slave, e.g.Slave1 : ARRAY[0..19] OF WORD. Point theDATA_PTRat a slice of this DB for each transaction. -
Create the state-machine FB. Use the SCL source provided in the next section. Add it as a new function block
FB_ModbusCycler; declare a single instance DBDB_Cycler. -
Call the state machine in OB1.
CALL FB_ModbusCycler, DB_Cycler ;. Set Enable TRUE, supply the list of slave addresses as an input array. -
Download and go online. With the CM 1241 unplugged from the bus, watch
Master.BUSY; the cycler should advance through all slaves in one cycle, each generating a timeout. Plug the bus back in and verify the online slaves return good data while the offline one is flagged.
SCL Source: Modbus RTU Cycler
Paste the following into a new SCL source under Program blocks → Add new → SCL:
FUNCTION_BLOCK "FB_ModbusCycler"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
Enable : BOOL; // enable cycler (FALSE holds state in IDLE)
SlaveAddresses : ARRAY[1..16] OF USINT; // Modbus addresses to poll, 0 = skip slot
Mode : USINT; // 0=FC01 1=FC03 2=FC15 3=FC06 4=FC16 5=FC05 6=FC02 7=FC04
DataAddr : UDINT; // start register/coil in slave
DataLen : UINT; // number of elements per transaction
PerSlaveTimeout : TIME; // application watchdog, e.g. T#2.5S
CycleTime : TIME; // inter-poll delay, e.g. T#20MS
MasterInstance : MB_MASTER; // in-out reference to the master FB
END_VAR
VAR_OUTPUT
CurrentSlave : USINT;
CurrentStatus : WORD;
LastError : BOOL;
Busy : BOOL;
SlaveResults : ARRAY[1..16] OF WORD; // 0 = no data, 0x0Exx = error code
END_VAR
VAR
sState : INT; // 0=IDLE 10=SELECT 20=ARM 30=WAIT_BUSY 40=WAIT_DONE 50=RECOVER
iIndex : INT; // 0-based index into SlaveAddresses
bReqPulse : BOOL;
bReqLast : BOOL;
tCycle : TON_TIME;
tWatchdog : TON_TIME;
END_VAR
BEGIN
// Default outputs
Busy := MasterInstance.BUSY;
CurrentStatus := MasterInstance.STATUS;
LastError := MasterInstance.ERROR;
IF NOT Enable THEN
sState := 0;
MasterInstance.REQ := FALSE;
bReqPulse := FALSE;
tCycle(IN := FALSE);
tWatchdog(IN := FALSE);
RETURN;
END_IF;
CASE sState OF
0: // IDLE - wait between transactions
tCycle(IN := TRUE, PT := CycleTime);
IF tCycle.Q THEN
tCycle(IN := FALSE);
sState := 10;
END_IF;
10: // SELECT - advance to next non-zero slot
iIndex := (iIndex MOD 16) + 1;
IF SlaveAddresses[iIndex] = 0 THEN
// skip empty slots, try next
sState := 10;
// simple skip-up loop, bounded by 16 iterations
RETURN;
END_IF;
MasterInstance.MB_ADDR := UINT#SlaveAddresses[iIndex];
MasterInstance.MODE := Mode;
MasterInstance.DATA_ADDR := DataAddr;
MasterInstance.DATA_LEN := DataLen;
MasterInstance.DATA_PTR := NULL; // bind in OB1 wrapper
CurrentSlave := SlaveAddresses[iIndex];
sState := 20;
20: // ARM - generate rising edge on REQ
bReqPulse := TRUE AND NOT bReqLast;
MasterInstance.REQ := bReqPulse;
bReqLast := TRUE;
IF MasterInstance.BUSY THEN
bReqLast := FALSE;
tWatchdog(IN := TRUE, PT := PerSlaveTimeout);
sState := 30;
END_IF;
30: // WAIT_BUSY->DONE/ERROR/timeout
IF MasterInstance.DONE THEN
tWatchdog(IN := FALSE);
SlaveResults[iIndex] := WORD#16#0000;
sState := 0;
ELSIF MasterInstance.ERROR THEN
tWatchdog(IN := FALSE);
SlaveResults[iIndex] := MasterInstance.STATUS;
sState := 0;
ELSIF tWatchdog.Q THEN
// Watchdog fired before library did - force recovery
MasterInstance.REQ := FALSE;
SlaveResults[iIndex] := WORD#16#0E02;
sState := 40;
END_IF;
40: // RECOVER - hold REQ low until BUSY clears
MasterInstance.REQ := FALSE;
bReqLast := FALSE;
IF NOT MasterInstance.BUSY THEN
tWatchdog(IN := FALSE);
sState := 0;
END_IF;
ELSE
sState := 0;
END_CASE;
END_FUNCTION_BLOCK
Wrap the call in OB1 with a concrete DATA_PTR binding for each address if the per-slave data areas differ; the DATA_PTR := NULL line above is a placeholder for illustration. A common production pattern is to maintain one shared DB_SlaveData with one array per slave and update DATA_PTR in the SELECT step.
Ladder Logic: Minimal REQ Pulse Generator
If SCL is unavailable on the target firmware, the same logic collapses to three networks in a single FB.
Network 1 — cycle tick:
tCycle TON_TIME
| IN EN |
|----|/|--------+EN Q-|--+-- ( M10.0 "NextSlave")
| M10.7 \\ | |
| (lastState)---+--PT |
| T#20MS |
+--- tCycle.IN | |
Network 2 — slave index increment: Use an ADD/INC block feeding an INT tag DB_Cycler.iIndex; clamp at 16 to wrap to 1. Look up the address in an ARRAY of USINT and copy to Master.MB_ADDR using a MOVE block.
Network 3 — REQ edge pulse:
bReqPulse
|---[ P ]---( Master.REQ )
| DB_Cycler.bTrigger
The P contact (positive edge detector) ensures REQ is TRUE for exactly one scan. Combine with the BUSY contact latching the trigger, exactly as in the SCL implementation.
Watchdog Tuning and Characteristic Calculations
Set the application watchdog based on three contributions:
- 3.5-character inter-frame gap. At 9600 bit/s with 11 bits per character, this is 11 × (1/9600) × 3.5 = 4.01 ms. At 19200: 2.00 ms.
- Request frame duration. For FC03 reading 10 holding registers: 8 bytes (addr, FC, start, qty, CRC) × 11 / 9600 = 9.17 ms. 20 registers: 9.17 ms. The Modbus payload itself adds one byte per 2 registers.
- Response frame duration. Same as above with up to 252 bytes payload. For 20 registers: (5 + 20×2) × 11 / 9600 = 53.0 ms.
- Library response timeout (RESP_TO). Default 1000 ms. Set higher if your slaves use any internal processing delay (e.g. holding register sourced from a slow A/D).
Reasonable working values:
| Baud | Frame size (request + response) | Char-gap | Recommended RESP_TO | App watchdog |
|---|---|---|---|---|
| 9600 | ~62 ms total | 4 ms | 500 ms | T#2S |
| 19200 | ~31 ms total | 2 ms | 300 ms | T#1.5S |
| 38400 | ~15 ms total | 1 ms | 200 ms | T#1S |
| 115200 | ~5 ms total | 0.4 ms | 100 ms | T#500MS |
Alternative Architectures
When the multi-slave RTU bus is more trouble than it is worth, consider these alternatives before commissioning the cyclic state machine.
Modbus TCP over PROFINET
The S7-1200 CPU has a built-in PROFINET port. Use the MODBUS_PN library (FBs MODBUS_PN, available from V4.4) for Modbus TCP. Each slave is reachable on its own IP and a single port lockup cannot take down the other sessions. Per the MODBUS_PN manual, you can run up to 8 concurrent client sessions; the loss of a slave only affects its own session. See the Siemens MODBUS_PN manual in the TIA Portal Help → Information System → Communication → MODBUS.
S7 Communication over Ethernet
For purely Siemens masters and slaves, S7 PUT/GET over Ethernet is more deterministic and survives individual node loss with built-in timeouts (TSAP-based). It avoids the Modbus state machine entirely. The CPU-to-CPU direction is PG/PC and S7 routing → Permitted with PUT/GET in the CPU properties.
ET 200SP serial module
For new installations, the CM PTP (6ES7137-6AA00-0BA0) in an ET 200SP head station with a PROFINET connection back to the master CPU offloads the serial work to a distributed I/O device. The master CPU programs it through standard process-image I/O, isolating the bus from any application-task timing issues.
Multiple MB_MASTER instances on separate CM modules
If you must stay on Modbus RTU but cannot tolerate a single point of failure, mount two CM 1241 modules in the master CPU, assign one to half the slaves, and run two independent FB_ModbusCycler instances. The modules are galvanically isolated from each other, so a failed bus on one channel does not affect the other. The cost is one extra slot and a separate RS-485 run.
Diagnostic & Verification Procedure
Walk through this sequence before declaring the issue closed:
- Power all slaves and confirm
Master.DONEpulses on every poll. Use a watch table on the online S7-1200;Master.DONEshould be TRUE once per cycle per slave. - Force one slave's RS-485 terminal block to be unplugged while online. The cycler should report
SlaveResults[i] = 16#0E02for that slot only, andMaster.BUSYshould clear within PerSlaveTimeout milliseconds. All other slaves should continue to return16#0000. - Reconnect the slave. The next cycle that targets it should produce a normal
DONEpulse.SlaveResults[i]reverts to 0x0000. - Pull a single wire (A+ or B-). The slave will generate CRC errors (
16#0E01). The cycler behaviour should be identical to the offline case — the watchdog fires, the slave is flagged, the others continue. - Short A+ to B-. After the library's RESP_TO elapses, the master will see a sustained mark/space and may report
16#0E03(framing) or a continuous busy depending on the CM 1241 revision. This is a physical-layer fault and must be repaired, not worked around. - Capture the bus with a USB-to-RS485 analyser (FTDI FT232-based) and confirm: (a) only one request per cycle per slave; (b) inter-frame gap is at least 3.5 character times; (c) no duplicate requests caused by a latched REQ.
Recommended online watch table tags to expose for maintenance:
-
DB_Cycler.sState— numeric, should cycle 0 → 10 → 20 → 30 → 0. -
DB_Cycler.CurrentSlave— address being polled. -
DB_Cycler.SlaveResults[1..7]— per-slave status word. 0x0000 healthy, 0x0E02 timeout, 0x0E01 CRC, etc. -
DB_ModbusMaster.Master.BUSY— should be TRUE only during transactions, never stuck. -
DB_ModbusMaster.Master.ERRORandSTATUS— one-cycle pulse; record in HMI tag log for trending.
Extended Considerations
CM 1241 hardware revisions and firmware. The original 6ES7241-1CH30-1XB0 (FW ≤ V1.0) has known issues with 115200 bit/s and a maximum of 16 slaves per port due to internal buffer sizes. The current 6ES7241-1CH32-0XB0 (FW ≥ V2.0) supports up to 32 slaves reliably. For a 7-slave bus at 9600 bit/s on the older module, you may still benefit from a state machine but the lockup will resolve in <1 s even without one.
Electrical noise. A floating shield or missing termination resistor turns a healthy bus into one that intermittently reports 0x0E01 (CRC) on certain slaves. The state machine handles this gracefully, but the root cause is hardware: install 120 Ω at both ends, ground the shield at one point only, and route the bus away from VFD output cables and contactor coils.
Firmware version matrix. The MB_MASTER FB exists in three versions in the Siemens library. The V3.0+ implementation (shipped with TIA Portal V15 and later) exposes additional error codes (0x80C8, 0x80D0) related to busy port access. Always use the V3.0 or higher variant on a multi-slave polling application; the V1.x variant from TIA V12 SP1 is single-master and prone to the lockup described in this article.
CPU scan time impact. The state machine adds < 0.5 ms per cycle at 1 ms OB1 scan. With 7 slaves and 20 ms inter-poll delay, the full cycle is ~150 ms. This is well within the budget for a 100 ms process loop and is irrelevant on a typical 1214C scan of 3–5 ms.
Using a CP 1242-7 GPRS or CP 1243-1 for remote Modbus. If the "offline slave" is in fact a remote site that has lost its WAN link, the state machine still works — the local master CPU sees the TCP socket close and the same watchdog path applies. The CP-specific diagnostic block provides additional event codes (0x8301, 0x8302) that can be cross-referenced with the slave's IP address.
FAQ
Why does MB_MASTER stay BUSY forever after a slave goes offline?
Because the REQ bit is being held high in the application logic, or because RESP_TO is set longer than the application watchdog. The block returns to idle only when the next REQ rising edge is presented and the port is no longer busy. If the application never lowers REQ, the port stays locked. Use a one-scan pulse on REQ and a per-slave TON to bound the wait.
Can I run two MB_MASTER instances on the same CM 1241 port?
No. The CM 1241 RS485 port is half-duplex; a single transaction owns the port and a second MB_MASTER will immediately return ERROR with STATUS = 0x80C8 ("Resource busy"). Use one MB_MASTER FB and cycle the MB_ADDR input via a state machine, as shown in this article.
What is the difference between MB_MASTER and MODBUS_MASTER / MODBUS_PN?
MB_MASTER is the legacy FB (FB 1217) used with the CM 1241 and MB_COMM_LOAD. MODBUS_MASTER / MODBUS_PN is the newer instruction set (TIA V15+) that uses MODBUS_LOAD and is part of the MODBUS_PN library; it supports Modbus TCP and is recommended for new projects on PROFINET-capable CPUs. The two are not interchangeable; the legacy FB is still required for serial RTU.
How do I detect which specific slave is offline?
Inspect the STATUS word on the falling edge of ERROR, then read the cycler's CurrentSlave output. Store the result in the SlaveResults array indexed by your slot number. A non-zero result with the high byte 0x0E indicates a transport-layer problem; a value with the high byte 0x00 is a Modbus exception returned by the slave itself.
What RESP_TO value should I use with a CM 1241 at 9600 bit/s?
Start with 1000 ms (RESP_TO is in milliseconds). The value is the time the master waits for the first response byte; for 9600 bit/s with 20 holding registers, the full response is about 50 ms, so 1000 ms gives 20× margin. If slaves can stall internally (e.g. A/D conversion), raise RESP_TO to 2000–3000 ms and set the application PerSlaveTimeout to RESP_TO + 1000 ms.