Ethernet

[中文]

Overview

ESP-IDF provides a set of consistent and flexible APIs to support both internal Ethernet MAC (EMAC) controller and external SPI-Ethernet modules.

This programming guide is split into the following sections:

Basic Ethernet Concepts

Ethernet is an asynchronous Carrier Sense Multiple Access with Collision Detect (CSMA/CD) protocol/interface. It is generally not well suited for low power applications. However, with ubiquitous deployment, internet connectivity, high data rates and limitless rage expandability, Ethernet can accommodate nearly all wired communications.

Normal IEEE 802.3 compliant Ethernet frames are between 64 and 1518 bytes in length. They are made up of five or six different fields: a destination MAC address (DA), a source MAC address (SA), a type/length field, data payload, an optional padding field and a Cyclic Redundancy Check (CRC). Additionally, when transmitted on the Ethernet medium, a 7-byte preamble field and Start-of-Frame (SOF) delimiter byte are appended to the beginning of the Ethernet packet.

Thus the traffic on the twist-pair cabling will appear as shown blow:

Ethernet Data Frame Format

Preamble and Start-of-Frame Delimiter

The preamble contains seven bytes of 55H, it allows the receiver to lock onto the stream of data before the actual frame arrives. The Start-of-Frame Delimiter (SFD) is a binary sequence 10101011 (as seen on the physical medium). It is sometimes considered to be part of the preamble.

When transmitting and receiving data, the preamble and SFD bytes will automatically be generated or stripped from the packets.

Destination Address

The destination address field contains a 6-byte length MAC address of the device that the packet is directed to. If the Least Significant bit in the first byte of the MAC address is set, the address is a multi-cast destination. For example, 01-00-00-00-F0-00 and 33-45-67-89-AB-CD are multi-cast addresses, while 00-00-00-00-F0-00 and 32-45-67-89-AB-CD are not. Packets with multi-cast destination addresses are designed to arrive and be important to a selected group of Ethernet nodes. If the destination address field is the reserved multi-cast address, i.e. FF-FF-FF-FF-FF-FF, the packet is a broadcast packet and it will be directed to everyone sharing the network. If the Least Significant bit in the first byte of the MAC address is clear, the address is a uni-cast address and will be designed for usage by only the addressed node.

Normally the EMAC controller incorporates receive filters which can be used to discard or accept packets with multi-cast, broadcast and/or uni-cast destination addresses. When transmitting packets, the host controller is responsible for writing the desired destination address into the transmit buffer.

Source Address

The source address field contains a 6-byte length MAC address of the node which created the Ethernet packet. Users of Ethernet must generate a unique MAC address for each controller used. MAC addresses consist of two portions. The first three bytes are known as the Organizationally Unique Identifier (OUI). OUIs are distributed by the IEEE. The last three bytes are address bytes at the discretion of the company that purchased the OUI. More information about MAC Address used in ESP-IDF, please see MAC Address Allocation.

When transmitting packets, the assigned source MAC address must be written into the transmit buffer by the host controller.

Type / Length

The type/length field is a 2-byte field, if the value in this field is <= 1500 (decimal), it is considered a length field and it specifies the amount of non-padding data which follows in the data field. If the value is >= 1536, it represents the protocol the following packet data belongs to. The following are the most common type values:

  • IPv4 = 0800H

  • IPv6 = 86DDH

  • ARP = 0806H

Users implementing proprietary networks may choose to treat this field as a length field, while applications implementing protocols such as the Internet Protocol (IP) or Address Resolution Protocol (ARP), should program this field with the appropriate type defined by the protocol’s specification when transmitting packets.

Payload

The payload field is a variable length field, anywhere from 0 to 1500 bytes. Larger data packets will violate Ethernet standards and will be dropped by most Ethernet nodes. This field contains the client data, such as an IP datagram.

Padding and FCS

The padding field is a variable length field added to meet IEEE 802.3 specification requirements when small data payloads are used. The DA, SA, type, payload and padding of an Ethernet packet must be no smaller than 60 bytes. Adding the required 4-byte FCS field, packets must be no smaller than 64 bytes. If the data field is less than 46 bytes long, a padding field is required.

The FCS field is a 4-byte field which contains an industry standard 32-bit CRC calculated with the data from the DA, SA, type, payload and padding fields. Given the complexity of calculating a CRC, the hardware normally will automatically generate a valid CRC and transmit it. Otherwise, the host controller must generate the CRC and place it in the transmit buffer.

Normally, the host controller does not need to concern itself with padding and the CRC which the hardware EMAC will also be able to automatically generate when transmitting and verify when receiving. However, the padding and CRC fields will be written into the receive buffer when packets arrive, so they may be evaluated by the host controller if needed.

Note

Besides the basic data frame described above, there’re two other common frame types in 10/100 Mbps Ethernet: control frames and VLAN tagged frames. They’re not supported in ESP-IDF.

Configure MAC and PHY

Ethernet driver is composed of two parts: MAC and PHY.

We need to setup necessary parameters for MAC and PHY respectively based on your Ethernet board design and then combine the two together, completing the driver installation.

Configuration for MAC is described in eth_mac_config_t, including:

Configuration for PHY is described in eth_phy_config_t, including:

  • eth_phy_config_t::phy_addr: multiple PHY device can share the same SMI bus, so each PHY needs a unique address. Usually this address is configured during hardware design by pulling up/down some PHY strapping pins. You can set the value from 0 to 15 based on your Ethernet board. Especially, if the SMI bus is shared by only one PHY device, setting this value to -1 can enable the driver to detect the PHY address automatically.

  • eth_phy_config_t::reset_timeout_ms: reset timeout value, in milliseconds, typically PHY reset should be finished within 100ms.

  • eth_phy_config_t::autonego_timeout_ms: auto-negotiation timeout value, in milliseconds. Ethernet driver will start negotiation with the peer Ethernet node automatically, to determine to duplex and speed mode. This value usually depends on the ability of the PHY device on your board.

  • eth_phy_config_t::reset_gpio_num: if your board also connect the PHY reset pin to one of the GPIO, then set it here. Otherwise, set this field to -1.

ESP-IDF provides a default configuration for MAC and PHY in macro ETH_MAC_DEFAULT_CONFIG and ETH_PHY_DEFAULT_CONFIG.

Create MAC and PHY Instance

Ethernet driver is implemented in an Object-Oriented style. Any operation on MAC and PHY should be based on the instance of them two.

SPI-Ethernet Module

eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();      // apply default MAC configuration
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();      // apply default PHY configuration
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;           // alter the PHY address according to your board design
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; // alter the GPIO used for PHY reset
// Install GPIO interrupt service (as the SPI-Ethernet module is interrupt driven)
gpio_install_isr_service(0);
// SPI bus configuration
spi_device_handle_t spi_handle = NULL;
spi_bus_config_t buscfg = {
    .miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
    .mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
    .sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
    .quadwp_io_num = -1,
    .quadhd_io_num = -1,
};
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
// Allocate SPI device from the bus
spi_device_interface_config_t devcfg = {
    .command_bits = 1,
    .address_bits = 7,
    .mode = 0,
    .clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
    .spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
    .queue_size = 20
};
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
/* dm9051 ethernet driver is based on spi driver */
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);

Note

  • When creating MAC and PHY instance for SPI-Ethernet modules (e.g. DM9051), the constructor function must have the same suffix (e.g. esp_eth_mac_new_dm9051 and esp_eth_phy_new_dm9051). This is because we don’t have other choices but the integrated PHY.

  • We have to create an SPI device handle firstly and then pass it to the MAC constructor function. More instructions on creating SPI device handle, please refer to SPI Master.

  • The SPI device configuration (i.e. spi_device_interface_config_t) can be different for other Ethernet modules. Please check out your module’s spec and the examples in esp-idf.

Install Driver

To install the Ethernet driver, we need to combine the instance of MAC and PHY and set some additional high-level configurations (i.e. not specific to either MAC or PHY) in esp_eth_config_t:

  • esp_eth_config_t::mac: instance that created from MAC generator (e.g. esp_eth_mac_new_esp32()).

  • esp_eth_config_t::phy: instance that created from PHY generator (e.g. esp_eth_phy_new_ip101()).

  • esp_eth_config_t::check_link_period_ms: Ethernet driver starts an OS timer to check the link status periodically, this field is used to set the interval, in milliseconds.

  • esp_eth_config_t::stack_input: In most of Ethernet IoT applications, any Ethernet frame that received by driver should be passed to upper layer (e.g. TCP/IP stack). This field is set to a function which is responsible to deal with the incoming frames. You can even update this field at runtime via function esp_eth_update_input_path() after driver installation.

  • esp_eth_config_t::on_lowlevel_init_done and esp_eth_config_t::on_lowlevel_deinit_done: These two fields are used to specify the hooks which get invoked when low level hardware has been initialized or de-initialized.

ESP-IDF provides a default configuration for driver installation in macro ETH_DEFAULT_CONFIG.

esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
esp_eth_driver_install(&config, &eth_handle); // install driver

Ethernet driver also includes event-driven model, which will send useful and important event to user space. We need to initialize the event loop before installing the Ethernet driver. For more information about event-driven programming, please refer to ESP Event.

/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
                              int32_t event_id, void *event_data)
{
    uint8_t mac_addr[6] = {0};
    /* we can get the ethernet driver handle from event data */
    esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;

    switch (event_id) {
    case ETHERNET_EVENT_CONNECTED:
        esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
        ESP_LOGI(TAG, "Ethernet Link Up");
        ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
                    mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
        break;
    case ETHERNET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "Ethernet Link Down");
        break;
    case ETHERNET_EVENT_START:
        ESP_LOGI(TAG, "Ethernet Started");
        break;
    case ETHERNET_EVENT_STOP:
        ESP_LOGI(TAG, "Ethernet Stopped");
        break;
    default:
        break;
    }
}

esp_event_loop_create_default(); // create a default event loop that running in background
esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL); // register Ethernet event handler (to deal with user specific stuffs when event like link up/down happened)

Start Ethernet Driver

After driver installation, we can start Ethernet immediately.

esp_eth_start(eth_handle); // start Ethernet driver state machine

Connect Driver to TCP/IP Stack

Up until now, we have installed the Ethernet driver. From the view of OSI (Open System Interconnection), we’re still on level 2 (i.e. Data Link Layer). We can detect link up and down event, we can gain MAC address in user space, but we can’t obtain IP address, let alone send HTTP request. The TCP/IP stack used in ESP-IDF is called LwIP, for more information about it, please refer to LwIP.

To connect Ethernet driver to TCP/IP stack, these three steps need to follow:

  1. Create network interface for Ethernet driver

  2. Attach the network interface to Ethernet driver

  3. Register IP event handlers

More information about network interface, please refer to Network Interface.

/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
                                 int32_t event_id, void *event_data)
{
    ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
    const esp_netif_ip_info_t *ip_info = &event->ip_info;

    ESP_LOGI(TAG, "Ethernet Got IP Address");
    ESP_LOGI(TAG, "~~~~~~~~~~~");
    ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
    ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
    ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
    ESP_LOGI(TAG, "~~~~~~~~~~~");
}

esp_netif_init()); // Initialize TCP/IP network interface (should be called only once in application)
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); // apply default network interface configuration for Ethernet
esp_netif_t *eth_netif = esp_netif_new(&cfg); // create network interface for Ethernet driver

esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); // attach Ethernet driver to TCP/IP stack
esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL); // register user defined IP event handlers
esp_eth_start(eth_handle); // start Ethernet driver state machine

Warning

It is recommended to fully initialize the Ethernet driver and network interface prior registering user’s Ethernet/IP event handlers, i.e. register the event handlers as the last thing prior starting the Ethernet driver. Such approach ensures that Ethernet/IP events get executed first by the Ethernet driver or network interface and so the system is in expected state when executing user’s handlers.

Misc control of Ethernet driver

The following functions should only be invoked after the Ethernet driver has been installed.

  • Stop Ethernet driver: esp_eth_stop()

  • Update Ethernet data input path: esp_eth_update_input_path()

  • Misc get/set of Ethernet driver attributes: esp_eth_ioctl()

/* get MAC address */
uint8_t mac_addr[6];
memset(mac_addr, 0, sizeof(mac_addr));
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
         mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

/* get PHY address */
int phy_addr = -1;
esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr);
ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr);

Flow control

Ethernet on MCU usually has a limitation in the number of frames it can handle during network congestion, because of the limitation in RAM size. A sending station might be transmitting data faster than the peer end can accept it. Ethernet flow control mechanism allows the receiving node to signal the sender requesting suspension of transmissions until the receiver catches up. The magic behind that is the pause frame, which was defined in IEEE 802.3x.

Pause frame is a special Ethernet frame used to carry the pause command, whose EtherType field is 0x8808, with the Control opcode set to 0x0001. Only stations configured for full-duplex operation may send pause frames. When a station wishes to pause the other end of a link, it sends a pause frame to the 48-bit reserved multicast address of 01-80-C2-00-00-01. The pause frame also includes the period of pause time being requested, in the form of a two-byte integer, ranging from 0 to 65535.

After Ethernet driver installation, the flow control feature is disabled by default. You can enable it by:

bool flow_ctrl_enable = true;
esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, &flow_ctrl_enable);

One thing should be kept in mind, is that the pause frame ability will be advertised to peer end by PHY during auto negotiation. Ethernet driver sends pause frame only when both sides of the link support it.

Application Example

API Reference

Functions

esp_err_t esp_eth_detect_phy_addr(esp_eth_mediator_t *eth, int *detected_addr)

Detect PHY address.

Parameters
  • eth[in] mediator of Ethernet driver

  • detected_addr[out] a valid address after detection

Returns

  • ESP_OK: detect phy address successfully

  • ESP_ERR_INVALID_ARG: invalid parameter

  • ESP_ERR_NOT_FOUND: can’t detect any PHY device

  • ESP_FAIL: detect phy address failed because some error occurred

Structures

struct esp_eth_mediator_s

Ethernet mediator.

Public Members

esp_err_t (*phy_reg_read)(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)

Read PHY register.

Param eth

[in] mediator of Ethernet driver

Param phy_addr

[in] PHY Chip address (0~31)

Param phy_reg

[in] PHY register index code

Param reg_value

[out] PHY register value

Return

  • ESP_OK: read PHY register successfully

  • ESP_FAIL: read PHY register failed because some error occurred

esp_err_t (*phy_reg_write)(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)

Write PHY register.

Param eth

[in] mediator of Ethernet driver

Param phy_addr

[in] PHY Chip address (0~31)

Param phy_reg

[in] PHY register index code

Param reg_value

[in] PHY register value

Return

  • ESP_OK: write PHY register successfully

  • ESP_FAIL: write PHY register failed because some error occurred

esp_err_t (*stack_input)(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length)

Deliver packet to upper stack.

Param eth

[in] mediator of Ethernet driver

Param buffer

[in] packet buffer

Param length

[in] length of the packet

Return

  • ESP_OK: deliver packet to upper stack successfully

  • ESP_FAIL: deliver packet failed because some error occurred

esp_err_t (*on_state_changed)(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args)

Callback on Ethernet state changed.

Param eth

[in] mediator of Ethernet driver

Param state

[in] new state

Param args

[in] optional argument for the new state

Return

  • ESP_OK: process the new state successfully

  • ESP_FAIL: process the new state failed because some error occurred

Type Definitions

typedef struct esp_eth_mediator_s esp_eth_mediator_t

Ethernet mediator.

Enumerations

enum esp_eth_state_t

Ethernet driver state.

Values:

enumerator ETH_STATE_LLINIT

Lowlevel init done

enumerator ETH_STATE_DEINIT

Deinit done

enumerator ETH_STATE_LINK

Link status changed

enumerator ETH_STATE_SPEED

Speed updated

enumerator ETH_STATE_DUPLEX

Duplex updated

enumerator ETH_STATE_PAUSE

Pause ability updated

enum eth_event_t

Ethernet event declarations.

Values:

enumerator ETHERNET_EVENT_START

Ethernet driver start

enumerator ETHERNET_EVENT_STOP

Ethernet driver stop

enumerator ETHERNET_EVENT_CONNECTED

Ethernet got a valid link

enumerator ETHERNET_EVENT_DISCONNECTED

Ethernet lost a valid link

Unions

union eth_mac_clock_config_t
#include <esp_eth_mac.h>

Ethernet MAC Clock Configuration.

Public Members

struct eth_mac_clock_config_t::[anonymous] mii

EMAC MII Clock Configuration

emac_rmii_clock_mode_t clock_mode

RMII Clock Mode Configuration

emac_rmii_clock_gpio_t clock_gpio

RMII Clock GPIO Configuration

struct eth_mac_clock_config_t::[anonymous] rmii

EMAC RMII Clock Configuration

Structures

struct esp_eth_mac_s

Ethernet MAC.

Public Members

esp_err_t (*set_mediator)(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)

Set mediator for Ethernet MAC.

Param mac

[in] Ethernet MAC instance

Param eth

[in] Ethernet mediator

Return

  • ESP_OK: set mediator for Ethernet MAC successfully

  • ESP_ERR_INVALID_ARG: set mediator for Ethernet MAC failed because of invalid argument

esp_err_t (*init)(esp_eth_mac_t *mac)

Initialize Ethernet MAC.

Param mac

[in] Ethernet MAC instance

Return

  • ESP_OK: initialize Ethernet MAC successfully

  • ESP_ERR_TIMEOUT: initialize Ethernet MAC failed because of timeout

  • ESP_FAIL: initialize Ethernet MAC failed because some other error occurred

esp_err_t (*deinit)(esp_eth_mac_t *mac)

Deinitialize Ethernet MAC.

Param mac

[in] Ethernet MAC instance

Return

  • ESP_OK: deinitialize Ethernet MAC successfully

  • ESP_FAIL: deinitialize Ethernet MAC failed because some error occurred

esp_err_t (*start)(esp_eth_mac_t *mac)

Start Ethernet MAC.

Param mac

[in] Ethernet MAC instance

Return

  • ESP_OK: start Ethernet MAC successfully

  • ESP_FAIL: start Ethernet MAC failed because some other error occurred

esp_err_t (*stop)(esp_eth_mac_t *mac)

Stop Ethernet MAC.

Param mac

[in] Ethernet MAC instance

Return

  • ESP_OK: stop Ethernet MAC successfully

  • ESP_FAIL: stop Ethernet MAC failed because some error occurred

esp_err_t (*transmit)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)

Transmit packet from Ethernet MAC.

Note

Returned error codes may differ for each specific MAC chip.

Param mac

[in] Ethernet MAC instance

Param buf

[in] packet buffer to transmit

Param length

[in] length of packet

Return

  • ESP_OK: transmit packet successfully

  • ESP_ERR_INVALID_SIZE: number of actually sent bytes differs to expected

  • ESP_FAIL: transmit packet failed because some other error occurred

esp_err_t (*transmit_vargs)(esp_eth_mac_t *mac, uint32_t argc, va_list args)

Transmit packet from Ethernet MAC constructed with special parameters at Layer2.

Note

Typical intended use case is to make possible to construct a frame from multiple higher layer buffers without a need of buffer reallocations. However, other use cases are not limited.

Note

Returned error codes may differ for each specific MAC chip.

Param mac

[in] Ethernet MAC instance

Param argc

[in] number variable arguments

Param args

[in] variable arguments

Return

  • ESP_OK: transmit packet successfully

  • ESP_ERR_INVALID_SIZE: number of actually sent bytes differs to expected

  • ESP_FAIL: transmit packet failed because some other error occurred

esp_err_t (*receive)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)

Receive packet from Ethernet MAC.

Note

Memory of buf is allocated in the Layer2, make sure it get free after process.

Note

Before this function got invoked, the value of “length” should set by user, equals the size of buffer. After the function returned, the value of “length” means the real length of received data.

Param mac

[in] Ethernet MAC instance

Param buf

[out] packet buffer which will preserve the received frame

Param length

[out] length of the received packet

Return

  • ESP_OK: receive packet successfully

  • ESP_ERR_INVALID_ARG: receive packet failed because of invalid argument

  • ESP_ERR_INVALID_SIZE: input buffer size is not enough to hold the incoming data. in this case, value of returned “length” indicates the real size of incoming data.

  • ESP_FAIL: receive packet failed because some other error occurred

esp_err_t (*read_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)

Read PHY register.

Param mac

[in] Ethernet MAC instance

Param phy_addr

[in] PHY chip address (0~31)

Param phy_reg

[in] PHY register index code

Param reg_value

[out] PHY register value

Return

  • ESP_OK: read PHY register successfully

  • ESP_ERR_INVALID_ARG: read PHY register failed because of invalid argument

  • ESP_ERR_INVALID_STATE: read PHY register failed because of wrong state of MAC

  • ESP_ERR_TIMEOUT: read PHY register failed because of timeout

  • ESP_FAIL: read PHY register failed because some other error occurred

esp_err_t (*write_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)

Write PHY register.

Param mac

[in] Ethernet MAC instance

Param phy_addr

[in] PHY chip address (0~31)

Param phy_reg

[in] PHY register index code

Param reg_value

[in] PHY register value

Return

  • ESP_OK: write PHY register successfully

  • ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC

  • ESP_ERR_TIMEOUT: write PHY register failed because of timeout

  • ESP_FAIL: write PHY register failed because some other error occurred

esp_err_t (*set_addr)(esp_eth_mac_t *mac, uint8_t *addr)

Set MAC address.

Param mac

[in] Ethernet MAC instance

Param addr

[in] MAC address

Return

  • ESP_OK: set MAC address successfully

  • ESP_ERR_INVALID_ARG: set MAC address failed because of invalid argument

  • ESP_FAIL: set MAC address failed because some other error occurred

esp_err_t (*get_addr)(esp_eth_mac_t *mac, uint8_t *addr)

Get MAC address.

Param mac

[in] Ethernet MAC instance

Param addr

[out] MAC address

Return

  • ESP_OK: get MAC address successfully

  • ESP_ERR_INVALID_ARG: get MAC address failed because of invalid argument

  • ESP_FAIL: get MAC address failed because some other error occurred

esp_err_t (*set_speed)(esp_eth_mac_t *mac, eth_speed_t speed)

Set speed of MAC.

Param ma:c

[in] Ethernet MAC instance

Param speed

[in] MAC speed

Return

  • ESP_OK: set MAC speed successfully

  • ESP_ERR_INVALID_ARG: set MAC speed failed because of invalid argument

  • ESP_FAIL: set MAC speed failed because some other error occurred

esp_err_t (*set_duplex)(esp_eth_mac_t *mac, eth_duplex_t duplex)

Set duplex mode of MAC.

Param mac

[in] Ethernet MAC instance

Param duplex

[in] MAC duplex

Return

  • ESP_OK: set MAC duplex mode successfully

  • ESP_ERR_INVALID_ARG: set MAC duplex failed because of invalid argument

  • ESP_FAIL: set MAC duplex failed because some other error occurred

esp_err_t (*set_link)(esp_eth_mac_t *mac, eth_link_t link)

Set link status of MAC.

Param mac

[in] Ethernet MAC instance

Param link

[in] Link status

Return

  • ESP_OK: set link status successfully

  • ESP_ERR_INVALID_ARG: set link status failed because of invalid argument

  • ESP_FAIL: set link status failed because some other error occurred

esp_err_t (*set_promiscuous)(esp_eth_mac_t *mac, bool enable)

Set promiscuous of MAC.

Param mac

[in] Ethernet MAC instance

Param enable

[in] set true to enable promiscuous mode; set false to disable promiscuous mode

Return

  • ESP_OK: set promiscuous mode successfully

  • ESP_FAIL: set promiscuous mode failed because some error occurred

esp_err_t (*enable_flow_ctrl)(esp_eth_mac_t *mac, bool enable)

Enable flow control on MAC layer or not.

Param mac

[in] Ethernet MAC instance

Param enable

[in] set true to enable flow control; set false to disable flow control

Return

  • ESP_OK: set flow control successfully

  • ESP_FAIL: set flow control failed because some error occurred

esp_err_t (*set_peer_pause_ability)(esp_eth_mac_t *mac, uint32_t ability)

Set the PAUSE ability of peer node.

Param mac

[in] Ethernet MAC instance

Param ability

[in] zero indicates that pause function is supported by link partner; non-zero indicates that pause function is not supported by link partner

Return

  • ESP_OK: set peer pause ability successfully

  • ESP_FAIL: set peer pause ability failed because some error occurred

esp_err_t (*custom_ioctl)(esp_eth_mac_t *mac, uint32_t cmd, void *data)

Custom IO function of MAC driver. This function is intended to extend common options of esp_eth_ioctl to cover specifics of MAC chip.

Note

This function may not be assigned when the MAC chip supports only most common set of configuration options.

Param mac

[in] Ethernet MAC instance

Param cmd

[in] IO control command

Param data

[inout] address of data for set command or address where to store the data when used with get command

Return

  • ESP_OK: process io command successfully

  • ESP_ERR_INVALID_ARG: process io command failed because of some invalid argument

  • ESP_FAIL: process io command failed because some other error occurred

  • ESP_ERR_NOT_SUPPORTED: requested feature is not supported

esp_err_t (*del)(esp_eth_mac_t *mac)

Free memory of Ethernet MAC.

Param mac

[in] Ethernet MAC instance

Return

  • ESP_OK: free Ethernet MAC instance successfully

  • ESP_FAIL: free Ethernet MAC instance failed because some error occurred

struct eth_mac_config_t

Configuration of Ethernet MAC object.

Public Members

uint32_t sw_reset_timeout_ms

Software reset timeout value (Unit: ms)

uint32_t rx_task_stack_size

Stack size of the receive task

uint32_t rx_task_prio

Priority of the receive task

uint32_t flags

Flags that specify extra capability for mac driver

Macros

ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE

MAC driver can work when cache is disabled

ETH_MAC_FLAG_PIN_TO_CORE

Pin MAC task to the CPU core where driver installation happened

ETH_MAC_DEFAULT_CONFIG()

Default configuration for Ethernet MAC object.

Type Definitions

typedef struct esp_eth_mac_s esp_eth_mac_t

Ethernet MAC.

Enumerations

enum emac_rmii_clock_mode_t

RMII Clock Mode Options.

Values:

enumerator EMAC_CLK_DEFAULT

Default values configured using Kconfig are going to be used when “Default” selected.

enumerator EMAC_CLK_EXT_IN

Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected.

Note

MAC will get RMII clock from outside. Note that ESP32 only supports GPIO0 to input the RMII clock.

enumerator EMAC_CLK_OUT

Output RMII Clock from internal APLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected.

enum emac_rmii_clock_gpio_t

RMII Clock GPIO number Options.

Values:

enumerator EMAC_CLK_IN_GPIO

MAC will get RMII clock from outside at this GPIO.

Note

ESP32 only supports GPIO0 to input the RMII clock.

enumerator EMAC_APPL_CLK_OUT_GPIO

Output RMII Clock from internal APLL Clock available at GPIO0.

Note

GPIO0 can be set to output a pre-divided PLL clock (test only!). Enabling this option will configure GPIO0 to output a 50MHz clock. In fact this clock doesn’t have directly relationship with EMAC peripheral. Sometimes this clock won’t work well with your PHY chip. You might need to add some extra devices after GPIO0 (e.g. inverter). Note that outputting RMII clock on GPIO0 is an experimental practice. If you want the Ethernet to work with WiFi, don’t select GPIO0 output mode for stability.

enumerator EMAC_CLK_OUT_GPIO

Output RMII Clock from internal APLL Clock available at GPIO16.

enumerator EMAC_CLK_OUT_180_GPIO

Inverted Output RMII Clock from internal APLL Clock available at GPIO17.

Functions

esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)

Create a PHY instance of IP101.

Parameters

config[in] configuration of PHY

Returns

  • instance: create PHY instance successfully

  • NULL: create PHY instance failed because some error occurred

esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)

Create a PHY instance of RTL8201.

Parameters

config[in] configuration of PHY

Returns

  • instance: create PHY instance successfully

  • NULL: create PHY instance failed because some error occurred

esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config)

Create a PHY instance of LAN87xx.

Parameters

config[in] configuration of PHY

Returns

  • instance: create PHY instance successfully

  • NULL: create PHY instance failed because some error occurred

esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)

Create a PHY instance of DP83848.

Parameters

config[in] configuration of PHY

Returns

  • instance: create PHY instance successfully

  • NULL: create PHY instance failed because some error occurred

esp_eth_phy_t *esp_eth_phy_new_ksz80xx(const eth_phy_config_t *config)

Create a PHY instance of KSZ80xx.

The phy model from the KSZ80xx series is detected automatically. If the driver is unable to detect a supported model, NULL is returned.

Currently, the following models are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041, KSZ8051, KSZ8061, KSZ8081, KSZ8091

Parameters

config[in] configuration of PHY

Returns

  • instance: create PHY instance successfully

  • NULL: create PHY instance failed because some error occurred

Structures

struct esp_eth_phy_s

Ethernet PHY.

Public Members

esp_err_t (*set_mediator)(esp_eth_phy_t *phy, esp_eth_mediator_t *mediator)

Set mediator for PHY.

Param phy

[in] Ethernet PHY instance

Param mediator

[in] mediator of Ethernet driver

Return

  • ESP_OK: set mediator for Ethernet PHY instance successfully

  • ESP_ERR_INVALID_ARG: set mediator for Ethernet PHY instance failed because of some invalid arguments

esp_err_t (*reset)(esp_eth_phy_t *phy)

Software Reset Ethernet PHY.

Param phy

[in] Ethernet PHY instance

Return

  • ESP_OK: reset Ethernet PHY successfully

  • ESP_FAIL: reset Ethernet PHY failed because some error occurred

esp_err_t (*reset_hw)(esp_eth_phy_t *phy)

Hardware Reset Ethernet PHY.

Note

Hardware reset is mostly done by pull down and up PHY’s nRST pin

Param phy

[in] Ethernet PHY instance

Return

  • ESP_OK: reset Ethernet PHY successfully

  • ESP_FAIL: reset Ethernet PHY failed because some error occurred

esp_err_t (*init)(esp_eth_phy_t *phy)

Initialize Ethernet PHY.

Param phy

[in] Ethernet PHY instance

Return

  • ESP_OK: initialize Ethernet PHY successfully

  • ESP_FAIL: initialize Ethernet PHY failed because some error occurred

esp_err_t (*deinit)(esp_eth_phy_t *phy)

Deinitialize Ethernet PHY.

Param phy

[in] Ethernet PHY instance

Return

  • ESP_OK: deinitialize Ethernet PHY successfully

  • ESP_FAIL: deinitialize Ethernet PHY failed because some error occurred

esp_err_t (*autonego_ctrl)(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)

Configure auto negotiation.

Param phy

[in] Ethernet PHY instance

Param cmd

[in] Configuration command, it is possible to Enable (restart), Disable or get current status of PHY auto negotiation

Param autonego_en_stat

[out] Address where to store current status of auto negotiation configuration

Return

  • ESP_OK: restart auto negotiation successfully

  • ESP_FAIL: restart auto negotiation failed because some error occurred

  • ESP_ERR_INVALID_ARG: invalid command

esp_err_t (*get_link)(esp_eth_phy_t *phy)

Get Ethernet PHY link status.

Param phy

[in] Ethernet PHY instance

Return

  • ESP_OK: get Ethernet PHY link status successfully

  • ESP_FAIL: get Ethernet PHY link status failed because some error occurred

esp_err_t (*pwrctl)(esp_eth_phy_t *phy, bool enable)

Power control of Ethernet PHY.

Param phy

[in] Ethernet PHY instance

Param enable

[in] set true to power on Ethernet PHY; ser false to power off Ethernet PHY

Return

  • ESP_OK: control Ethernet PHY power successfully

  • ESP_FAIL: control Ethernet PHY power failed because some error occurred

esp_err_t (*set_addr)(esp_eth_phy_t *phy, uint32_t addr)

Set PHY chip address.

Param phy

[in] Ethernet PHY instance

Param addr

[in] PHY chip address

Return

  • ESP_OK: set Ethernet PHY address successfully

  • ESP_FAIL: set Ethernet PHY address failed because some error occurred

esp_err_t (*get_addr)(esp_eth_phy_t *phy, uint32_t *addr)

Get PHY chip address.

Param phy

[in] Ethernet PHY instance

Param addr

[out] PHY chip address

Return

  • ESP_OK: get Ethernet PHY address successfully

  • ESP_ERR_INVALID_ARG: get Ethernet PHY address failed because of invalid argument

esp_err_t (*advertise_pause_ability)(esp_eth_phy_t *phy, uint32_t ability)

Advertise pause function supported by MAC layer.

Param phy

[in] Ethernet PHY instance

Param addr

[out] Pause ability

Return

  • ESP_OK: Advertise pause ability successfully

  • ESP_ERR_INVALID_ARG: Advertise pause ability failed because of invalid argument

esp_err_t (*loopback)(esp_eth_phy_t *phy, bool enable)

Sets the PHY to loopback mode.

Param phy

[in] Ethernet PHY instance

Param enable

[in] enables or disables PHY loopback

Return

  • ESP_OK: PHY instance loopback mode has been configured successfully

  • ESP_FAIL: PHY instance loopback configuration failed because some error occurred

esp_err_t (*set_speed)(esp_eth_phy_t *phy, eth_speed_t speed)

Sets PHY speed mode.

Note

Autonegotiation feature needs to be disabled prior to calling this function for the new setting to be applied

Param phy

[in] Ethernet PHY instance

Param speed

[in] Speed mode to be set

Return

  • ESP_OK: PHY instance speed mode has been configured successfully

  • ESP_FAIL: PHY instance speed mode configuration failed because some error occurred

esp_err_t (*set_duplex)(esp_eth_phy_t *phy, eth_duplex_t duplex)

Sets PHY duplex mode.

Note

Autonegotiation feature needs to be disabled prior to calling this function for the new setting to be applied

Param phy

[in] Ethernet PHY instance

Param duplex

[in] Duplex mode to be set

Return

  • ESP_OK: PHY instance duplex mode has been configured successfully

  • ESP_FAIL: PHY instance duplex mode configuration failed because some error occurred

esp_err_t (*custom_ioctl)(esp_eth_phy_t *phy, uint32_t cmd, void *data)

Custom IO function of PHY driver. This function is intended to extend common options of esp_eth_ioctl to cover specifics of PHY chip.

Note

This function may not be assigned when the PHY chip supports only most common set of configuration options.

Param phy

[in] Ethernet PHY instance

Param cmd

[in] IO control command

Param data

[inout] address of data for set command or address where to store the data when used with get command

Return

  • ESP_OK: process io command successfully

  • ESP_ERR_INVALID_ARG: process io command failed because of some invalid argument

  • ESP_FAIL: process io command failed because some other error occurred

  • ESP_ERR_NOT_SUPPORTED: requested feature is not supported

esp_err_t (*del)(esp_eth_phy_t *phy)

Free memory of Ethernet PHY instance.

Param phy

[in] Ethernet PHY instance

Return

  • ESP_OK: free PHY instance successfully

  • ESP_FAIL: free PHY instance failed because some error occurred

struct eth_phy_config_t

Ethernet PHY configuration.

Public Members

int32_t phy_addr

PHY address, set -1 to enable PHY address detection at initialization stage

uint32_t reset_timeout_ms

Reset timeout value (Unit: ms)

uint32_t autonego_timeout_ms

Auto-negotiation timeout value (Unit: ms)

int reset_gpio_num

Reset GPIO number, -1 means no hardware reset

Macros

ESP_ETH_PHY_ADDR_AUTO
ETH_PHY_DEFAULT_CONFIG()

Default configuration for Ethernet PHY object.

Type Definitions

typedef struct esp_eth_phy_s esp_eth_phy_t

Ethernet PHY.

Enumerations

enum eth_phy_autoneg_cmd_t

Auto-negotiation controll commands.

Values:

enumerator ESP_ETH_PHY_AUTONEGO_RESTART
enumerator ESP_ETH_PHY_AUTONEGO_EN
enumerator ESP_ETH_PHY_AUTONEGO_DIS
enumerator ESP_ETH_PHY_AUTONEGO_G_STAT

Functions

esp_eth_netif_glue_handle_t esp_eth_new_netif_glue(esp_eth_handle_t eth_hdl)

Create a netif glue for Ethernet driver.

Note

netif glue is used to attach io driver to TCP/IP netif

Parameters

eth_hdl – Ethernet driver handle

Returns

glue object, which inherits esp_netif_driver_base_t

esp_err_t esp_eth_del_netif_glue(esp_eth_netif_glue_handle_t eth_netif_glue)

Delete netif glue of Ethernet driver.

Parameters

eth_netif_glue – netif glue

Returns

-ESP_OK: delete netif glue successfully

Type Definitions

typedef struct esp_eth_netif_glue_t *esp_eth_netif_glue_handle_t

Handle of netif glue - an intermediate layer between netif and Ethernet driver.