S7-1200 Modbus FC23 Mastervolt Charger: Read/Write Workaround

David Krause14 min read
S7-1200SiemensTechnical Reference
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

S7-1200 Modbus FC23 Mastervolt Charger: Read/Write Workaround

The Siemens S7-1200 PLC cannot issue Modbus function code 23 (Read/Write Multiple Registers, 0x17) natively, yet Mastervolt battery chargers expose a significant portion of their telemetry, configuration, and control registers through this combined transaction over a MasterBus-to-Modbus converter. This reference documents the underlying problem, the converter topology, the FC23 payload that Mastervolt produces, and three field-proven workarounds that keep the project on a S7-1200 CPU without changing the PLC family.

1. Problem Overview

A standard engineering scenario pairs a Siemens SIMATIC S7-1200 CPU 1214C DC/DC/DC with a CM 1241 RS422/RS485 communications module (Siemens part number 6ES7241-1CH32-0XB0) and reads/writes several Mastervolt Mass Combi, ChargeMaster, or CombiMaster battery chargers. The chargers do not expose a raw Modbus RTU interface; they speak MasterBus, a CAN-based proprietary bus. A Mastervolt MasterBus-Modbus converter translates MasterBus frames into Modbus RTU registers and back again.

The complication is that the Mastervolt side of this converter implements several combined read/write services using Modbus function code 23 (0x17) with custom IDB/IDAL addressing tags. The S7-1200 Modbus RTU library (the MB_COMM_LOAD and MB_MASTER instructions documented in the TIA Portal help) only supports the following function codes in the standard instruction set:

FC Name S7-1200 MB_MASTER
01 (0x01) Read Coils Supported
02 (0x02) Read Discrete Inputs Supported
03 (0x03) Read Holding Registers Supported
04 (0x04) Read Input Registers Supported
05 (0x05) Write Single Coil Supported
06 (0x06) Write Single Register Supported
15 (0x0F) Write Multiple Coils Supported
16 (0x10) Write Multiple Registers Supported
23 (0x17) Read/Write Multiple Registers Not supported

FC23 is therefore the obstacle. It is not a "missing feature" in the sense of a bug: the S7-1200 Modbus library was designed against the classic Modbus RTU application layer and FC23 is an optional extension defined in Modbus RFC extension. Any project that requires it must either use a workaround on the S7-1200 or insert a translation stage in front of the PLC.

Important: The TIA Portal V21 Modbus RTU documentation (referenced below) is explicit: "The Modbus_Master instruction communicates as Modbus master via a port configured by the Modbus_Comm_Load instruction." The instruction's MODE input only accepts the integer codes 0, 1, 2, 3, 4, 5, 6, 15, and 16. A MODE of 23 returns STATUS = 0x80C8 (illegal function) on the wire.

2. Hardware Topology

The complete bus layout is shown below. Each component, its order number, and its role is called out so the same setup can be replicated in cabinet design.

Position Component Order / Part Number Function
A S7-1200 CPU 1214C DC/DC/DC 6ES7214-1AG40-0XB0 PLC, executes Modbus master
B CM 1241 RS422/RS485 6ES7241-1CH32-0XB0 Serial port, RS485 2-wire to converter
C Mastervolt MasterBus-Modbus converter 77030800 (Mastervolt) Translates MasterBus <-> Modbus RTU
D1..Dn Mastervolt chargers (Mass Combi, ChargeMaster, CombiMaster) Various (e.g. ChargeMaster 12/35-3, 44010350) Slaves on MasterBus CAN, exposed as Modbus registers
E MasterBus terminator Mastervolt 77031500 120 Ω CAN terminator, both ends of bus

2.1 RS485 Cabling Rules

  • Use a twisted pair, characteristic impedance 120 Ω, e.g. Belden 3106A or Lapp ETHERLINE 2-pair.
  • Place the cable shield on the converter side only, bonded to PE through a 10 nF / 1 MΩ parallel network to bleed RF without passing 50/60 Hz fault current.
  • Maximum bus length at 19200 bit/s: 1200 m. Mastervolt converters ship with a fixed baud default of 19200 8N1 when ordered for Modbus RTU operation.
  • Connect pin 8 (T/R+, A) on the CM 1241 to A on the converter; pin 3/4 (T/R-, B) to B. The CM 1241 has no internal termination; insert a 120 Ω resistor across A/B at each physical end of the RS485 segment.

3. The MasterBus / Modbus Converter

MasterBus is a CAN 2.0B based proprietary bus running at 250 kbit/s with 11-bit identifiers. Each MasterBus device has a unique Device ID (1..247) that becomes its Modbus slave address once the Mastervolt converter has been configured. The converter acts as a transparent bilingual gateway: every MasterBus message produced by a charger (state, alarms, configuration, telemetry) is mirrored into a set of Modbus holding registers on the converter's RTU side, and writes arriving over Modbus are wrapped back into MasterBus messages and forwarded to the addressed device.

Mastervolt distributes an open register map for each device family. For example, the ChargeMaster 12/35-3 exposes the following illustrative block (verify against the current datasheet for the specific charger you are using):

Modbus Register (0-based) IDB Tag Access Meaning Type
0x0001 IDB.ChargeState R 0=Off, 1=Bulk, 2=Absorption, 3=Float, 4=Storage UINT16
0x0002 IDB.BatteryVoltage R Pack V × 100 UINT16
0x0003 IDB.ChargeCurrent R Pack A × 10 UINT16
0x0004 IDB.TempSensor R °C + 40 offset INT16
0x0010 IDB.MaxChargeCurrent R/W A × 10 UINT16
0x0011 IDB.ChargeMode R/W 0=Off, 1=On, 2=Auto UINT16
0x0012 IDAL.SetBulkVoltage R/W V × 100 UINT16
0x0013 IDAL.SetFloatVoltage R/W V × 100 UINT16

The IDAL tags are the configuration block: they must be read, modified, and written back. On a full MasterBus session the converter combines the read of a status block and the write of a configuration block into a single FC23 transaction to keep the configuration atomic. That is the function code the S7-1200 cannot issue.

4. Decoding FC23 (Read/Write Multiple Registers, 0x17)

The wire frame for FC23 on Modbus RTU looks like this:

Byte Field Notes
0 Slave address (1..247) MasterBus device ID
1 Function code 0x17 Read/Write Multiple Registers
2..3 Read starting address High / Low
4..5 Quantity of read registers (N) 0x0001..0x007D
6..7 Write starting address High / Low
8..9 Quantity of write registers (M) 0x0001..0x007D
10..11 Write byte count (2×M)
12..(12+2M-1) Write register values High / Low per register
.. CRC16 (low, high) Modbus RTU CRC, polynomial 0xA001

The response returns 2 × N bytes of read register data followed by CRC. The atomicity property (one transaction, one MasterBus round-trip) is what makes FC23 attractive to the Mastervolt gateway: writing a new absorption voltage and reading back the state machine flags in the same frame keeps the converter's internal state consistent.

5. Why the S7-1200 Cannot Issue FC23

The TIA Portal V21 Modbus_Master instruction documentation lists only the function codes 01, 02, 03, 04, 05, 06, 15, and 16. Internally the instruction is implemented as a function block in the Modbus library that issues the request via the protocol stack on the CM/CP. The MODE input is a BYTE value validated against this set; any other value, including 23, is rejected before the request is encoded.

Two practical consequences follow:

  1. No firmware or library option on the CM 1241 can be enabled to add FC23. Newer CPUs (S7-1500 and S7-1200 G2) ship with the same library scope and likewise do not add FC23 in standard firmware.
  2. You cannot free-program a custom FC23 frame from the S7-1200 using the standard blocks. Free serial protocols (USS, ASCII, 3964R) do not give you arbitrary Modbus PDU encoding: they require you to build the request and decode the reply byte-by-byte, and the CM 1241's SEND_P2P/RECV_P2P instructions also enforce inter-character and inter-frame timing that complicates Modbus CRC handling.

6. Workaround Architecture: Split the FC23

The lowest-risk fix is to decompose every FC23 transaction into a FC06 (or FC16) write followed by a FC03 read. The Mastervolt converter accepts these as independent operations. The only cost is the loss of the "one atomic transaction" property: between the write and the read, a second master on the same bus, or a charger event, could change the value. For SCADA monitoring with a single master on a slow (1-2 s) poll, this is acceptable.

6.1 Logical Flow

The PLC code follows this state machine on every periodic OB (e.g. OB1 cyclic, 100 ms):

  1. Initialize the RS485 port once in OB100 (cold restart) using MB_COMM_LOAD with mode = RTU, baud = 19200, parity = 8N1, flow control = none.
  2. Cycle through chargers in a ring counter. For each charger, alternate between a write phase and a read phase.
  3. Write phase: issue MB_MASTER with MODE = 6 (Write Single Register) or MODE = 16 (Write Multiple Registers), starting at the IDAL address, with the new configuration values from a data block.
  4. Read phase: issue MB_MASTER with MODE = 3 (Read Holding Registers), starting at the IDB address, into a buffer data block.
  5. Insert a configurable inter-transaction delay (default 50 ms) to let the converter complete the MasterBus write before the read pulls fresh data.
  6. Repeat on the next OB1 cycle until all chargers have been serviced, then loop back.

6.2 TIA Portal SCL Code Skeleton

Use two instance DBs from the Modbus library: one for MB_COMM_LOAD, one for MB_MASTER. The cyclic control is a small FB that owns the state machine.

// FB_MastervoltPoll - cyclic Modbus RTU driver
// Inputs: i_b_SlaveAddr (1..247)
//         i_i_StartAddrWrite, i_i_StartAddrRead
//         i_i_QuantityWrite, i_i_QuantityRead
//         i_w_Payload[1..32]  // values to write
// Outputs: o_w_Result[1..32] // values read
//          o_b_Done, o_b_Error, o_w_Status

CASE #e_State OF
    0:  // IDLE
        #e_State := 10;
    10: // issue WRITE
        #MB_MASTER_Instance.MODE      := 16;          // FC16 = Write Multiple
        #MB_MASTER_Instance.DATA_ADDR := 400001 + #i_i_StartAddrWrite;
        #MB_MASTER_Instance.DATA_LEN  := #i_i_QuantityWrite;
        #MB_MASTER_Instance.DATA_PTR  := #Payload_DB;
        #MB_MASTER_Instance.REQ      := TRUE;
        IF #MB_MASTER_Instance.DONE THEN
            #MB_MASTER_Instance.REQ := FALSE;
            #e_State := 20;
            #t_Delay(IN := FALSE);
        ELSIF #MB_MASTER_Instance.ERROR THEN
            #o_w_Status := #MB_MASTER_Instance.STATUS;
            #o_b_Error  := TRUE;
            #e_State    := 0;
        END_IF;
    20: // inter-transaction delay (50 ms)
        #t_Delay(IN := TRUE, PT := T#50ms);
        IF #t_Delay.Q THEN
            #e_State := 30;
        END_IF;
    30: // issue READ
        #MB_MASTER_Instance.MODE      := 3;           // FC03 = Read Holding
        #MB_MASTER_Instance.DATA_ADDR := 400001 + #i_i_StartAddrRead;
        #MB_MASTER_Instance.DATA_LEN  := #i_i_QuantityRead;
        #MB_MASTER_Instance.DATA_PTR  := #Result_DB;
        #MB_MASTER_Instance.REQ      := TRUE;
        IF #MB_MASTER_Instance.DONE THEN
            #MB_MASTER_Instance.REQ := FALSE;
            #o_b_Done := TRUE;
            #e_State  := 0;
        ELSIF #MB_MASTER_Instance.ERROR THEN
            #o_w_Status := #MB_MASTER_Instance.STATUS;
            #o_b_Error  := TRUE;
            #e_State    := 0;
        END_IF;
END_CASE;

6.3 DATA_ADDR Encoding for MB_MASTER

The S7-1200 Modbus library expects the Modicon-style 5-/6-digit base-1 address (400001 for holding register 0, 300001 for input register 0, 100001 for coil 0, 000001 for discrete 0). For Mastervolt holding registers the engineering address 0x0001 is therefore passed as 400001 + 0 = 400001 in the library. Adjust the offset to the actual address list you derived from the Mastervolt map.

7. Workaround B: External Modbus Gateway That Speaks FC23

If atomicity is a hard requirement (for example because the SCADA simultaneously writes the absorption voltage and reads the state machine and you cannot tolerate the value rolling back), insert an external Modbus TCP/RTU gateway that exposes the chargers' full FC23 register map to the S7-1200 as separate FC03 and FC16 transactions. The gateway then reassembles them into FC23 toward the Mastervolt converter. Devices that can be configured for this include the HMS Anybus X-gateway Modbus TCP to Modbus RTU and the Red Lion CR3000 in custom-protocol mode. Configure the gateway's IDB/IDAL reassembly table to match the Mastervolt register map; the S7-1200 continues to issue plain FC03/FC16 and never knows FC23 is in play.

8. Workaround C: Front-End the S7-1200 With a S7-1500 or Third-Party Bridge

If a S7-1500 CPU (or an ET 200SP CPU) is acceptable as a bridging controller on the same subnet, it can run a custom FC23 implementation in its SCL/STRUCT, since the S7-1500's higher-performance serial point-to-point blocks give finer control over inter-frame timing and PDU construction. That bridge then publishes the charger data to the S7-1200 over PROFINET or Modbus TCP. This is the cleanest solution if your project is open to a small hardware change.

9. Timing and Performance Budget

At 19200 bit/s, one byte is 520.8 µs. A typical FC16 of 8 registers is approximately 11 + (8 × 2 + 9) = 36 bytes (request + response), so 36 × 10 / 19200 = 18.75 ms wire time. A FC03 of 16 registers is about 53 bytes, i.e. 27.6 ms. The inter-transaction delay adds 50 ms, the converter's own processing adds 30..80 ms. Therefore a single charger write-then-read cycle takes about 130..180 ms. With 8 chargers polled sequentially on a 1 s period budget, each gets 125 ms - tight but achievable. Drop the poll to 2 s for headroom, or move to a faster baud (115200 bit/s, supported by the converter with re-configuration) to halve the cycle.

10. Verification and Commissioning Steps

  1. Bring up the RS485 link between CM 1241 and the Mastervolt converter with no chargers connected. Use a Modbus RTU scanner (e.g. a laptop with Modbus Poll tool in read-only mode) to confirm that the converter responds to FC03 reads of registers 0x0001..0x0004 and returns sane default values.
  2. Connect one charger to MasterBus, terminate both ends, and power up. Confirm the charger appears with its configured Modbus slave ID (factory default 1; re-assign via the converter's web UI or DIP switch if you have multiple chargers).
  3. In TIA Portal, run the FB_MastervoltPoll instance online. Watch MB_MASTER.DONE and MB_MASTER.ERROR for each transaction. Common status codes:
STATUS (hex) Meaning Likely Cause
0x0000 OK Success
0x80C8 Illegal function Slave does not support the FC; FC23 is the usual cause
0x80C9 Illegal data address Address not in converter map; check IDB/IDAL register list
0x80D1 CRC error Wiring, termination, or baud mismatch
0x80D2 Timeout Slave not on bus, wrong slave ID, or no inter-frame delay
0x80D8 Parity / framing Baud or parity mismatch (converter default is 8N1)
  1. Force a known write (e.g. IDAL.SetBulkVoltage = 14.40 V -> 1440) and verify the new value is held by the charger. Then power-cycle the charger and re-read: the value should persist if it is an IDAL (non-volatile) tag. IDB tags (volatile) revert on power-up.
  2. Add chargers one at a time. Watch the cumulative poll time in a trace to confirm it stays inside the OB1 budget. If a cycle overruns, increase the OB1 period or reduce the number of polled registers per charger.

11. Diagnostic Checklist

Symptom First Check Second Check
No response from any charger Converter powered, RS485 A/B not swapped Slave address 1..247 in the project, baud 19200 8N1
STATUS 0x80D2 on first poll only Inter-frame delay too short (3.5 char times ~ 2 ms) Converter's silence timer; many converters need 10 ms minimum
STATUS 0x80C9 on write of IDAL tag Tag is read-only at that address Verify against the Mastervolt datasheet for that product family
Values change in PLC but charger ignores them MasterBus cable inversion (CAN-H / CAN-L swapped) Charger is in remote control disable; enable via front panel
Charger state reads back 0xFFFE Charger is off-line on MasterBus Check terminator and CAN wiring

12. Recommended Pattern for New Projects

For new deployments where the design has not yet been frozen, two changes remove the FC23 pain entirely:

  1. Ask Mastervolt to put the converter in legacy mode (when available on the firmware you ordered) where the device exposes all IDB and IDAL tags as separate FC03-readable and FC16-writable registers, so the S7-1200 never needs FC23.
  2. If a new-build is acceptable, replace the MasterBus converter with a Modbus TCP variant that exposes the same register map over Modbus TCP. The S7-1200's MB_CLIENT instruction supports FC03 and FC16 natively over TCP and the timing is much easier to manage than RTU. The CM 1241 RS422/RS485 is no longer required; use the CPU's PROFINET port instead.
Safety note: Battery charging state and limits are safety-relevant. Never write IDAL.SetBulkVoltage or IDAL.SetFloatVoltage from a PLC without an operator confirmation, current-limit clamping, and a watchdog that reverts to the last known good value on communication loss. Mastervolt chargers treat an out-of-range voltage setpoint as a hardware fault condition.

13. Frequently Asked Questions

Does any firmware version of the S7-1200 support Modbus FC23?

No. The S7-1200 Modbus RTU library shipped with all firmware versions up to and including the G2 generation supports only function codes 01, 02, 03, 04, 05, 06, 15, and 16. The CM 1241 (order number 6ES7241-1CH32-0XB0) does not add FC23. Refer to the TIA Portal V21 Modbus_Master instruction documentation for the official list of supported function codes.

Can I split a FC23 transaction into a FC16 followed by a FC03 on the S7-1200?

Yes. Issue MB_MASTER with MODE = 16 (Write Multiple Registers) for the IDAL block, wait at least 50 ms for the converter to forward the write to the charger on MasterBus, then issue MB_MASTER with MODE = 3 (Read Holding Registers) for the IDB block. The only loss is the atomicity of the original combined transaction; for SCADA polling with a single master this is normally acceptable.

What is the default serial configuration of the Mastervolt MasterBus-Modbus converter?

The factory default is 19200 bit/s, 8 data bits, no parity, 1 stop bit (8N1), Modbus RTU. Slave address is DIP-switch selectable or set via the converter's web interface. Re-verify on commissioning with a Modbus RTU master tool before connecting the S7-1200, because a baud mismatch produces STATUS 0x80D8 (framing) on the S7-1200 side and is the most common first-day failure.

How long does one full poll cycle take for 8 chargers at 19200 bit/s?

Each write+read pair takes roughly 130 to 180 ms including inter-transaction delay and converter processing. Eight chargers polled sequentially therefore need about 1.0 to 1.5 seconds. If you need a 1 s cycle, reduce the registers per charger, raise the baud to 115200 bit/s (re-configure the converter), or move to Modbus TCP.

Is there a way to make the S7-1200 issue raw Modbus FC23 with free-protocol blocks?

Not reliably. The SEND_P2P and RCV_P2P free-protocol instructions on the CM 1241 give you control over bytes on the wire, but you must also enforce Modbus RTU inter-character and inter-frame timing (1.5 / 3.5 character times) and compute the CRC16 (polynomial 0xA001) per request and validate it on every reply. The complexity and the lack of automatic Modbus exception decoding make this approach less maintainable than splitting the transaction, and it is not officially supported by Siemens for Modbus RTU use cases.

Back to blog