Wiznet makers

viktor

Published March 18, 2026 ©

150 UCC

20 WCC

48 VAR

0 Contests

0 Followers

0 Following

Original Link

How to Forward Triple CAN Traffic to the Cloud with W5500 on STM32H723?

This project uses an STM32H723VGT6 to read three FDCAN buses, timestamp and serialize the frames, and stream them to a remote server over WebSocket

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

Summary

This project uses an STM32H723VGT6 to read three FDCAN buses, timestamp and serialize the frames, and stream them to a remote server over WebSocket while also supporting SD-card logging. In that architecture, the WIZnet W5500 is the SPI-attached Ethernet endpoint and socket engine that carries DNS, NTP, and WebSocket traffic without forcing the application to build around a separate software Ethernet stack.

3D PCB Front
Source: https://github.com/killer400033/stm32-can-forwarder-v2

What the Project Does

The repository is a CAN-to-Ethernet forwarder built around the STM32H723, three FDCAN peripherals, FreeRTOS tasks, a W5500 Ethernet controller, and microSD storage. Its main job is to ingest frames from three independent CAN buses, preserve bus identity and timestamps, package those frames into protobuf messages, and send them upstream through a WebSocket connection. The same project also includes DNS resolution, NTP time synchronization, ADC monitoring, watchdog handling, and SD-card logging as supporting services around the data path.

The CAN side is implemented as an interrupt-driven intake path. In Core/Src/can_driver.c, the firmware accepts both standard and extended CAN identifiers, reads frames from the FDCAN RX FIFO, stamps each frame with bus identity and time, and pushes the result into canStreamQueueHandle for later transmission. That means the project is not just “reading CAN”; it is building a structured queue between real-time capture and network export.

On the network side, Core/Src/app_layer.c creates a WebSocket client on top of the W5500 socket API. The task waits for DNS resolution and NTP sync, connects to the server on port 80, batches up to nine CAN frames at a time, encodes them with nanopb protobuf, and sends them as binary WebSocket frames. That is the critical application-level behavior: raw vehicle or machine-bus traffic becomes timestamped cloud telemetry.

Although the repository is presented as a vehicle CAN forwarder, the architecture also maps cleanly to Industrial IoT gateways, lab instrumentation, classroom demos, and commercial data loggers, because the core pattern is the same in each case: multiple field buses in, deterministic local capture, Ethernet backhaul out. That broader applicability is an inference from the project’s confirmed CAN-queue-WebSocket structure.

Where WIZnet Fits

The exact WIZnet part in this project is the W5500. The README identifies it as the system’s Ethernet controller, and the firmware wraps it in W5500Init() plus an initWizchip() call that sets IP, gateway, subnet, and per-socket memory allocation. The header file also assigns dedicated sockets for DHCP, DNS, streaming, and NTP, so W5500 is not a passive PHY here; it is the active transport boundary for every network-facing service in the design.

That is a good fit for this architecture. The STM32H723 is already handling three CAN receivers, timestamp management, protobuf serialization, task scheduling, logging, and storage. W5500 contributes hardwired TCP/IP, eight hardware sockets, and 32 KB of internal packet memory over SPI, which keeps the network side in a socket-oriented model instead of pushing more Ethernet stack work into the MCU application. In this project, that matters because the firmware explicitly tunes socket buffers and dedicates one socket to the streaming path.

The most interesting detail is that the streaming socket is treated as a first-class resource. During basic startup, the code allocates a moderate transmit budget to the stream socket. Once DNS and time sync are in place, the app layer reinitializes the W5500 and expands the stream socket to a 16 KB TX buffer for WebSocket traffic. That is a concrete example of W5500 being used as a controllable transport engine, not merely a board-level Ethernet checkbox.

Implementation Notes

In Core/Src/w5500_setup.c, the initial W5500 configuration reserves sockets for infrastructure services and gives extra transmit space to the stream path:

rx_buf_sizes[STREAM_SOCKET] = 1;
tx_buf_sizes[STREAM_SOCKET] = 8;
result = initWizchip(net_info.ip, net_info.sn, net_info.gw,
                     rx_buf_sizes, tx_buf_sizes);
This matters because it shows how the project treats W5500 memory as part of system design. DNS, DHCP, NTP, and streaming are all present, but the stream socket is already biased for outbound throughput from the first initialization step.

Later, in Core/Src/app_layer.c, the firmware reallocates W5500 memory once the remote target is known and the system clock is synchronized:

rx_buf_sizes[STREAM_SOCKET] = 1;
tx_buf_sizes[STREAM_SOCKET] = 16;
ws_client_init(&ws_config);
This is the strongest WIZnet-specific design choice in the repo. The code gives the WebSocket channel the full 16 KB transmit allocation, then initializes the client against the resolved host, which is exactly what you would expect in a forwarder optimized for one dominant uplink flow rather than many equal sockets.

The CAN side explains why this network choice is sensible. In Core/Src/can_driver.c, each incoming frame is tagged with its bus number and timestamp before being queued, and the RX FIFO callback drains frames when the watermark interrupt fires. In other words, the MCU’s time budget is already spoken for by capture integrity; using W5500 for socket handling leaves more of that budget available for the actual forwarding logic.

Practical Tips / Pitfalls

  • Keep the W5500 socket plan aligned with the header definitions. This repo reserves Socket 0 for DHCP, 1 for DNS, 2 for streaming, and 3 for NTP, so changing one part of the network layer without updating the rest will break assumptions quickly.
  • Do not ignore buffer sizing. The project starts with an 8 KB TX allocation for the stream socket and later expands it to 16 KB for WebSocket traffic, which tells you the uplink path is sensitive to transmit buffering.
  • Treat SPI wiring and chip select as part of bring-up, not afterthoughts. The generated STM32 header exposes the W5500 on SPI1_CS_Pin and defines a separate WIZNET_INT_Pin, which is the minimum board-level evidence you should preserve if you reproduce the design.
  • Validate queue pressure under real CAN load. The capture path increments dropped_packets when canStreamQueueHandle fills, so sustained uplink stalls will surface first as queue loss rather than graceful backpressure.
  • Keep time sync in the architecture. This firmware waits for NTP synchronization before committing to the WebSocket session, and its CAN timestamps are part of the forwarded data model, so removing NTP changes the meaning of the output, not just a cosmetic clock.
  • For noisy automotive or industrial environments, deterministic wired Ethernet is a sensible transport choice here because the repo already depends on continuous queued forwarding and timestamp preservation. That is an engineering inference from the verified data path, not a claim made verbatim by the author.

FAQ

Q: Why use W5500 in this project instead of building the Ethernet side around lwIP and a separate MAC flow?
A: Because this firmware is already busy with three FDCAN receivers, timestamps, protobuf packing, DNS, NTP, SD logging, and FreeRTOS scheduling. W5500 gives the design a hardwired socket model with dedicated packet memory, which matches the repo’s explicit per-socket buffer allocation and lets the application stay focused on capture and forwarding rather than broader Ethernet stack integration.

Q: How does W5500 connect to the STM32H723 platform here?
A: Over SPI. The initialization path passes an STM32 SPI handle into W5500Init(), and the generated main.h defines SPI1_CS_Pin on GPIOD plus a separate WIZNET_INT_Pin, which is exactly the kind of wiring you expect for an SPI-attached W5500 on STM32.

Q: What role does W5500 play in this specific forwarder?
A: It carries the project’s entire Ethernet service layer: DNS resolution, NTP time sync, and the WebSocket uplink used to stream protobuf-encoded CAN frames. The code assigns sockets by role and then enlarges the streaming socket’s TX buffer once the uplink is ready, so W5500 is the active network engine for the CAN-to-cloud bridge.

Q: Can beginners follow this project?
A: A beginner can learn from it, but it is better suited to an intermediate embedded developer. You need working knowledge of STM32Cube/HAL, FreeRTOS tasks and queues, CAN/FDCAN framing, SPI peripherals, and basic network concepts such as DNS, NTP, and WebSocket transport.

Q: How does W5500 compare with lwIP or Wi-Fi for this kind of gateway?
A: Compared with an lwIP-style approach, W5500 keeps the design in a simpler socket-offload model that this repo is already coded around. Compared with Wi-Fi, wired Ethernet is the cleaner fit for timestamped, continuous bus forwarding because the project’s queueing, logging, and reconnect logic all assume a stable uplink rather than a highly variable radio link. The first point is directly supported by the code and W5500 documentation; the second is an engineering comparison drawn from the project’s traffic pattern.

Documents
Comments Write