ESP32/Living on a network/50. Ethernet instead of Wi-Fi
Your chip
Your language
Living on a network · 50 of 81

Ethernet instead of Wi-Fi

Wi-Fi is right until the board is inside a metal cabinet, or has to answer within ten milliseconds every time, or must survive somebody changing the router password. Then you want a cable, and there are two very different ways to get one.

/esp32/ethernet-instead-of-wifi · arduino · S3

What a cable actually buys

1 wall away from the router
12 ms
Walls between board and router1
Wi-Fi round trip
12 ms
Packets lost
5%
Ethernet costs
9 pins + a PHY
12 ms and it wanders by ±9 ms. For a sensor posting every minute that is irrelevant. For anything where a late packet is a wrong packet — a light that must come on with a switch, a machine that must stop — the jitter is the specification, not the average, and Ethernet's 0.4 ms that never moves is what you are actually buying.

The two routes

Native MAC plus an external PHY — LAN8720 or similar, over RMII. Fast, needs six specific pins plus MDC and MDIO, and exists only on the classic ESP32 and the P4. The clock arrangement is fiddly and it is where most first attempts stall.

An SPI module — W5500 or ENC28J60. Four pins on any GPIO, works on every chip, roughly 8 Mbit/s in practice. The W5500 also runs its own TCP stack, so it uses less of the ESP32's RAM.

For nearly every project that wants a cable, the SPI module is the right answer.

Turn the radio off

If the board is wired, WiFi.mode(WIFI_OFF) saves 60–80 mA and removes a whole category of interference. Do it explicitly — the radio does not switch itself off just because you never called begin.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

The classic ESP32 has an Ethernet MAC built in and needs an external PHY. Six RMII pins are fixed by the hardware and belong to Ethernet for ever once you use them.

eth_rmii.ino
#include <ETH.h>

static bool up = false;

void onEvent(arduino_event_id_t e) {
  if (e == ARDUINO_EVENT_ETH_GOT_IP) {
    up = true;
    Serial.println(ETH.localIP());
  }
  if (e == ARDUINO_EVENT_ETH_DISCONNECTED) up = false;
}

void setup() {
  Serial.begin(115200);
  Network.onEvent(onEvent);
  // PHY address, MDC, MDIO, power pin, PHY type, clock mode
  ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN);
}

void loop() {
  if (up) { /* the network is ready */ }
}

ETH.begin returns before the link is up. Wait for the ETH_CONNECTED event rather than assuming, exactly as with Wi-Fi.

When it does not work

The link light is on and there is no IP address

RMII clocking. The PHY and the ESP32 must agree on which end generates the 50 MHz clock, and getting it backwards gives you exactly this - a physical link and no traffic.

It works until Wi-Fi is also enabled

On an RMII design GPIO 0 often carries the clock, and GPIO 0 is also a strapping pin. Adding anything else to it breaks both.

Six pins is more than I have left

Then use the SPI route. A W5500 costs four pins, works on the C3 and C6 which have no Ethernet MAC at all, and gives up throughput you probably were not using.

Power over Ethernet resets the board under load

PoE splitters have a startup surge and many cheap ones cannot hold 3.3 V through a Wi-Fi burst. If the board is wired, switch the radio off entirely.

Where this goes next

However it got on the network, the next chapter is what it can serve once it is there.

Hello world from the board

Edit this page — content/esp32/ethernet-instead-of-wifi.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse ESP32 on the forum