vetrnik
STM32F401 + W5500 edge controller enables real-time MQTT over hardware TCP/IP offload for deterministic, fail-safe wind turbine control.
What the Project Does
Vetrnik is not just a sensor node—it is a network-connected control system for a wind turbine.
It performs three roles simultaneously:
Data acquisition
Power board via UART
Wind speed via RS485 (Modbus RTU)
Temperature via OneWire (DS18B20)
Real-time control
Duty cycle adjustment
Control strategy switching
Emergency shutdown via GPIO
Network integration (MQTT)
Publishes telemetry to broker
Receives remote control commands
Executes runtime logic (even Lisp scripts)
Generated by Chat GPT
Data Flow (actual system behavior)
Sensors / Power Board
↓
STM32F401CC
↓ (SPI)
W5500
↓
MQTT Broker (Home Assistant)
↑
Remote Control Commands
Key detail:
Control decisions depend on network state, making networking part of the safety system—not just telemetry.
Where WIZnet Fits
The system uses WIZnet W5500 via WIZ850io module as the only network interface.
Its role is not “connectivity”—it is system isolation:
1) Hardware TCP/IP Offload
TCP retransmission, ACK, checksum handled in silicon
STM32 never runs a TCP/IP stack
2) Deterministic Execution
No LwIP interrupts
No Wi-Fi stack jitter
Control loop timing remains stable
3) Socket-Level Abstraction
EthernetClient maps directly to W5500 sockets
MQTT runs on top without custom drivers
4) System Safety Dependency
Network failure triggers emergency shutdown logic
W5500 stability directly affects physical safety
This is where W5500 becomes critical:
It turns networking into a predictable peripheral, not a software risk.
Implementation Notes
1) Boot Sequence Is Network-Aware
File: firmware/vetrnik-control/src/main.cpp
pinMode(PIN_ETH_RST, OUTPUT);
ETH_reset(); // 1. Reset W5500 first
SerialFlash.begin(PIN_FLASH_SS); // 2. Validate SPI bus
settings_init(); // 3. Load config
MQTT_init(); // 4. Start Ethernet + MQTT
IWatchdog.begin(WATCHDOG_TIME * 1000UL); // 5. Start watchdogWhy this matters:
W5500 must be stable before MQTT starts
Watchdog starts after DHCP to avoid false resets
This is hardware timing shaping software architecture
2) W5500 Initialization with Safety Constraints
File: src/mqtt.cpp
if (DHCP_mode)
result = Ethernet.begin(settings.ETH_MAC,
settings.DHCP_timeout_s * 1000UL);
else
Ethernet.begin(settings.ETH_MAC, settings.ETH_IP);
MQTTClient.setSocketTimeout(settings.MQTT_timeout_s);Key insight:
DHCP timeout = 14s
Watchdog = 16s
→ This is intentional margin design
→ Prevents boot-loop failure
3) Hardware TCP Socket → MQTT Layer
static EthernetClient ethClient;
PubSubClient MQTTClient(ethClient);What actually happens:
EthernetClient = W5500 socket registers
No TCP stack in MCU
MQTT becomes lightweight message layer only
4) MQTT with LWT (Failure Detection)
MQTTClient.connect(
MQTTclientID,
settings.MQTTuser,
settings.MQTTpassword,
MQTTtopic_availability,
2, true, "offline"
);If device crashes → broker publishes "offline"
Used directly by Home Assistant
This is network-level health monitoring without extra code
5) Reconnection Strategy (Industrial-Grade)
if (MQTT_reconnect_count > 6)
{
if (now - MQTTLastReconnect < MQTTReconnectRate * 3)
return;
}First 6 retries: 20s interval
After that: 60s interval
15 minutes → forced W5500 reset
Why this matters:
Prevents network flooding
Handles long-term instability
Assumes real-world field failures
6) MQTT Topic Dispatch Optimization (O(1))
constexpr uint16_t topic_hash_ce(const char* str, uint16_t hash = 5381);
switch (topic_hash(topic))
{
case topic_hash_ce("power_board/duty"):
wt_hal.pwr_set_duty(duty);
break;
}Why this exists:
Avoid strcmp() loops
Reduce CPU cycles on STM32
Deterministic dispatch time
7) Publish Optimization (Bandwidth Control)
#define COND_HYST(var, hysteresis) \
(abs((int_fast32_t)var - (int_fast32_t)(prev_##var)) > hysteresis)Example:
Temperature only sent if change > 0.9°C
Result:
Reduced MQTT traffic
Lower SPI + network load
Stable broker performance
8) Fail-Safe: Network Loss → Emergency Stop
File: control.cpp
if (millis() - MQTT_last_command_ms >= 30000UL)
{
control_set_strategy(control_emergency);
}Emergency mode:
digitalWrite(PIN_EMERGENCY, LOW);
Critical insight:
Network is part of control loop
Loss of MQTT = physical shutdown
This is network-aware safety design
9) SPI Bus Sharing (Hidden Design Strength)
#define PIN_FLASH_SS PB1
// W5500 uses PA4 (default CS)W5500 + Flash share SPI1
Only CS lines differ
Why this is important:
Saves pins
Reduces PCB complexity
Works because W5500 handles buffering internally
10) Ethernet-Based OTA (Field Deployment)
ArduinoOTA.begin(
Ethernet.localIP(),
settings.OTAname,
settings.OTApassword,
InternalStorage
);Firmware update via HTTP POST
Uses W5500 connection
Extra detail:
Buzzer toggles during OTA → physical feedback
Practical Tips / Pitfalls
Always align DHCP timeout < Watchdog timeout
Use hardware reset (RST pin) for long-term reliability
Avoid SPI contention when sharing with Flash
Do not rely on polling-only designs for high traffic (consider INTn if scaling)
Tune MQTT packet size based on payload (e.g., Lisp execution here)
Use hysteresis to reduce unnecessary network load
Treat network loss as a control failure, not just connectivity issue
FAQ
Q: Why is W5500 critical in this system?
A: It offloads TCP/IP entirely, ensuring the STM32 can run deterministic control logic without being interrupted by networking tasks.
Q: How is W5500 connected to STM32?
A: Via SPI1 (PA5/PA6/PA7) with CS on PA4 and reset on PB10. It shares the bus with external flash using separate chip select lines.
Q: What exactly does W5500 do here?
A: It handles all Ethernet communication, including TCP sockets used by MQTT, while the MCU only reads/writes data through SPI.
Q: Can beginners build this system?
A: It requires intermediate knowledge: STM32, SPI, MQTT, and embedded control logic. Not beginner-level but reproducible with experience.
Q: Why not use Wi-Fi instead?
A: Wi-Fi introduces latency variation and connection instability. This system requires deterministic behavior because network failure directly triggers emergency control.
Source
Project: Vetrnik Wind Turbine Controller
Key files:
firmware/vetrnik-control/src/mqtt.cppfirmware/vetrnik-control/src/main.cppfirmware/vetrnik-control/src/control.cppfirmware/vetrnik-control/src/ota.cpphardware/vetrnik-control/lib/vetrnik-control.pretty/WIZ850io.kicad_mod
Tags
#W5500 #WIZ850io #STM32 #MQTT #IndustrialIoT #EdgeController #Ethernet #SPI #EmbeddedSystems #FailSafe

