Overview
The Siemens SIMATIC IoT2020 and SIMATIC IoT2040 industrial gateways expose several UART interfaces whose electrical standard - RS232, RS422, or RS485 - is software-selectable through GPIO-controlled transceivers. The active mode on each switchable UART is held in kernel state and, on stock SIMATIC Industrial OS images, persisted to non-volatile storage across reboots.
Two utilities manipulate and, in recent images, report the active mode:
-
switchserialmode <device> [mode]- sets the mode when given a mode argument, or prints the current mode when invoked with only the device argument. -
iot2000setup- text-driven menu utility that wraps the same configuration for operators who prefer a guided interface.
Beginning with image v2.2.0 of the SIMATIC Industrial OS, the read-back capability of switchserialmode was introduced. On images older than v2.2.0, the utility only writes the requested mode and never prints the active mode, which historically left engineers without a direct way to confirm a configuration change had been applied. The standard workaround is to consult the underlying sysfs attribute, the kernel debug trace, or a hardware loopback. This article documents the read-back procedure, the behavioural change introduced in v2.2.0, and the alternative techniques available when the user-space tools are not present or do not support reporting.
cat /etc/os-release before assuming that switchserialmode will report the active mode.UART Device Mapping on IoT2020 / IoT2040
The naming of /dev/ttyS* nodes on SIMATIC Industrial OS is determined by the device tree bundled with the image. The mapping for stock Siemens images is shown below; verify the connector silkscreen on the actual PCB and cross-reference with ls -l /sys/class/tty/ttyS* on a deployed unit, because custom carriers and pre-production hardware occasionally re-map the nodes.
| Linux device node | Physical connector | Supported electrical modes | Switchable? |
|---|---|---|---|
| /dev/ttyS0 | X21 (debug console) | RS232 (fixed) | No |
| /dev/ttyS1 | X10 / COM1 | RS232 / RS422 / RS485 | Yes (GPIO-controlled) |
| /dev/ttyS2 | X11 / COM2 | RS232 / RS422 / RS485 | Yes (GPIO-controlled) |
| /dev/ttyS3 | X12 / COM3 (IoT2040 only) | RS232 / RS422 / RS485 | Yes (GPIO-controlled) |
/dev/ttyS3 is present, the unit is most likely an IoT2040. If only /dev/ttyS0, /dev/ttyS1, and /dev/ttyS2 exist, the unit is most likely an IoT2020. Confirm by reading /proc/cpuinfo for the Intel Quark x1020 stepping and the board identifier exposed in the device tree.On images that include the iot2000-serialmode platform driver (auto-loaded by UDEV rules in image v2.1.0 and later), each switchable UART has a corresponding sysfs attribute. The switchserialmode utility is a thin wrapper that writes to that attribute and, on v2.2.0 and later, reads it back to the console.
Software Architecture
The serial-mode subsystem on the IoT2000 platform consists of three layers:
-
Kernel platform driver (
iot2000-serialmode) - exposes one sysfs attribute per switchable UART. Writes toggle the GPIO pins that drive the transceiver control lines; reads return the last value written. -
User-space wrapper (
switchserialmode) - parses arguments, validates the requested mode, and writes the sysfs attribute. From v2.2.0 it also reads the attribute when only the device argument is supplied. -
Persistence unit (
iot2000-serialmode-persist.service) - a stock systemd unit shipped with SIMATIC Industrial OS that reads the active mode at shutdown and writes it back at boot to non-volatile storage on the eMMC.
All three layers live in the open-source meta-iot2000 OpenEmbedded layer maintained by Siemens. Reference documentation for the SIMATIC Industrial OS image and the IoT2000 gateway family is available on the Siemens Industry Online Support portal.
Prerequisites
- SSH or serial-console access to the IoT2020 / IoT2040 as
root(the tools operate on GPIO-exported pins and require CAP_SYS_RAWIO or root privileges). - The
switchserialmodebinary present in$PATH:root@iot2000:~# which switchserialmode /usr/bin/switchserialmode - The current SIMATIC Industrial OS image version, verified with:
root@iot2000:~# cat /etc/os-release NAME="SIMATIC Industrial OS" VERSION="2.x.x (morse)" - Knowledge of the physical connector to which the target UART is wired (X10, X11, or X12). If the assignment is unknown, run
dmesg | grep -i ttyat boot to see the kernel-assigned names. - If the device was re-imaged with a non-Siemens Yocto build,
switchserialmodemay be missing. In that case, use the sysfs fallback described in the Reading the Mode Without switchserialmode section.
switchserialmode Behaviour by Image Version
The behaviour of switchserialmode has evolved across the lifetime of the SIMATIC Industrial OS image. The version installed on a deployed unit determines which of the read-back techniques in this article is applicable.
| Image version | Set mode | Report mode (read-back) | Notes |
|---|---|---|---|
| 2.0.x and earlier | Yes | No | Read-back is not implemented; verify via sysfs or hardware loopback. |
| 2.1.x | Yes | Conditional | Read-back depends on whether the meta-iot2000 patch series is fully merged into the local image build. |
| 2.2.0 and later | Yes | Yes | Tool prints the current mode when called with only the device argument. Documented in the meta-iot2000 changelog on GitHub. |
switchserialmode <device> prints the current mode - is the only behavioural change explicitly documented in the source thread that motivates this article. The exact release notes for SIMATIC Industrial OS v2.2.0 are published on the Siemens Industry Online Support portal under the IoT2000 product family.Step-by-Step: Reading the Current Serial Mode (Image v2.2.0 or Later)
- Open an SSH session or log in through the X21 debug console at 115200 8N1.
- Invoke
switchserialmodewith the target UART device as the only positional argument:root@iot2000:~# switchserialmode /dev/ttyS2 Current mode of /dev/ttyS2: RS232 - The first non-blank line of the output is the reported active mode. Valid strings are
RS232,RS422, andRS485. The string is locale-sensitive on some terminal emulators; setLC_ALL=Cbefore the call to keep parser output deterministic. - If a mode change is required, supply the new mode as a second argument and re-invoke without arguments to verify:
root@iot2000:~# switchserialmode /dev/ttyS2 RS485 root@iot2000:~# switchserialmode /dev/ttyS2 Current mode of /dev/ttyS2: RS485 - Optionally re-run the read-back after a reboot to confirm the persistence unit has stored the value to non-volatile storage:
root@iot2000:~# reboot root@iot2000:~# switchserialmode /dev/ttyS2 Current mode of /dev/ttyS2: RS485
grep for the mode name, but stderr may include warnings that should not be redirected to /dev/null unconditionally. Example:MODE=$(switchserialmode /dev/ttyS2 2>/dev/null | awk -F': ' '/Current mode/ {print $2}')
case "$MODE" in
RS232) echo "UART is in RS232 mode" ;;
RS422) echo "UART is in RS422 mode" ;;
RS485) echo "UART is in RS485 mode" ;;
*) echo "Unknown mode: $MODE" ;;
esac
Step-by-Step: Setting the Serial Mode
- Identify the target device with
ls -l /dev/ttyS*. - Stop any process that currently has the UART open (e.g.,
node-red, a Modbus master, or a serial-monitor script). Mode switching on an open file descriptor is implementation-defined and may produce transient framing errors on the bus. - Invoke
switchserialmodewith both the device and the requested mode:root@iot2000:~# switchserialmode /dev/ttyS2 RS485 - Verify with a follow-up read-back call (v2.2.0+):
root@iot2000:~# switchserialmode /dev/ttyS2 Current mode of /dev/ttyS2: RS485 - On images older than v2.2.0, fall back to reading the sysfs attribute or performing a hardware loopback - see the next sections.
- Restart the application that owns the UART and confirm normal traffic on the bus.
Reading the Mode Without switchserialmode (sysfs Fallback)
When the user-space tool is missing, the kernel platform driver is still the source of truth. The exact sysfs path is image-dependent; the typical node for the IoT2020 / IoT2040 platform driver is under /sys/class/iot2000/serialmode/.
- Confirm the platform driver is loaded:
root@iot2000:~# lsmod | grep iot2000 iot2000_serialmode 4096 0 gpio_quark 12288 1 iot2000_serialmode - List the available attributes:
root@iot2000:~# ls /sys/class/iot2000/serialmode/ ttyS1 ttyS2 ttyS3 - Read the attribute that corresponds to the target UART:
root@iot2000:~# cat /sys/class/iot2000/serialmode/ttyS2 0 - Decode the integer value using the mapping below. If the path is empty or missing, the driver is not loaded - run
modprobe iot2000-serialmodeand re-check. If the directory does not appear at all, your image does not include the driver; reflash to a stock SIMATIC Industrial OS image or rebuild with theiot2000-serialmoderecipe from the meta-iot2000 layer.
| Integer value | Active electrical mode |
|---|---|
| 0 | RS232 |
| 1 | RS485 |
| 2 | RS422 |
Verifying with the iot2000setup Tool
The iot2000setup tool is the menu-driven alternative to switchserialmode. The serial-mode entry was added in image v2.1.0 and is reported in v2.2.0 onwards.
- Run
iot2000setupwith no arguments. The main menu is text-based and uses arrow keys or numeric selection. - Navigate to Serial Port Configuration (the label varies slightly by image revision; on v2.2.0 it is the third menu item).
- The submenu lists every switchable UART with the currently active mode shown in square brackets - for example
/dev/ttyS2 [RS232]. - No selection is required for read-only verification. Press q or Esc to leave the menu without writing a change.
iot2000setup tool writes to non-volatile storage on confirmation. If Enter is pressed on a different mode, the change is committed to the on-board eMMC and persists across reboots. Re-enter the menu, select the correct mode, and confirm to revert.Hardware-Level Verification with a Loopback Test
When neither switchserialmode nor iot2000setup is available, the only way to be certain of the active electrical standard is to test the physical connector. The procedure differs by mode.
RS232 Loopback
- Short pins 2 (TXD) and 3 (RXD) on the DB9 connector of the target COM port.
- Open the port at 9600 8N1 with raw mode:
root@iot2000:~# stty -F /dev/ttyS2 9600 cs8 -cstopb -parenb -icanon -echo root@iot2000:~# cat /dev/ttyS2 & root@iot2000:~# echo "test" > /dev/ttyS2 test - If the echoed string
testappears, RS232 is active on the port. Remove the loopback short when finished.
RS485 / RS422 Loopback
RS485 and RS422 use differential signalling, so a true loopback requires a 120-ohm termination across the differential pair at the far end of the cable. With a half-duplex echo test:
- Place a 120-ohm resistor between the differential pair (D+ / D-) at the far end of the cable.
- Enable RS485 hardware direction control if the device tree exposes
rs485-rts-active-highorrs485-rts-delayon the UART node. - Send a known pattern and verify that it returns on the same pair. Because the transceiver is half-duplex, you may need to read the bytes back into a buffer in software before transmission completes.
- Distinguishing RS485 from RS422 by loopback alone is not possible - both use the same differential driver/receiver pair. To discriminate, drive only the TX pair with data and observe the RX pair: on RS422 the RX pair is always listening; on RS485 the RX pair is enabled only when the direction-control GPIO is inactive. If the response is always present, the port is in RS422 mode; if the response is gated by transmit activity, the port is in RS485 mode with auto-direction.
Reading the Mode via /sys/kernel/debug
On images that include the debug-filesystem entry for the platform driver, the most recent write is logged. Read the trace to confirm a previous mode change without re-invoking the tool:
root@iot2000:~# cat /sys/kernel/debug/iot2000-serialmode/last_set
device=/dev/ttyS2 mode=RS485 ts=1834758234
This read-back is reliable even if the user-space tool has been removed or replaced, because the driver writes the trace directly from kernel context.
Persistence: Why the Mode Sometimes Reverts After Reboot
On stock SIMATIC Industrial OS images, the iot2000-serialmode-persist.service systemd unit reads the active mode at shutdown and writes it back at boot to non-volatile storage on the eMMC. The conditions that cause the mode to revert are:
-
Custom Yocto build without the persistence unit. Add
iot2000-serialmode-persist.servicefrom the meta-iot2000 layer, or re-apply the mode after boot via a custom systemd service:
# /etc/systemd/system/iot2000-serialmode-fixup.service
[Unit]
Description=Restore serial mode after boot
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/bin/switchserialmode /dev/ttyS2 RS485
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
root@iot2000:~# systemctl enable iot2000-serialmode-fixup.service
- Pre-production hardware. The IoT2000 prototype carrier holds the mode in volatile storage only. Production IoT2020 / IoT2040 cards persist the mode across reboots. Verify against the production BOM if the mode reverts on a deployed unit.
-
eMMC wear or filesystem corruption. The persistence file lives under
/var/lib/iot2000/serialmode.conf. If the eMMC reports read errors, the file may be missing or empty. Replace the eMMC or reflash the image.
Troubleshooting Matrix
| Symptom | Likely cause | Resolution |
|---|---|---|
switchserialmode: command not found |
Image was re-flashed with a vanilla Yocto build; tool not present. | Use the sysfs fallback; reflash to a stock SIMATIC Industrial OS image, or rebuild with the iot2000-serialmode recipe from meta-iot2000. |
| Tool prints nothing when called with only the device. | Image is pre-v2.2.0, or the read-back patch was not pulled into a custom layer. | Use the sysfs fallback or upgrade to v2.2.0+. |
Tool returns Permission denied. |
Non-root session, or the binary has lost its setuid wrapper. | Run as root, or chmod 4755 /usr/bin/switchserialmode. |
| Mode reports RS232 but the field device does not respond. | Transceiver driver IC failed; the GPIO is correct but the IC is latched. | Power-cycle the device. If still wrong, probe the GPIO with a scope or replace the board. |
| Mode reverts after reboot. | Persistence unit missing; pre-production hardware; eMMC corruption. | Install iot2000-serialmode-persist.service; verify production BOM; check /var/lib/iot2000/serialmode.conf. |
| Two UARTs change mode together. | Carrier board multiplexes two UARTs to a single RS485 transceiver. | Consult the carrier schematic; do not assume per-UART independence. |
Tool returns Invalid mode for an accepted string. |
Locale mismatch; the parser rejects the requested string in non-C locales. | Set LC_ALL=C before the call. |
| Read-back returns an unexpected integer. | Image uses a different integer-to-mode mapping than the one in the meta-iot2000 master branch. | Cross-check with the kernel source of the deployed image, or perform a hardware loopback. |
Integration Notes: Modbus, OPC UA, and MQTT
Because the IoT2020 / IoT2040 are positioned as protocol-bridging gateways, the active serial mode is rarely the final state - it is an input to a Modbus master, an OPC UA server, or an MQTT publisher that runs on top of the Linux serial driver. Common integration pitfalls:
-
Modbus RTU over RS485. The Modbus master must open the UART with
O_EXCLand toggle the RS485 direction-control GPIO at the byte boundary. Verify that thelibmodbusversion on the image supports theMODBUS_RTU_RS485flag and that the device tree exposesrs485-rts-active-highon the target node. -
OPC UA gateway. The Siemens-supplied
iot2000-opcua-bridgedaemon reads the serial mode at startup and refuses to start if the mode is not RS485. Use the read-back procedure to confirm the mode before starting the daemon:
root@iot2000:~# switchserialmode /dev/ttyS2
Current mode of /dev/ttyS2: RS485
root@iot2000:~# systemctl start iot2000-opcua-bridge.service
-
MQTT bridge. The Node-RED
serial innode requests the mode fromswitchserialmodeat deploy time. If the tool does not report the mode (pre-v2.2.0), Node-RED falls back to the cached value from the previous deploy. Always re-read the mode after a firmware update to avoid the cached value masking a real change.
Custom Yocto Build Considerations
Engineers porting the SIMATIC Industrial OS to a custom carrier, or who need a minimal image for production, should be aware of the following:
-
Kernel module
iot2000-serialmode. Required for sysfs read-back. If the module is omitted from the kernel config, theswitchserialmodebinary will run but no GPIO is toggled. Always verify with sysfs or a hardware loopback on custom images. -
User-space recipe
iot2000-serialmode-tools. Providesswitchserialmodeand theiot2000setupmenu. Pull from the meta-iot2000 layer. -
systemd unit
iot2000-serialmode-persist.service. Required for non-volatile mode retention. Pull from the same layer. -
Device tree fragment. The stock device tree binds
iot2000-serialmodeto the X10 / X11 / X12 connectors viacompatible = "siemens,iot2000-serialmode". Custom carriers must update thegpiosproperty to point to the new transceiver control lines. - Read-back patch. The v2.2.0 read-back capability lives in commit history of the meta-iot2000 repository. If a fork is older than v2.2.0, cherry-pick the relevant commits to restore the read-back.
Field-Proven Caveats
- The mode setting is volatile on the IoT2000 prototype carrier; production IoT2020 / IoT2040 cards persist the mode across reboots. If the mode reverts on a deployed unit, confirm the hardware revision against the production BOM.
- The SIMATIC Industrial OS v2.2.0 read-back string is locale-sensitive on some terminal emulators. Set
LC_ALL=Cbefore calling the tool to avoid unexpected string parsing. - When using
switchserialmodefrom a script, capture stdout only and route stderr to a log file. The tool prints a one-line status that is safe togrepfor the mode name, but stderr may include warnings that should not be silently discarded. - Some carrier boards multiplex two UARTs to a single RS485 transceiver. Setting one mode sets the other; consult the carrier schematic before assuming per-UART independence.
- If the kernel platform driver is rebuilt against a newer kernel version, the sysfs path may change. Re-discover the attribute with
find /sys -name 'ttyS*' -type f 2>/dev/nullafter the upgrade. - Custom builds that drop the
iot2000-serialmodekernel module will appear to runswitchserialmodesuccessfully but no GPIO is actually toggled. Always verify with sysfs or a hardware loopback on custom images.
Frequently Asked Questions
Which image version added the read-back of the active serial mode?
SIMATIC Industrial OS v2.2.0. The change is recorded in the meta-iot2000 changelog on GitHub and in the Siemens Industry Online Support release notes for the IoT2000 product family.
Can I run switchserialmode from a non-root account?
On stock images, no. The tool drives GPIOs that are not exported to unprivileged users; the binary is owned by root. Run it via sudo or as root, or add a sudoers entry that scopes the command to the device argument.
Why does the mode revert after a reboot on my custom Yocto build?
Custom builds frequently omit the iot2000-serialmode-persist.service unit that writes the active mode back at boot. Add the unit from the meta-iot2000 layer, or re-apply the mode after boot via a custom systemd service.
Is /dev/ttyS2 always COM2?
On the stock SIMATIC Industrial OS for the IoT2020 and IoT2040, yes. On custom carriers the device tree may rename the node; verify with ls -l /sys/class/tty/ttyS2/device/driver to confirm the physical UART instance.
How do I distinguish RS422 from RS485 with only a multimeter?
You cannot. Both standards use the same differential pair. The only practical way to discriminate is to drive the TX pair and observe the RX pair with the direction-control GPIO inactive (RS422 always listens) or active (RS485 toggles with transmit enable).