How to Build a Deterministic eBUS Ethernet Adapter with W5500 on PIC16F15356?
This project implements a deterministic PIC16F15356 firmware scaffold for a Helianthus eBUS adapter, using the WIZnet W5500 as the Ethernet transport
Summary
This project implements a deterministic PIC16F15356 firmware scaffold for a Helianthus eBUS adapter, using the WIZnet W5500 as the Ethernet transport path for the adapter’s TCP connection. The PIC firmware handles adapter framing, bus-byte forwarding, scan/status behavior, and host communication, while the W5500 provides the wired Ethernet socket layer that keeps TCP/IP handling outside the small 8-bit MCU runtime.
About the author
Project Helianthus is an open HVAC (Heating, Ventilation and Air Conditioning) gateway platform built around a protocol-agnostic semantic core. Its architecture separates transport, protocol decoding, device identity, semantic modeling, and consumer APIs so different HVAC bus adapters can plug into the same platform without rewriting the rest of the stack. Today, eBUS is the active production track and reference implementation, with repositories covering the Go eBUS transport layer, registry and semantic model, GraphQL/MCP gateway, Home Assistant add-on and integration, adapter proxy, TinyGo adapter harness, and the deterministic PIC16F15356 firmware used by this W5500 Ethernet adapter path.
What the Project Does
helianthus-ebus-adapter-pic is a clean-room firmware implementation for the PIC16F15356 used in Helianthus eBUS adapter v3.x hardware. The adapter sits between an ESP host and the eBUS wire. It is not a full eBUS application node; it behaves as a transparent adapter layer that detects SYN bytes, processes ENH adapter framing, forwards bus bytes, manages scan windows, emits status frames, and leaves higher-level eBUS protocol work to the host-side Go gateway.
The data flow is simple and timing-sensitive. On one side, the PIC talks to the eBUS transceiver through its bus UART. On the host side, it communicates with an ESP-based gateway using adapter framing at serial speeds such as 9600 or 115200 baud. In the Ethernet variant, the W5500 adds a wired TCP endpoint so the firmware can expose a socket interface instead of depending only on a serial host path.
A major design theme is determinism. The documentation states that the firmware is currently a host-buildable scaffold rather than a silicon-complete production image, and it explicitly tracks constraints such as bounded execution, fixed RAM budget, power-of-two buffers, limited call depth, and avoiding dynamic allocation. This matters because eBUS arbitration and byte forwarding are sensitive to jitter.
Where WIZnet Fits
The WIZnet product used here is the W5500 Ethernet controller. In this firmware, it acts as the hardware Ethernet and TCP socket interface for the PIC16F15356 Ethernet variant. The repository defines a W5500 register-level abstraction, maps common and socket registers, checks PHY link state, applies MAC/IP/subnet/gateway values, and opens a TCP listening socket for the eBUS daemon path.
This is a practical match for the PIC16F15356. The project’s own memory model notes 2 KB total RAM on the PIC16F15356, and the W5500 keeps TCP/IP state and Ethernet buffering outside the MCU’s limited runtime state. WIZnet’s W5500 provides a hardwired TCP/IP stack, SPI interface up to 80 MHz, 32 KB internal memory, and 8 independent hardware sockets, which aligns with this project’s preference for bounded firmware behavior instead of a software TCP/IP stack running on the PIC.
The platform mapping identifies the W5500 Ethernet module on SPI1 using PIC pins RB4 through RB7: SCK, select, SPCLK, and SPDAT. The firmware also defines the Ethernet hardware variant as PICFW_VARIANT_ETHERNET, which is the variant that enables the Ethernet state machine instead of leaving the Ethernet layer disabled.
Implementation Notes
The repository includes real W5500 integration code. It is important to read it as a scaffolded firmware model: the W5500 abstraction is present, the socket state machine is modeled, and Ethernet service logic exists, but the project documentation says the current tree is not yet a silicon-complete production image.
File: runtime/src/ethernet.c
This function opens the W5500 TCP socket on the configured eBUS daemon port and then moves it into listen mode:
static picfw_bool_t open_tcp_listen(picfw_w5500_t *w5500) {
if (!picfw_w5500_socket_open_tcp(w5500, PICFW_W5500_EBUSD_PORT)) {
return PICFW_FALSE;
}
return picfw_w5500_socket_listen(w5500);
}PICFW_ETH_STATE_TCP_LISTEN when the W5500 socket successfully opens.File: runtime/include/picfw/w5500.h
The W5500 header fixes the socket buffer sizes and default scaffold port:
#define PICFW_W5500_TX_BUF_SIZE 2048u
#define PICFW_W5500_RX_BUF_SIZE 2048u
#define PICFW_W5500_EBUSD_PORT 3333uebusd uses a single TCP connection, saving RAM compared with mirroring all eight sockets.The W5500 socket implementation is also explicit. picfw_w5500_socket_open_tcp() sets socket 0 to TCP mode, writes the source port, issues the W5500 OPEN command, and expects the socket state to become INIT. picfw_w5500_socket_listen() then issues LISTEN and checks for the LISTEN socket state.
One limitation is DHCP. The current DHCP service is a simulation path: the source comment states that real DHCP would use a W5500 UDP socket for the DHCP exchange, while the scaffold immediately transitions through default IP binding before opening the TCP listener.
Practical Tips / Pitfalls
- Treat port
3333as a scaffold default, not the usual production ENH adapter port. The documentation notes that production ENH adapters use9999or an EEPROM-configurable port. - Keep the W5500 path on SPI1 pins RB4–RB7 as modeled, and verify chip-select timing before moving from the host model to real hardware.
- Do not assume DHCP is complete. The current code uses a simulated DHCP transition; real DHCP would require UDP socket handling on the W5500.
- Preserve the single-socket design unless there is a clear requirement for more connections. The code intentionally mirrors only socket 0 to save RAM.
- Watch RAM growth. The PIC16F15356 has 2 KB RAM, and the project’s deterministic rules depend on keeping static runtime state bounded.
- Use the W5500 PHY link state as part of startup sequencing. The Ethernet service waits for link before selecting DHCP or fixed IP behavior.
FAQ
Q: Why use the W5500 in this PIC16F15356 eBUS adapter?
A: The W5500 moves TCP/IP handling into a dedicated Ethernet controller instead of forcing the PIC16F15356 to run a software network stack. That is useful here because the firmware is designed around bounded execution, low jitter, and a 2 KB RAM budget.
Q: How does the W5500 connect to the PIC16F15356?
A: The project models the W5500 on SPI1. The platform header maps the W5500 Ethernet module to RB4/SCK1, RB5/SEL1, RB6/SPCLK, and RB7/SPDAT.
Q: What role does the W5500 play in this project?
A: It provides the wired TCP listener for the Ethernet variant. The firmware applies MAC/IP configuration, opens socket 0 as TCP on PICFW_W5500_EBUSD_PORT, and moves the socket into listen mode so the adapter can expose its eBUS bridge through Ethernet.
Q: Can beginners follow this project?
A: It is better suited to embedded developers who already understand C, PIC register-level firmware, UART timing, SPI peripherals, and basic TCP socket behavior. The code is structured and heavily validated, but the deterministic constraints and scaffold status make it more of a firmware-engineering reference than a beginner tutorial.
Q: How does W5500 compare with using LwIP on the PIC?
A: LwIP would require the MCU to carry more TCP/IP state, timers, packet buffers, and protocol processing in firmware. In this project, the W5500 is the more realistic architecture because it provides hardwired TCP/IP, internal packet memory, and socket registers while the PIC remains focused on adapter timing and byte-forwarding behavior.
