Wiznet makers

TheoIm

Published March 20, 2026 ©

75 UCC

27 WCC

7 VAR

0 Contests

0 Followers

0 Following

Original Link

vetrnik

STM32F401 + W5500 edge controller enables real-time MQTT over hardware TCP/IP offload for deterministic, fail-safe wind turbine control.

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

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 watchdog

Why 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:

 
power_board_set_duty(0);
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.cpp
  • firmware/vetrnik-control/src/main.cpp
  • firmware/vetrnik-control/src/control.cpp
  • firmware/vetrnik-control/src/ota.cpp
  • hardware/vetrnik-control/lib/vetrnik-control.pretty/WIZ850io.kicad_mod

Tags

#W5500 #WIZ850io #STM32 #MQTT #IndustrialIoT #EdgeController #Ethernet #SPI #EmbeddedSystems #FailSafe

Documents
Comments Write