Ethernet on ESP32 using LAN8720

ESP32 LAN8720 Adapter with components

The ESP32 from Espressif features - along with a lot of other cool function blocks - an Ethernet MAC with an RMII-interface. You only have to add an Ethernet PHY, some transformers, a RJ45 connector and a few resistors and capacitors.
Espressif have published some code for the TLK110. But it is relatively expensive (around 6 EUR when bought in small quantities) and is relatively big as it has an MII-interface which is not entirely needed.
A better choice seems to be the LAN8720 which costs only 1EUR and is significantly smaller as it only has a RMII-interface an therefore lesser pins.
Robin Cutshaw and Rudi Wagner made some effort and made a pull request for the ESP-IDF.

I made a small prototype for the eBox ESP32-T and the Waveshare LAN8720 ETH Board which already has an 50MHz oscillator.

ESP32 LAN8720 Adapter bareboneAdapter board without daughter boards

The clock issue

There is one major problem with the pin configuration of the ESP32. If GPIO0 is pulled LOW during the bootup sequence the bootloader awaits serial programming. But GPIO0 is also the clock input for the EMAC function block in the ESP32.
So it has to be ensured that GPIO0 is held HIGH during boot and the 50MHz REFCLK is supplied just before the LAN8720 is initialised. Fortunately the 50MHz oscillator has an enable pin. When this pin is held LOW, the output is disabled. In the ESP-IDF firmware GPIO17 is already used als PHY_POWER which is an input during boot and then recofigured as output and set HIGH. To make sure the enable pin of the oscillator is LOW during bootup a 4.7kΩ pulldown resistor has to be added. But the disabled clock output needs an additional 4.7kΩ pullup resistor to make sure GPIO0 is in HIGH state.
On the LAN8720 board the is an unused pin on the pinheader marked NC which can easily be used to connect the clock-enable pin of the oscillator with GPIO17.

Modifications to the Waveshare-LAN8720Waveshare LAN8720 with clock enable modification

The connections needed

GPIO17 - PHY_POWER   : NC - Osc. Enable - 4k7 Pulldown
GPIO22 - EMAC_TXD1   : TX1
GPIO19 - EMAC_TXD0   : TX0
GPIO21 - EMAC_TX_EN  : TX_EN
GPIO26 - EMAC_RXD1   : RX1
GPIO25 - EMAC_RXD0   : RX0
GPIO27 - EMAC_RX_DV  : CRS
GPIO00 - EMAC_TX_CLK : nINT/REFCLK (50MHz) - 4k7 Pullup
GPIO23 - SMI_MDC     : MDC
GPIO18 - SMI_MDIO    : MDIO
GND                  : GND
3V3                  : VCC

PHY_POWER, SMI_MDC and SMI_MDIO can freely be moved to other GPIOs.

EMAC_TXD0, EMAC_TXD1, EMAC_TX_EN, EMAC_RXD0, EMAC_RXD1, EMAC_RX_DV and EMAC_TX_CLK are fixed and can't be rerouted to other GPIOs.

ESP32 LAN8720 Adapter bottom viewBottom view of adapter board with pin references

LAN8720 bootstrap config on the Waveshare board

The LAN8720 on the Waveshare board is bootstraped to use I²C address 1. So you have to configure the ESP-IDF to access the LAN8720 as PHY1 config.phy_addr = PHY1;.