1. Overview
The Siemens SIMATIC IOT2040 (and its successor SIMATIC IOT2050) is a ruggedized industrial gateway based on an Intel Quark x86 processor. It runs the Siemens Example Image, a Yocto-derived Linux distribution that exposes RS-232, RS-485, Ethernet, USB, and GPIO for protocol bridging, edge analytics, and SCADA integration. Because the platform exposes a full POSIX userspace, it can host any serial-attached transceiver that speaks an ASCII command set.
This article documents the field-proven integration of Microchip RN2483 LoRaWAN modules with the IOT2040 for bidirectional telemetry in private (self-hosted gateway) and public (operator-hosted) LoRaWAN networks. The configuration works with the IOT2050 as well, since the Example Image tooling and UART mapping are preserved across hardware revisions. Two physical integration paths are covered: direct UART connection to the on-board RS-232 header, and the EXPEMB FlexSensor LoRaWAN Shield stacked on the Arduino-compatible header.
2. LoRaWAN Protocol Fundamentals
LoRaWAN is a low-power, wide-area network (LPWAN) protocol layered on top of the proprietary LoRa chirp-spread-spectrum modulation. The modulation and the MAC layer are independently specified:
- LoRa (physical layer): Chirp spread spectrum operating in sub-GHz ISM bands. Regional duty-cycle and channel plans are defined by the LoRa Alliance regional parameters document (RP2-1.0.3 for the latest revision).
- LoRaWAN (MAC layer): Star-of-stars topology in which end devices communicate exclusively with a gateway that forwards the frame to a network server. The network server handles deduplication, ADR (Adaptive Data Rate), and security.
Three device classes are defined:
| Class | Receive Windows | Power Profile | Typical Use |
|---|---|---|---|
| A | Two, only after uplink | Lowest | Battery sensors, metering |
| B | Scheduled ping slots | Medium | Actuator control |
| C | Continuous (except while transmitting) | Highest | Mains-powered actuators |
The RN2483 ships as a Class A device. To upgrade to Class C, the RN2903 or firmware >= 1.0.5 is required; verify against the Microchip LoRaWAN stack release notes.
3. IOT2040 Hardware Architecture
The IOT2040 platform is documented in the Siemens IOT2040 Operating Instructions and the IOT2050 manual set. Relevant interfaces for this integration:
| Interface | Connector | Use for LoRaWAN |
|---|---|---|
| RS-232 (X30 COM1) | RJ45, 3-wire | Direct RN2483 UART (TX/RX/GND) |
| RS-485 (X31 COM2) | RJ45 | Not used; LoRaWAN is point-to-point UART |
| Arduino shield header (X20/X21) | 2x 16-pin | EXPEMB FlexSensor shield socket |
| USB 2.0 | Type-A | Optional debug console |
| Ethernet | RJ45 x2 | Backhaul to WinCC OA / SCADA |
The on-board RS-232 transceiver is a TRS3122E or compatible, providing true ±5 V levels. The RN2483 logic is 3.3 V CMOS, so a level shifter (e.g., TXS0108E or discrete MOSFET bridge) is mandatory when wiring directly. The EXPEMB shield integrates the level translation and the SMA antenna connector.
4. Microchip RN2483 Module Specifications
The RN2483 is a fully certified 868 MHz LoRaWAN module from Microchip. Key parameters from the RN2483 datasheet (DS50002346C):
| Parameter | Value |
|---|---|
| Frequency band | 863–870 MHz (EU/ETSI) |
| Modulation | LoRa (CSS), FSK/OOK for legacy |
| TX power | +14 dBm max (programmable, 1 dB steps) |
| RX sensitivity | -148 dBm at SF12/125 kHz |
| UART | 3.3 V CMOS, 8N1, default 57600 bps |
| Operating voltage | 2.1–3.6 V (typ. 3.3 V) |
| MAC | LoRaWAN 1.0.2 (Class A) |
| Certifications | ETSI EN 300 220, FCC, IC, ARIB |
The module exposes a UART-driven ASCII command interface that returns line-terminated responses. Every command line is terminated by \r\n and the module echoes commands unless echo is disabled with sys set echo off.
5. Hardware Integration Paths
5.1 Direct UART (X30 → RN2483)
Wire the RN2483 evaluation board to the IOT2040 COM1 (X30 RJ45) using the Siemens standard RS-232 pinout. The shield ground is pin 4; TXD/RXD are pins 3 and 5 in the Siemens convention.
IOT2040 X30 (RS-232) RN2483 (3.3V CMOS)
Pin 3 RXD ------------> TX (3.3V via level shifter)
Pin 5 TXD <------------ RX (3.3V CMOS)
Pin 4 GND ------------- GND
VCC <- 3.3V from IOT2040 5V via LDO
5.2 EXPEMB FlexSensor LoRaWAN Shield
The EXPEMB FlexSensor LoRaWAN Shield for IOT2000 plugs directly onto the Arduino-compatible shield header (X20/X21) on the IOT2040. It carries the RN2483, SMA antenna connector, level shifters, and a reset line wired to a GPIO. The shield communicates with the host over UART, mapped to /dev/ttyS2 by the Example Image device tree overlay.
&uart2 in the IOT2040 BSP. Confirm overlay availability against the Example Image release notes for your installed image version.6. Configuring the Serial Port on the IOT2040
The Example Image ships with stty, setserial, and the Linux serial drivers preinstalled. The RN2483 default baud rate is 57600 8N1 with hardware flow control disabled.
# Identify COM1
ls -l /dev/ttyS*
# /dev/ttyS0 (console on debug UART)
# /dev/ttyS1 (RS-485 COM2)
# /dev/ttyS2 (RS-232 COM1, used for LoRaWAN)
# Configure 57600 8N1, raw mode
stty -F /dev/ttyS2 57600 cs8 -cstopb -parenb -ixon -ixoff raw -echo
To verify the link, send the RN2483 firmware version query:
echo -e 'sys get ver\r' > /dev/ttyS2
cat /dev/ttyS2 &
sleep 1
# Expected: "RN2483 1.0.5 Dec 15 2017 09:38:09" (or similar)
If the version string is not returned within 1 s, check the level shifter polarity (RN2483 TX is high-idle) and confirm the antenna is attached (transmissions without antenna can corrupt firmware on some boards).
7. Joining the LoRaWAN Network
Over-the-air activation (OTAA) is the recommended path because the session keys are derived per session and rotated by the network server. Provision the device on the network server (TTN console, ChirpStack, or Actility ThingPark) and capture the three OTAA parameters:
-
DevEUI— 8-byte device identifier, printed on the module label or returned bysys get hweui(RN2483 uses the hardware EUI as the default DevEUI). -
AppEUI— 8-byte application identifier, sometimes called JoinEUI in LoRaWAN 1.1.x. -
AppKey— 16-byte AES-128 root key, provisioned out-of-band.
# Persist credentials on the module
mac set deveui 70B3D57ED0051234
mac set appeui 70B3D57ED000ABCD
mac set appkey 4A5B6C7D8E9F0A1B2C3D4E5F60718293
# Confirm LoRaWAN regional band (EU868 for EU deployments)
mac set ch drrange dn 0 5 # mandatory channels 0..2 in EU868, default DR0..DR5
mac set pwridx 1 # +10 dBm TX power (start low for lab work)
# Save and join
mac save
mac join otaa
# Expected: "accepted" within 5–10 s on a healthy link
If the response is denied or no_free_ch, the gateway is not reachable. Verify uplink on the gateway server, then re-attempt the join with mac join otaa. The join attempt opens two receive windows (RX1 1 s after uplink, RX2 2 s after uplink); an answered join returns accepted.
8. C++ Application on the IOT2040
A minimal C++ wrapper around the POSIX serial port is sufficient for telemetry pipelines. The Example Image toolchain includes GCC 7.x and the standard Boost libraries, but a hand-written termios loop is leaner and avoids dependency overhead.
// rn2483.hpp
#pragma once
#include <string>
#include <termios.h>
class RN2483 {
public:
explicit RN2483(const std::string& dev = "/dev/ttyS2");
~RN2483();
std::string send(const std::string& cmd, int timeout_ms = 1000);
bool joinOTAA(const std::string& devEui,
const std::string& appEui,
const std::string& appKey);
bool sendUplink(const std::string& payloadHex,
bool confirmed = true,
int port = 1);
private:
int fd_ = -1;
struct termios tio_{};
void drain();
};
// rn2483.cpp
#include "rn2483.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sys/select.h>
#include <cstring>
#include <iostream>
RN2483::RN2483(const std::string& dev) {
fd_ = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd_ < 0) throw std::runtime_error("open failed: " + dev);
::tcgetattr(fd_, &tio_);
::cfmakeraw(&tio_);
::cfsetispeed(&tio_, B57600);
::cfsetospeed(&tio_, B57600);
tio_.c_cc[VMIN] = 0;
tio_.c_cc[VTIME] = 1;
::tcsetattr(fd_, TCSANOW, &tio_);
}
RN2483::~RN2483() { if (fd_ >= 0) ::close(fd_); }
void RN2483::drain() {
char buf[256];
while (::read(fd_, buf, sizeof(buf)) > 0) {}
}
std::string RN2483::send(const std::string& cmd, int timeout_ms) {
drain();
std::string out = cmd + "\r\n";
::write(fd_, out.data(), out.size());
std::string resp;
char c;
struct timeval tv { timeout_ms / 1000, (timeout_ms % 1000) * 1000 };
fd_set rfds; FD_ZERO(&rfds); FD_SET(fd_, &rfds);
while (::select(fd_ + 1, &rfds, nullptr, nullptr, &tv) > 0) {
ssize_t n = ::read(fd_, &c, 1);
if (n <= 0) break;
if (c == '\n') break;
resp.push_back(c);
}
return resp;
}
bool RN2483::joinOTAA(const std::string& devEui,
const std::string& appEui,
const std::string& appKey) {
send("mac set deveui " + devEui);
send("mac set appeui " + appEui);
send("mac set appkey " + appKey);
send("mac save");
auto r = send("mac join otaa", 8000);
return r.find("accepted") != std::string::npos;
}
bool RN2483::sendUplink(const std::string& payloadHex,
bool confirmed, int port) {
std::string prefix = confirmed ? "mac tx cnfport " : "mac tx uncnfport ";
auto r = send(prefix + std::to_string(port) + " " + payloadHex, 6000);
return r.find("ok") != std::string::npos;
}
Compile with g++ -O2 -std=c++17 rn2483.cpp main.cpp -o lora_app and deploy to the IOT2040. A systemd unit can supervise the application across reboots:
# /etc/systemd/system/lora-app.service
[Unit]
Description=RN2483 LoRaWAN uplink
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/opt/lora/lora_app
Restart=on-failure
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
Enable with systemctl daemon-reload && systemctl enable --now lora-app.service.
9. WinCC OA Integration
WinCC OA (formerly PVSS) can subscribe to the IOT2040 over OPC UA or Modbus TCP, both of which the Example Image exposes through optional packages. The reference architecture used by the source integration is:
- IOT2040 receives LoRaWAN uplinks via RN2483.
- A C++ parser on the IOT2040 decodes the CayenneLPP payload and writes measurements to an OPC UA server (e.g., open62541).
- WinCC OA connects to the OPC UA endpoint
opc.tcp://iot2040.local:4840and maps each measurement to a datapoint.
CayenneLPP is the recommended payload format because it provides a compact binary encoder for the most common sensor types (temperature, humidity, digital input, analog input). A typical 4-byte temperature frame is 01 67 01 10 (channel 1, temperature, signed 16-bit 0.1 °C, value 272 = 27.2 °C).
When OPC UA is not available on the WinCC OA side, the IOT2040 can publish a Modbus TCP holding register set on port 502 and WinCC OA can poll it via the Modbus/TCP driver. Use libmodbus on the IOT2040 and configure WinCC OA driver type MODBUS with the appropriate register map.
10. Adaptive Data Rate and Channel Planning
EU868 mandates a 1 % duty cycle on the default channels. The RN2483 firmware enforces the duty cycle internally once the channel mask is set correctly:
mac set ch drrange dn 0 5 # ch0 DR0..DR5 (mandatory 868.1 MHz)
mac set ch drrange dn 1 5 # ch1 DR0..DR5 (mandatory 868.3 MHz)
mac set ch drrange dn 2 5 # ch2 DR0..DR5 (mandatory 868.5 MHz)
mac set ch status 3 on # enable default channels
For links with good RSSI margins, raise the data rate with mac set dr 5 to maximize airtime headroom. ADR negotiation can be enabled with mac set adr on; the network server will then optimize the DR on each uplink.
11. Commissioning Procedure
- Flash or update the Example Image to the latest supported release per Siemens Example Image release notes.
- Power-cycle the IOT2040 with the antenna attached and verify
sys get verreturns the RN2483 firmware string. - Configure the serial port with
sttyas shown in Section 6. - Provision OTAA credentials from the network server console.
- Issue
mac join otaaand confirmaccepted. - Send a confirmed uplink (
mac tx cnfport 1 AAAA) and confirmokand a server-side reception log entry. - Verify in WinCC OA that the datapoint updates within the expected airtime + backhaul latency budget (typically < 6 s for SF7).
- Enable the systemd unit for unattended operation.
12. Troubleshooting Matrix
| Symptom | Likely Cause | Remediation |
|---|---|---|
sys get ver returns nothing |
Wrong UART, missing level shifter, baud mismatch | Confirm /dev/ttyS2 at 57600 8N1; check level translation; verify GND is common |
mac join otaa → denied
|
DevEUI/AppEUI/AppKey mismatch or gateway down | Recheck credentials against network server; confirm gateway uplink packets reach the network server |
mac join otaa → no_free_ch
|
Duty cycle exhausted | Wait 60 s and retry; check that channel mask is correct for the region |
Uplink ok but no payload on network server |
Wrong DevAddr or AppSKey after ABP migration | Reset to OTAA; do not mix OTAA and ABP key sets on the same DevEUI |
| Periodic resets of RN2483 | Insufficient current on TX bursts | Add 100 µF bulk capacitor at module VCC; ensure supply can deliver 120 mA peak |
| WinCC OA sees stale data | OPC UA session timeout | Lower publish interval below session timeout; configure keepalive |
| RX2 misses confirmed downlinks | Default RX2 window set to DR0 / 869.525 MHz missing on gateway | Confirm RX2 frequency and DR are enabled on the gateway; align mac set rx2 <freq> <dr>
|
| High packet loss at long range | Antenna mismatch or SF too low | Switch to SF9..SF12; verify antenna SWR with VNA or return-loss meter |
13. Migration to IOT2050
The IOT2050 supersedes the IOT2040 and exposes the same Example Image with an updated device tree. The COM1 RS-232 UART is mapped to /dev/ttyS2 on the IOT2050 as well; existing RN2483 wiring harnesses are reusable. The Arduino shield header is preserved on the IOT2050 Advanced variant, so the EXPEMB FlexSensor shield is forward-compatible. When migrating, validate against the latest IOT2050 manual for any UART pinout revisions.
14. Field-Proven Caveats
- Some RN2483 firmware revisions prior to 1.0.4 have a bug where
mac savecorrupts the AppKey on a brown-out. Always re-read credentials withmac get appkeyafter a power cycle. - The Example Image console is also routed to a UART; do not connect the RN2483 to
/dev/ttyS0. - For an industrial installation, place the antenna outside any metal enclosure and use a lightning arrestor on outdoor cable runs. The RN2483 has no internal surge protection.
- When the IOT2040 is deployed in a cabinet with other RF emitters, mount the antenna at least 30 cm from any switching power supply or VFD cable.
Does the Siemens IOT2040 support LoRaWAN natively?
No. The IOT2040 has no onboard LoRa radio. LoRaWAN connectivity is added with an external module such as the Microchip RN2483 (UART) or the EXPEMB FlexSensor shield stacked on the Arduino header. A device-tree overlay may be required to enable the shield UART.
What serial parameters does the RN2483 require?
57600 bps, 8 data bits, no parity, 1 stop bit (8N1), no hardware flow control. The module idles high; mismatched polarity will appear as a silent UART.
Which LoRaWAN bands does the RN2483 support?
The RN2483 is the EU/ETSI 868 MHz variant. For 915 MHz (US/Asia/Australia) use the RN2903. Mixing modules across regions violates ETSI and FCC rules.
Can I run ABP instead of OTAA?
Yes, but OTAA is recommended for production because it rotates session keys on every join. ABP is acceptable only for permanent test devices with fixed keys; LoRaWAN 1.1.x additionally requires the NwkSKey and AppSKey plus a JoinSKey.
How do I forward LoRaWAN uplinks to WinCC OA?
Decode the payload on the IOT2040 (CayenneLPP or proprietary) and publish the measurements through OPC UA (open62541) or Modbus TCP (libmodbus). WinCC OA connects to the OPC UA endpoint or polls the Modbus registers. Keep the publish interval below the OPC UA session timeout (default 60 s).