Step 39 of 56
W5500: Ethernet with the stack on the chip
A hardwired TCP/IP controller with eight hardware sockets — and a layered driver that ends up looking like GNAT.Sockets.
The stack is not yours
The WIZnet W5500 is an SPI slave carrying an on-chip 10/100 PHY, a MAC, and a hardwired TCP/IP stack exposing eight independent hardware sockets. You are not writing a TCP implementation against it; you are driving one that already exists in silicon.
The driver is built in layers, which is worth knowing because it decides which package you should be reaching for:
| Layer | What it gives you |
|---|---|
ESP32S3.W5500 |
The SPI frame transport, hardware/software reset, common registers (identity, network config) and PHY link status. |
.Sockets |
The socket engine: TCP and UDP over the eight hardware sockets, with
a self-contained Socket handle and a
Status error model. |
.DHCP |
A minimal DHCP client — a software protocol over UDP, so it sits above the socket engine rather than in the chip. |
.Net_Device |
The W5500 as a concrete Net_Devices.Device, so it can
back the chip-neutral GNAT.Sockets facade. |
.Interrupts |
The INTn line. The base layer configures it as a pulled-up input but does not use it — the first pass is polling. |
The SPI frame, and why CS is a GPIO
Every access is one frame in Variable Length Data Mode: a 16-bit offset, a control byte, then N data bytes, with the offset auto-incrementing inside the frame. VDM keeps the bus shareable rather than demanding an exclusive transaction per register.
CS is driven as a plain GPIO, not routed to the SPI
peripheral — exactly as with SD over
SPI — because it has to be held low across all three phases of the
frame, and the peripheral's own CS pulses per transfer. Another concrete case for
SPI's CS_Pin. The chip runs in SPI mode
0.
Two levels of concurrency
Each frame takes the SPI host's session for its own transfer and releases it — the "lock the bus only as long as necessary" idiom shared with the other SPI drivers — so every W5500 access is atomic against any other task or device on that bus.
The socket layer then adds per-socket ownership on top. The eight sockets are genuinely independent, so different tasks can drive different sockets simultaneously, with the transport serialising the shared bus underneath. That is the arrangement that makes a multi-socket application straightforward rather than a locking exercise.
What is not there yet
- Polling, not interrupts. The blocking operations
—
Connect, andSend's completion — poll. INTn is wired and configured but unused at this layer. - DHCP has no renewal.
Acquire_Leaseis one-shot; call it again before the lease expires, because nothing will do it for you and the failure mode is a silently dead network.
A useful pairing: give the W5500 its address from
the eFuse MAC block's Ethernet entry
— a real manufacturer-assigned address rather than one you invented, which
matters as soon as two of your boards share a segment.