Resolving S7-1200 MB_MASTER Busy State on Offline Modbus RTU

David Krause18 min read
S7-1200SiemensTroubleshooting
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

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:

Master CPU S7-1214C/DC/DC FW 4.4 CM 1241 RS485 6ES7241-1CH32-0XB0 A+ B- GND 120 Ω term Slave 1 S7-1200 Slave 2 S7-1200 Slave 3 S7-1200 Slave 4 S7-1200 Slave 5 S7-1200 Slave 6 OFFLINE RS-485 trunk 120 Ω

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) or CB 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_SLAVE from the same library; configure the slave address in the MB_SLAVE instance DB.
  • TIA Portal V15.1 or later. The legacy MB_COMM_LOAD / MB_MASTER pair 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.
Important: 0x0E02 is the expected status when a slave drops offline. If you are seeing 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":

  1. REQ held continuously. The most common cause. If a programmer latches REQ = TRUE until DONE arrives, the very first BUSY rising edge is fine — but the instant a slave is offline, DONE never sets, the latched REQ stays 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.
  2. 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_ADDR simply rewrites an input the engine has already captured. The block must return to idle (BUSY = FALSE) before a new transaction can begin.
  3. 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 produce ERROR + STATUS = 0x0E02 in a few hundred milliseconds and clear BUSY on 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 the BUSY lockup 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.

IDLE Wait for cycle tick SELECT SLAVE i := (i+1) MOD N ARM REQUEST REQ := TRUE one scan WAIT BUSY rising TRANSACT Watchdog running DONE / ERROR Store status, i := i+1 no TIMEOUT REQ := FALSE, log 0x0E02 yes back to IDLE

Key design rules:

  • Generate REQ as a one-scan pulse with rising-edge detection. Do not latch it.
  • Update MB_ADDR only when BUSY = FALSE and 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 TON with 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

  1. 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.
  2. 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.
  3. 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) and MB_MASTER (FB 1217) into the project.
  4. Create the configuration DB. Add a global DB, e.g. DB_CommConfig, with a single tag MB_Load_DB of type MB_COMM_LOAD. The REQ input is normally TRUE for the lifetime of the CPU; MODE = 0 selects the legacy MB_MASTER protocol. 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.
  5. Create the master instance DB. Add a global DB, e.g. DB_ModbusMaster, and drop one MB_MASTER instance named Master into it. The DB must be non-optimised (remove Optimised block access on the DB's attributes) because the DATA_PTR uses absolute addressing.
  6. Create the data image DB. Add DB_SlaveData with one array per slave, e.g. Slave1 : ARRAY[0..19] OF WORD. Point the DATA_PTR at a slice of this DB for each transaction.
  7. 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 DB DB_Cycler.
  8. Call the state machine in OB1. CALL FB_ModbusCycler, DB_Cycler ;. Set Enable TRUE, supply the list of slave addresses as an input array.
  9. 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:

  1. 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.
  2. 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.
  3. Response frame duration. Same as above with up to 252 bytes payload. For 20 registers: (5 + 20×2) × 11 / 9600 = 53.0 ms.
  4. 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
Note: The library's RESP_TO is the time the master waits after transmitting before declaring the slave silent. The application PerSlaveTimeout in the cycler FB should always be RESP_TO + 1000 ms at minimum. Never set RESP_TO below the inter-character timeout or the master will see ghost errors on the first byte of a valid response.

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:

  1. Power all slaves and confirm Master.DONE pulses on every poll. Use a watch table on the online S7-1200; Master.DONE should be TRUE once per cycle per slave.
  2. Force one slave's RS-485 terminal block to be unplugged while online. The cycler should report SlaveResults[i] = 16#0E02 for that slot only, and Master.BUSY should clear within PerSlaveTimeout milliseconds. All other slaves should continue to return 16#0000.
  3. Reconnect the slave. The next cycle that targets it should produce a normal DONE pulse. SlaveResults[i] reverts to 0x0000.
  4. 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.
  5. 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.
  6. 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.ERROR and STATUS — 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.

Back to blog