KONTRX Industrial Gateway
Kontrx is a bare-metal STM32F407 + FreeRTOS industrial edge gateway for water-quality monitoring. It doesn't just "have Ethernet"
Kontrx Edge Gateway — How an Industrial Water-Quality Controller Puts the W5500's Hardware Sockets to Work
Kontrx is a bare-metal STM32F407 + FreeRTOS industrial edge gateway for water-quality monitoring. It doesn't just "have Ethernet" — it runs three independent TCP roles simultaneously on a single WIZnet W5500: an HTTP dashboard server, an MQTT publisher, and a Modbus TCP client talking to remote PLCs. All three share the same SPI bus and the same chip's socket pool, arbitrated by a recursive mutex confirmed at the code level.
Overview
Field-level water-quality monitoring — pH, ORP, conductivity, dissolved oxygen, ammonia, ultrasonic level — usually means a pile of RS485 Modbus sensors on one side and, on the other, whatever mix of local control, SCADA integration, and cloud telemetry the plant happens to need. The challenge is fitting all of these communication needs onto a single microcontroller and a single Ethernet chip.
Kontrx is a single-board answer to that mix: an STM32F407VET6 running FreeRTOS, bridging an RS485 sensor bus and 10 local relays on one side to HTTP, MQTT, and Modbus TCP on the other — all of it going out through one WIZnet W5500.
What makes this project worth a closer look isn't "it uses a W5500 for internet access." It's how many different things that one chip is asked to do at once, and how the firmware keeps them from stepping on each other.
About IGNOVA Systems Integration
IGNOVA Systems Integration is an Egypt-based technology company specializing in industrial automation, smart buildings, and system integration. Its work spans technologies such as KNX, BMS, PLC, SCADA, HMI, energy management, and Industrial IoT.
KONTRX reflects this system-integration background by combining field-level sensing, control, Ethernet networking, MQTT/SCADA connectivity, and web-based management in a single embedded gateway architecture.
No commercial KONTRX hardware product is publicly listed, so the project is best described as an industrial edge-gateway platform or reference implementation built around STM32F407 and WIZnet W5500.
WIZnet Products Used
| Item | Detail |
|---|---|
| Chip | WIZnet W5500 (hardwired TCP/IP, 8 sockets, 32 KB internal buffer) |
| Host MCU | STM32F407VET6 (ARM Cortex-M4F @ 168 MHz) |
| Interface | SPI2 @ 21 MHz |
| Software stack | WIZnet's official ioLibrary_Driver, included directly in the repository |
Why the W5500, and Why This Way?
🔷 One Chip, Three Concurrent TCP Roles
The README's own architecture table assigns W5500 sockets by function:
| Task (FreeRTOS Priority) | W5500 Socket | Role |
|---|---|---|
Task_HTTPServer (Normal 2) | Socket 0 | TCP server on port 80 — dashboard + REST API |
Task_MQTTClient (High 4) | Socket 1 | TCP client — MQTT publisher |
Task_ControlEngine (Realtime 5) → plc_control.c | Socket 4 | TCP client — Modbus TCP, FC5 Write Single Coil to remote PLCs |
This is a textbook use of the W5500's independent hardware sockets: one acting as a server, two acting as clients to different remote endpoints, all coexisting without any of them needing to share a software TCP/IP stack or block each other.
🔷 Three Sockets, Mapped Precisely Onto a Priority Hierarchy
Looking closely at the combination of these three sockets reveals design intent that goes beyond "using several protocols at once."
Server role separated from client roles (Socket 0 vs. 1 and 4) Only Socket 0 is a server (listening for inbound connections); the other two are outbound clients. By putting "inbound" traffic — dashboard and REST API requests a human initiates — on a physically different socket from "outbound" traffic the gateway initiates itself (MQTT, Modbus TCP), delays in handling an external HTTP request never bleed into the cloud telemetry path or the PLC control loop.
Priority and time-sensitivity line up exactly with socket assignment
- Socket 4 (Modbus TCP) →
Task_ControlEngine, FreeRTOS priority Realtime (5), called directly inside a 10 ms cycle — the most time-sensitive path - Socket 1 (MQTT) →
Task_MQTTClient, priority High (4), event-driven Change-of-Value publishing - Socket 0 (HTTP) →
Task_HTTPServer, priority Normal (2) — the dashboard a human watches, and the most tolerant of latency
In other words, it isn't the socket number that matters but the priority of the task calling that socket — a real QoS hierarchy. The most critical real-time control traffic (Socket 4) sits on the highest-priority task, and the most latency-tolerant traffic (Socket 0) sits on the lowest, consistently.
What it means that a Realtime task calls network I/O directly Embedded real-time systems generally avoid putting network I/O inside their highest-priority task, because software TCP/IP stacks have jittery latency from retransmission, buffering, and internal locks — exactly the kind of thing that can blow a 10 ms deadline. Kontrx can put the Modbus TCP client (Socket 4) straight inside a Realtime task because accessing the W5500's socket registers is a predictable, fixed-time SPI transaction, not a software stack — the TOE's deterministic latency is what makes this placement possible at all. And because the command running through this path is FC5 Write Single Coil — a write, not a read — this is a genuine "local real-time rule engine directly commanding a remote PLC actuator" closed-loop path.
Per-socket hardware isolation backs up the logical separation The W5500 gives each socket its own physically separate register set and dedicated TX/RX buffer, so the intent to "split things across sockets" translates directly into hardware-level isolation. The recursive mutex discussed below doesn't undermine this isolation — it only serializes the shared order of SPI bus access on top of it; each socket's TCP connection state remains fully independent of the others.
🔷 Confirmed at the Code Level: ioLibrary_Driver in the Repository
Kontrx's repository ships WIZnet's own ioLibrary_Driver directly rather than a wrapper library or an lwIP-based Ethernet PHY driver. Combined with the socket-per-task table above, this confirms the project is driving the W5500's hardware TCP/IP offload engine (TOE) directly — the STM32F407 firmware never has to implement its own TCP state machine, retransmission logic, or ARP handling.
Task_HTTPServer ──► Socket 0 ──┐
Task_MQTTClient ──► Socket 1 ──┼──► SPI2 (21 MHz) ──► W5500 TOE ──► Ethernet
plc_control.c ──► Socket 4 ──┘
🔷 The Real Engineering Problem: Sharing One SPI Bus Across Three Sockets
Three tasks at three different FreeRTOS priorities all need to talk to sockets on the same physical chip over the same SPI2 bus. The README calls this out explicitly as a designed-for hazard:
"Because both
Task_HTTPServer(Socket 0) andTask_MQTTClient(Socket 1) communicate over SPI2 to the W5500 controller, all WIZnet socket transactions are guarded byxSemaphoreCreateRecursiveMutex(). This completely prevents SPI transaction interleaving and eliminates socket timeout faults."
This is the detail that separates "we wired up a W5500" from "we understood what happens when a Realtime-priority control task, a High-priority MQTT task, and a Normal-priority HTTP task all want the same SPI bus at once." A naive implementation would corrupt SPI frames or stall a socket waiting on a higher-priority task's transaction; Kontrx's recursive spiMutex is exactly the fix that class of bug requires.
🔷 Advantage Over Alternative Approaches
A typical ESP32-style Ethernet approach (ETH.h + lwIP) hands TCP/IP processing to the host MCU's software stack. Had Kontrx processed HTTP, MQTT, and Modbus TCP simultaneously through a software stack on a resource-constrained STM32F407 (192 KB SRAM), the burden of TCP state management, retransmission, and buffering would have eaten directly into MCU RAM and CPU cycles. By offloading that burden entirely to the W5500's TOE, the STM32 stays free to focus on application logic like the 100 Hz real-time control loop.
System Architecture
┌──────────────────────────────────────────────────────────────────────┐
│ KONTRX EDGE GATEWAY │
│ │
│ RS485 Modbus RTU ──► Continuous Poller ──► Sample Batch Averager │
│ │ │ │
│ ▼ ▼ │
│ 100Hz Control Engine ──► Rule Engine Sparkplug B Protobuf │
│ │ │ │
│ ▼ ▼ │
│ Local / Remote Actuators W5500 SPI Ethernet (TOE) │
│ - 10x Onboard Relays - Socket 0: HTTP Server │
│ - Modbus TCP (Socket 4, port 502) - Socket 1: MQTT Publisher │
│ - OPC UA interface - Offline 512KB Ring Queue │
└──────────────────────────────────────────────────────────────────────┘
Hardware, Communication & Reliability
Hardware Interface
| Signal | Pin | Detail |
|---|---|---|
| SPI2 SCK / MISO / MOSI | PB13 / PB14 / PB15 | 21 MHz, Alternate Function 5 |
| W5500 Chip Select | PB12 | Active-low, GPIO push-pull |
The W5500 shares SPI2 with a Winbond W25Q16 (2 MB NOR flash used for web assets, config, and the telemetry ring buffer) — a second reason the SPI mutex matters: it's not just arbitrating between W5500 sockets, it's arbitrating between two different SPI peripherals on one bus.
Reliability Design
- Offline telemetry queue: If the Ethernet link or MQTT broker connection drops, telemetry automatically diverts to a 512 KB SPI-flash FIFO queue, buffering up to 32,768 records with microsecond RTC timestamps, then flushing them in chronological order once connectivity returns.
- Rule-engine probation: When a user uploads new automation rules, they run in RAM for a 30-second trial period before being committed to flash — only surviving that window without a crash gets a rule set written permanently. A reboot during probation rolls back to the last stable backup rule set automatically.
- Redundant config storage: Both gateway configuration and automation rules are stored in duplicate Primary/Backup sectors.
- Field OTA: After OTP authentication on the dashboard, a new firmware image is written to staging flash, verified by CRC32, and only then does the bootloader jump to it — enabling safe field updates with no physical access required.
What is Sparkplug B?
Kontrx publishes its telemetry as Eclipse Sparkplug B, a lightweight open standard built on top of MQTT for industrial/SCADA data (birth/death lifecycle messages, structured Protobuf payloads). It's what lets telemetry plug directly into SCADA platforms like Ignition or Node-RED without custom parsing on the receiving end. It's worth noting that Sparkplug B is an optional layer on top of MQTT for cloud/SCADA delivery — the underlying Modbus RTU/TCP communication in Kontrx works completely independently of it and doesn't require it.
Project Value
Most maker-scale W5500 projects use one socket for one job — an HTTP server, or an MQTT client, or a UDP stream. Kontrx is a useful reference point precisely because it's the opposite case: three roles, three sockets, one chip, one SPI bus, arbitrated correctly under a hard real-time scheduler.
For anyone building a multi-protocol industrial gateway on the W5500 rather than a single-purpose IoT node, the socket-per-task table and the recursive-mutex pattern here are directly reusable. It's also a reminder of what the W5500's socket-based TOE is for: not just "more connections," but structurally isolated network roles that a single MCU can drive without writing its own TCP/IP stack three times over.
Comparison with Similar WIZnet Projects
Compared with similar W5500-based industrial projects on WIZnet Maker, Kontrx combines several common gateway patterns into a more integrated real-time architecture.
| Project | Similarity | Key Difference |
|---|---|---|
| Industrial Multi-Protocol Gateway (MTGateway) | Uses W5500 hardware sockets for HTTP, Modbus TCP, and BACnet/IP | Focuses on protocol conversion, while Kontrx combines networking with real-time control, MQTT telemetry, and actuator management |
| Zero Downtime Industrial IoT Gateway | STM32 + RTOS + W5500 architecture with Modbus and MQTT | Emphasizes long-term communication reliability, while Kontrx adds HTTP, Modbus TCP control, offline buffering, and rule-based automation |
| Interrupt-Driven W5500 UDP Server on STM32F4 | Uses STM32F407, FreeRTOS, W5500, and ioLibrary | Demonstrates a minimal single-socket implementation, while Kontrx expands the same platform into a multi-socket industrial gateway |
The main distinction of Kontrx is its use of multiple W5500 hardware sockets as part of a prioritized FreeRTOS control architecture. HTTP, MQTT, and Modbus TCP operate independently while sharing the same W5500 through controlled SPI access, allowing networking, telemetry, and real-time control to coexist on a single MCU.
FAQ
Q. Does Kontrx use the W5500 as a plain Ethernet PHY, or does it use the hardware TOE? A. The hardware TOE. The repository includes WIZnet's own ioLibrary_Driver, and the architecture explicitly assigns application roles to specific hardware sockets (0, 1, 4) rather than routing everything through a software TCP/IP stack.
Q. Why does a single chip need a mutex around its own sockets? A. Because three FreeRTOS tasks at three different priorities all issue SPI transactions to the same W5500 over the same SPI2 bus. Without arbitration, a higher-priority task could interrupt another task's SPI frame mid-transaction, corrupting socket state or causing timeouts. The recursive mutex serializes all W5500 SPI access regardless of which task or socket is involved.
Q. Is the water-quality use case specific to the wiring, or could this architecture generalize? A. The socket-per-role pattern (server + N clients on one W5500, guarded by one mutex) doesn't depend on water quality at all — it would generalize to any STM32 + FreeRTOS gateway that needs an HTTP/REST interface, an MQTT/cloud path, and a Modbus TCP (or other TCP client) path simultaneously.
Q. What's not confirmed from the public repository? A. There's no visible star/fork/issue activity, so real-world deployment scale or field-tested throughput numbers aren't independently verifiable — the technical claims here are based on what's confirmed in the source code and README, not on production usage evidence. It's also worth noting that the repository's About description says "built on KNX," while the README body never mentions KNX at all — a mismatch between the description and the actual content.

