ESP-IDF 以太网驱动开发指南:从 IEEE 802.3 帧格式到 esp_eth 驱动安装与 TCP/IP 接入 ESP-IDF 以太网驱动开发指南从 IEEE 802.3 帧格式到 esp_eth 驱动安装与 TCP/IP 接入【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf本指南基于 ESP-IDF 官方编程指南 docs/en/api-reference/network/esp_eth.rst 编写系统讲解 ESP-IDF 以太网Ethernet驱动的完整开发流程从以太网帧格式等基础概念到内部 EMAC 与 SPI-Ethernet 模块的 MAC/PHY 配置、驱动安装、事件处理、接入 LwIP TCP/IP 协议栈再到硬件时间戳PTP、流量控制等进阶能力。读完本文你将能够基于 ESP-IDF 从零配置并驱动一块以太网 PHY 芯片让设备通过有线网络获得可 Ping 通的 IP 地址。OverviewESP-IDF 以太网驱动概览ESP-IDF 提供了一组一致且灵活的 API用于同时支持内部以太网 MAC 控制器EMAC与外部 SPI-Ethernet 模块。对于内部集成 EMAC 的芯片驱动同时涵盖 MAC 与 PHY 两层对于仅支持外部模块的芯片驱动则专注于 SPI-Ethernet 模块。整个编程指南按以下四个部分组织Basic Ethernet Concepts —— 以太网基础概念Driver Configuration and Installation —— 驱动配置与安装Connect Driver to Stack —— 将驱动接入 TCP/IP 协议栈Misc Operation of Driver —— 驱动杂项控制。在 components/esp_eth 组件中include/目录下的头文件定义了全部公共 APIesp_eth.h、esp_eth_driver.h、esp_eth_mac.h、esp_eth_mac_esp.h、esp_eth_phy.h、esp_eth_com.h、esp_eth_netif_glue.h等src/目录则包含 MACmac/、PHYphy/与驱动核心esp_eth.c的实现。以太网基础概念理解 IEEE 802.3 帧结构以太网是一种异步的载波侦听多路访问/冲突检测CSMA/CD协议。它虽不适合低功耗应用但因部署广泛、接入互联网便捷、数据速率高、可无限扩展距离等优势几乎可以承载所有有线通信需求。符合 IEEE 802.3 规范的以太网帧长度为64 到 1518 字节由五或六个字段组成字段长度说明DA目的 MAC 地址6 字节帧要送达的节点 MAC 地址SA源 MAC 地址6 字节产生该帧的节点 MAC 地址Type/Length类型/长度2 字节协议类型或数据长度Payload数据负载0~1500 字节客户端数据如 IP 数据报Padding填充可变使帧达到最小长度要求FCS帧校验序列4 字节32 位 CRC 校验值此外帧在物理介质上传输时其开头还会附加7 字节前导码Preamble与帧起始定界符SFDStart-of-Frame Delimiter。以太网双绞线上的流量结构如下原文档配图为 docs/_static/diagrams/ethernet/data_frame_format.diag。前导码与帧起始定界符前导码包含7 个字节的55H用于让接收端在实际帧到来之前锁定数据流。SFD 是在物理介质上呈现的二进制序列10101011有时被视为前导码的一部分。收发数据时前导码与 SFD 会被硬件自动生成或剥离。目的地址DA目的地址字段包含 6 字节的目标节点 MAC 地址。若 MAC 地址首字节的最低位为 1则为组播multicast地址。例如01-00-00-00-F0-00和33-45-67-89-AB-CD是组播地址而00-00-00-00-F0-00和32-45-67-89-AB-CD不是。若目的地址为保留组播地址FF-FF-FF-FF-FF-FF则该帧是广播broadcast帧会送达网络中所有节点若首字节最低位为 0则为单播unicast地址仅由被寻址的节点使用。EMAC 控制器通常内置接收过滤器可丢弃或接收具有组播、广播和/或单播目的地址的帧。发送时主机控制器负责把目的地址写入发送缓冲区。源地址SA源地址字段包含 6 字节的源节点 MAC 地址。每个控制器都需要唯一的 MAC 地址它由两部分组成前 3 字节为组织唯一标识符OUIOrganizationally Unique Identifier由 IEEE 分配后 3 字节为购买 OUI 的公司自行分配的地址字节。关于 ESP-IDF 中的 MAC 地址分配策略可参考 MAC 地址分配文档。类型/长度字段这是 2 字节字段若值≤ 1500十进制则视为长度字段表示数据字段中非填充数据的数量若值≥ 1536则表示数据所属的协议类型。常见类型值IPv4 0800H、IPv6 86DDH、ARP 0806H。实现私有网络的用户可把该字段当作长度字段而实现 IP、ARP 等协议的应用发送时应按协议规范写入相应类型值。负载Payload负载字段长度可变为0 到 1500 字节。更大的数据包违反以太网标准会被大多数以太网节点丢弃。该字段包含客户端数据例如 IP 数据报。填充与 FCS填充字段长度可变用于在数据负载较小时满足 IEEE 802.3 规范要求DA、SA、Type、Payload 与 Padding 合计不得小于 60 字节加上 4 字节 FCS 后帧不得小于 64 字节当 Payload 小于 46 字节时必须填充FCS 是 4 字节字段包含基于 DA、SA、Type、Payload、Padding 计算的业界标准 32 位 CRC。鉴于 CRC 计算的复杂度硬件通常会自动生成并发送有效 CRC否则主机控制器必须自行计算并写入发送缓冲区。通常主机控制器无需关心填充与 CRC——硬件 EMAC 在发送时自动生成、接收时自动校验。但帧到达时填充与 CRC 字段会写入接收缓冲区因此主机控制器需要时也可读取评估。注意除了上述基本数据帧10/100 Mbps 以太网还有另外两种常见帧类型控制帧与VLAN 标记帧这两种类型在 ESP-IDF 中不支持。配置 MAC 与 PHY驱动安装前的关键参数以太网驱动由MAC与PHY两部分组成。MAC 与 PHY 之间的通信有多种接口选择MIIMedia Independent Interface介质无关接口、RMIIReduced Media Independent Interface精简介质无关接口等。MII 与 RMII 最明显的差异是信号数量MII 通常最多占用18 根信号线而 RMII 可将消耗降至9 根。ESP-IDF 仅支持 RMII 接口因此eth_esp32_emac_config_t::interface必须始终设置为EMAC_DATA_INTERFACE_RMII。RMII 参考时钟REF_CLK的三种生成方式在 RMII 模式下收发信号都以REF_CLK为基准。对 PHY 与 MAC 的任何访问期间REF_CLK必须保持稳定。根据电路设计通常有三种生成REF_CLK的方式方式时钟来源clock_config.rmii.clock_mode配置aPHY 芯片从其外部 25 MHz 晶振衍生REF_CLKEMAC_CLK_EXT_INbPHY 使用外部 50 MHz 晶振或其他时钟源作为 MAC 侧的REF_CLKEMAC_CLK_EXT_INcEMAC 控制器使用内部高精度 PLL 生成REF_CLKEMAC_CLK_OUT无论选择哪种模式硬件设计上都必须重视REF_CLK 的信号完整性走线尽量短远离射频器件与电感元件。ESP32 上的特殊注意事项若配置为EMAC_CLK_OUT内部Audio PLLAPLL被用作 50 MHz 时钟源需确保不与 I2S 总线配置冲突此时GPIO0可直接输出REF_CLK该时钟直接输出到 GPIO与 EMAC 外设无直接关系某些 PHY 下可能工作不佳若设计中未使用 PSRAMGPIO16和GPIO17也可输出参考时钟来源同为 APLL但从 EMAC 外设路由。若配置为EMAC_CLK_EXT_INGPIO0是输入REF_CLK的唯一选择。注意GPIO0 是 ESP32 的重要 strapping 引脚上电时若采样到低电平ESP32 会进入下载模式系统将停滞直至手动复位。规避方法是默认在硬件上禁用REF_CLK不干扰 boot 阶段 strapping然后在以太网驱动安装阶段重新使能。禁用方式包括禁用或断电晶振方式 b、强制 PHY 复位方式 a但部分 PHY 即使处于复位状态仍会向 GPIO0 输出信号此方法可能失效。若希望以太网与 Wi-Fi 或蓝牙共存不要选择 ESP32 作为REF_CLK来源会导致REF_CLK不稳定。应禁用 Wi-Fi或使用 PHY / 外部晶振作为REF_CLK源。ESP32-P4 的 MPLL 限制ESP32-P4 上若配置为EMAC_CLK_OUTEMAC 通过整数分频器从MPLL衍生 50 MHz RMII 参考时钟。当同时启用 PSRAM 时两者共享 MPLL而 PSRAM 会将其锁定到由其速度配置决定的频率。若 PSRAM 速度配置为 80 MHzCONFIG_SPIRAM_SPEEDMPLL 运行在 320 MHz而 320 MHz 不存在能在 ±50 ppm 容差内产生 50 MHz 的整数分频最接近的是 320/6 ≈ 53.33 MHz此时EMAC 初始化将失败。若必须使用 80 MHz PSRAM 速度应从外部PHY 或晶振提供REF_CLK并配置为EMAC_CLK_EXT_IN。内部时钟输出时的外部回环要求对于不支持内部回环的芯片not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK若配置为EMAC_CLK_OUTREF_CLK输出信号必须在外部回环到 EMAC需要将clock_config_out_in.clock_mode配置为EMAC_CLK_EXT_IN并选择与REF_CLK输入 GPIO 对应的 GPIO 号。数据面与控制面 GPIO 的差异对于不支持多 IO_MUX 的芯片not SOC_EMAC_USE_MULTI_IO_MUX数据面信号通过IO_MUX固定到特定 GPIO无法修改控制面信号可通过GPIO Matrix路由到任意空闲 GPIO。对于支持多 IO_MUX 的芯片SOC_EMAC_USE_MULTI_IO_MUX数据面 GPIO 可通过 IO_MUX 配置为预定义集合由驱动根据eth_esp32_emac_config_t::emac_dataif_gpio的内容完成配置控制面信号仍可通过 GPIO Matrix 自由路由。以下为不同芯片的 RMII 数据面 GPIO 预定义表由 esp_eth_mac_esp.h 中的默认配置印证引脚名称ESP32ESP32-P4TX_ENGPIO21GPIO33、GPIO40、GPIO49TXD0GPIO19GPIO34、GPIO41TXD1GPIO22GPIO35、GPIO42CRS_DVGPIO27GPIO28、GPIO45、GPIO51RXD0GPIO25GPIO29、GPIO46、GPIO52RXD1GPIO26GPIO30、GPIO47、GPIO53REF_CLK输入 GPIOESP32 为 GPIO0ESP32-P4 为 GPIO32、GPIO44、GPIO50REF_CLK输出 GPIOESP32 为 GPIO0/GPIO16/GPIO17ESP32-P4 为 GPIO23、GPIO39。MAC 层通用配置eth_mac_config_tMAC 层通用配置在eth_mac_config_t中描述定义见 esp_eth_mac.h配置项说明sw_reset_timeout_ms软件复位超时值毫秒。MAC 复位通常在 100 ms 内完成rx_task_stack_sizeMAC 驱动会创建专用任务处理入包此参数设置该任务的栈大小rx_task_prio上述接收任务的优先级flags指定 MAC 驱动的额外特性可与ETH_MAC_FLAG_前缀的宏按位或。例如需要 MAC 驱动在缓存禁用时也能工作可配置ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE内部 MAC 专用配置eth_esp32_emac_config_t针对内部 MAC 模块的配置在eth_esp32_emac_config_t中描述定义见 esp_eth_mac_esp.h配置项说明smi_gpio.mdc_num/smi_gpio.mdio_num连接 SMI 信号MDC/MDIO的 GPIO 号interfaceMAC 到 PHY 的数据接口MII/RMII必须为 RMIIclock_configEMAC 接口时钟配置RMII 下的REF_CLK模式与 GPIO 号intr_priorityMAC 中断优先级。设为 0 或负值则由驱动按默认优先级分配Low/Medium 优先级1~3可在 C 中处理emac_dataif_gpioEMAC MII/RMII 数据面 GPIO 号配置多 IO_MUX 芯片clock_config_out_in内部生成REF_CLK并外部回环时EMAC 输入接口时钟的配置模式必须始终为EMAC_CLK_EXT_IN仅当clock_config为EMAC_CLK_OUT时有效dma_burst_lenEMAC DMA 突发长度Tx/Rxmdc_freq_hzEMAC MDC 频率上限0 或负值时驱动将 CSR 时钟范围设为最高 2.5 MHz以 ESP32 为例ETH_ESP32_EMAC_DEFAULT_CONFIG()默认配置为MDCGPIO23、MDIOGPIO18、接口 RMII、EMAC_CLK_EXT_IN且 clock_gpio0、DMA 突发长度 32、中断优先级 0。内部 MAC 的 DMA 内存考量内部 MAC 子系统通过 DMA 以描述符链表方式与 CPU 域交换数据描述符分发送Transmit与接收Receive两类每类描述符保存帧的状态信息或提供传输控制并包含指向当前数据缓冲区与下一描述符的指针。单个 EMAC DMA 描述符在 DMA 内存中占32 字节ESP32-P4 因内存对齐需要实际占 64 字节。默认配置可覆盖大多数场景但以下情况可能需要调整短而频繁的帧占主导的网络流量尽管额定 100 Mbps仍可能出现吞吐量低于预期、接收丢帧发送时 socket API 返回errno ENOMEM并伴随insufficient TX buffer size日志调试级别。原因是默认内存配置面向较大帧优化——CONFIG_ETH_DMA_BUFFER_SIZE默认为 512 字节以取得更好的数据缓冲区/描述符开销比。解决办法是增大CONFIG_ETH_DMA_RX_BUFFER_NUM或CONFIG_ETH_DMA_TX_BUFFER_NUM并可考虑减小CONFIG_ETH_DMA_BUFFER_SIZE以匹配网络中的典型帧大小。高吞吐导致缓冲区耗尽若发送间歇性返回ENOMEM且吞吐接近额定 100 Mbps说明接近硬件极限硬件无法跟上发送请求。应增大CONFIG_ETH_DMA_TX_BUFFER_NUM以缓冲更多帧、缓解瞬时发送峰值。但这无法解决持续超额定吞吐的场景此时只能在应用层通过软件限制带宽。相关配置项在 components/esp_eth/Kconfig 中定义ETH_DMA_BUFFER_SIZE范围 256~1600默认 512ESP32-P4/S31 需 64 字节对齐、ETH_DMA_RX_BUFFER_NUM范围 3~30ESP32 默认 10其余默认 20、ETH_DMA_TX_BUFFER_NUM范围 3~30默认 10当 RX 缓冲区数大于 15 时还可启用ETH_SOFT_FLOW_CONTROL软件流控。PHY 层配置eth_phy_config_tPHY 配置在eth_phy_config_t中描述定义见 esp_eth_phy.h配置项说明phy_addrPHY 地址范围 0~15。多个 PHY 可共享同一 SMI 总线故每个 PHY 需唯一地址通常由硬件 strapping 引脚决定。若 SMI 总线仅挂一个 PHY设为-1ESP_ETH_PHY_ADDR_AUTO可让驱动自动探测地址reset_timeout_msPHY 复位超时值毫秒通常在 100 ms 内完成autonego_timeout_ms自动协商超时值毫秒。驱动会自动与对端协商双工与速率模式具体取决于板载 PHY 能力reset_gpio_numPHY 复位引脚 GPIO未连接则设为-1hw_reset_assert_time_usPHY 复位引脚断言时间微秒设为 0 使用芯片默认时序post_hw_reset_delay_ms硬件复位完成后的等待时间毫秒0 使用芯片默认-1ESP_ETH_NO_POST_HW_RESET_DELAY不等待ESP-IDF 通过宏ETH_MAC_DEFAULT_CONFIG()与ETH_PHY_DEFAULT_CONFIG()提供 MAC 与 PHY 的默认配置。ETH_PHY_DEFAULT_CONFIG()默认phy_addr -1自动探测、reset_timeout_ms 100、autonego_timeout_ms 4000、reset_gpio_num 5。创建 MAC 与 PHY 实例以太网驱动采用面向对象风格实现对 MAC 与 PHY 的任何操作都基于二者的实例。MAC 与 PHY 的构造函数成对使用例如esp_eth_mac_new_esp32与esp_eth_phy_new_generic。内部 EMAC 外部 PHYeth_mac_config_t mac_config ETH_MAC_DEFAULT_CONFIG(); // 应用默认通用 MAC 配置 eth_esp32_emac_config_t esp32_emac_config ETH_ESP32_EMAC_DEFAULT_CONFIG(); // 应用默认厂商专属 MAC 配置 esp32_emac_config.smi_gpio.mdc_num CONFIG_ETHERNET_MDC_GPIO; // 修改 MDC 信号 GPIO esp32_emac_config.smi_gpio.mdio_num CONFIG_ETHERNET_MDIO_GPIO; // 修改 MDIO 信号 GPIO esp_eth_mac_t *mac esp_eth_mac_new_esp32(esp32_emac_config, mac_config); // 创建 MAC 实例 eth_phy_config_t phy_config ETH_PHY_DEFAULT_CONFIG(); // 应用默认 PHY 配置 phy_config.phy_addr CONFIG_ETHERNET_PHY_ADDR; // 按板卡设计修改 PHY 地址 phy_config.reset_gpio_num CONFIG_ETHERNET_PHY_RST_GPIO; // 修改 PHY 复位 GPIO esp_eth_phy_t *phy esp_eth_phy_new_generic(phy_config); // 创建通用 PHY 实例注意使用esp_eth_phy_new_generic创建实例时任何符合 IEEE 802.3 的 PHY 芯片均可使用。但基础功能虽总是可用部分特定特性如回环功能某些 PHY 需设置特定速率模式才能正确工作可能受限。若需要针对芯片定制的驱动可使用 ESP-IDF 官方支持的 PHY 驱动或参考下文自定义 PHY 驱动章节自行开发。可选运行时 MAC 时钟配置。EMAC 的REF_CLK也可在用户应用代码中配置eth_esp32_emac_config_t esp32_emac_config ETH_ESP32_EMAC_DEFAULT_CONFIG(); // 应用默认厂商专属 MAC 配置 // ... esp32_emac_config.interface EMAC_DATA_INTERFACE_RMII; // 修改 EMAC 数据接口 esp32_emac_config.clock_config.rmii.clock_mode EMAC_CLK_OUT; // 选择 EMAC REF_CLK 模式 esp32_emac_config.clock_config.rmii.clock_gpio 17; // 选择 EMAC REF_CLK 输入/输出 GPIO esp_eth_mac_t *mac esp_eth_mac_new_esp32(esp32_emac_config, mac_config); // 创建 MAC 实例SPI-Ethernet 模块eth_mac_config_t mac_config ETH_MAC_DEFAULT_CONFIG(); // 应用默认通用 MAC 配置 eth_phy_config_t phy_config ETH_PHY_DEFAULT_CONFIG(); // 应用默认 PHY 配置 phy_config.phy_addr CONFIG_ETHERNET_PHY_ADDR; // 按板卡设计修改 PHY 地址 phy_config.reset_gpio_num CONFIG_ETHERNET_PHY_RST_GPIO; // 修改 PHY 复位 GPIO // 安装 GPIO 中断服务SPI-Ethernet 模块为中断驱动 gpio_install_isr_service(0); // SPI 总线配置 spi_device_handle_t spi_handle NULL; spi_bus_config_t buscfg { .miso_io_num CONFIG_ETHERNET_SPI_MISO_GPIO, .mosi_io_num CONFIG_ETHERNET_SPI_MOSI_GPIO, .sclk_io_num CONFIG_ETHERNET_SPI_SCLK_GPIO, .quadwp_io_num -1, .quadhd_io_num -1, }; ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_ETHERNET_SPI_HOST, buscfg, 1)); // 配置 SPI 设备 spi_device_interface_config_t spi_devcfg { .mode 0, .clock_speed_hz CONFIG_ETHERNET_SPI_CLOCK_MHZ * 1000 * 1000, .spics_io_num CONFIG_ETHERNET_SPI_CS_GPIO, .queue_size 20 }; /* dm9051 以太网驱动基于 SPI 驱动 */ eth_dm9051_config_t dm9051_config ETH_DM9051_DEFAULT_CONFIG(CONFIG_ETHERNET_SPI_HOST, spi_devcfg); dm9051_config.int_gpio_num CONFIG_ETHERNET_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);注意为 SPI-Ethernet 模块如 DM9051创建 MAC 与 PHY 实例时构造函数必须具有相同后缀如esp_eth_mac_new_dm9051与esp_eth_phy_new_dm9051因为模块集成了 PHY别无选择SPI 设备配置spi_device_interface_config_t可能因模块或 PCB 的 SPI 时序要求而异请查阅模块规格书与 ESP-IDF 示例。安装驱动组合 MAC 与 PHY安装以太网驱动需要将 MAC 与 PHY 实例组合并在esp_eth_config_t中设置额外的高层配置定义见 esp_eth_driver.h配置项说明mac由 MAC 构造器创建的实例如esp_eth_mac_new_esp32phy由 PHY 构造器创建的实例如esp_eth_phy_new_genericcheck_link_period_ms驱动启动 OS 定时器周期性检查链路状态此字段设置间隔毫秒stack_input/stack_input_info大多数 IoT 应用中驱动接收到的帧应上交上层如 TCP/IP 协议栈。此字段设置为处理入帧的函数。驱动安装后还可通过esp_eth_update_input_path在运行时更新。stack_input_info变体可额外携带帧信息时间戳、CRC 校验结果等on_lowlevel_init_done/on_lowlevel_deinit_done底层硬件初始化/去初始化完成时调用的钩子read_phy_reg/write_phy_regPHY 寄存器读写函数通常由 MACSMI 接口提供若 PHY 由其他接口如 I2C管理则需用户实现置 NULL 表示由 MAC 的 SMI 接口管理ETH_DEFAULT_CONFIG(emac, ephy)提供默认配置check_link_period_ms 2000安装代码如下esp_eth_config_t config ETH_DEFAULT_CONFIG(mac, phy); // 应用默认驱动配置 esp_eth_handle_t eth_handle NULL; // 驱动安装后获得驱动句柄 esp_eth_driver_install(config, eth_handle); // 安装驱动以太网驱动还包含事件驱动模型会向用户空间发送有用事件。需要在安装驱动前初始化事件循环详见 ESP Event 文档/** 以太网事件处理器 */ 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}; /* 可从事件数据中获取以太网驱动句柄 */ 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(); // 创建后台运行的默认事件循环 esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL); // 注册以太网事件处理器事件类型定义于 esp_eth_com.h 的eth_event_tETHERNET_EVENT_START、ETHERNET_EVENT_STOP、ETHERNET_EVENT_CONNECTED、ETHERNET_EVENT_DISCONNECTED事件基为ETH_EVENT。驱动内部通过esp_eth_mediator_t的on_state_changed回调感知链路、速率、双工等状态变化再转换为上层事件。启动以太网驱动驱动安装完成后可立即启动esp_eth_start(eth_handle); // 启动以太网驱动状态机esp_eth_start在独立模式即不接 TCP/IP 协议栈下启动驱动状态机与内部软件定时器用于周期性检查链路状态。将驱动接入 TCP/IP 协议栈至此我们仍处于 OSI 第二层数据链路层虽可在用户空间检测链路上下事件、获取 MAC 地址但无法获得 IP 地址更不用说发送 HTTP 请求。ESP-IDF 使用的 TCP/IP 协议栈是LwIP详见 LwIP 文档。将以太网驱动接入 TCP/IP 协议栈需三步为以太网驱动创建网络接口esp_netif将网络接口附加到以太网驱动注册 IP 事件处理器。网络接口相关请参考 esp_netif 文档。/** 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()); // 初始化 TCP/IP 网络接口应用中只应调用一次 esp_netif_config_t cfg ESP_NETIF_DEFAULT_ETH(); // 应用以太网默认网络接口配置 esp_netif_t *eth_netif esp_netif_new(cfg); // 为以太网驱动创建网络接口 esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); // 将以太网驱动附加到 TCP/IP 协议栈 esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler, NULL); // 注册用户 IP 事件处理器 esp_eth_start(eth_handle); // 启动以太网驱动状态机警告建议在注册用户的以太网/IP 事件处理器之前完整初始化以太网驱动与网络接口——即把事件处理器的注册作为启动以太网驱动前的最后一步。这样可确保以太网/IP 事件先由驱动或网络接口处理用户处理器执行时系统处于预期状态。完整的应用实现可参考 examples/ethernet/basic/main/ethernet_example_main.c其中eth_init()完整展示了默认配置初始化、PHY 地址/复位引脚覆盖、RMII 时钟模式与数据面 GPIO 配置含SOC_EMAC_USE_MULTI_IO_MUX分支app_main()则展示了 netif 创建、esp_eth_new_netif_glue粘合、事件注册与esp_eth_start的完整调用序列并支持在运行指定秒数后停止并反初始化整个网络演示esp_eth_stop、esp_eth_del_netif_glue、esp_netif_destroy、esp_eth_driver_uninstall等清理流程。以太网驱动的杂项控制以下函数应在以太网驱动安装后调用停止驱动esp_eth_stop更新以太网数据输入路径esp_eth_update_input_path驱动属性杂项读写esp_eth_ioctl/* 获取 MAC 地址 */ 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]); /* 获取 PHY 地址 */ 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);esp_eth_ioctl支持的常用命令完整列表见 esp_eth_driver.h 中的esp_eth_io_cmd_tETH_CMD_G/S_MAC_ADDR获取/设置 MAC 地址6 字节缓冲区ETH_CMD_G/S_PHY_ADDR获取/设置 PHY 地址0~31uint32_tETH_CMD_G/S_AUTONEGO获取/启用/禁用自动协商bool设置前需停止驱动ETH_CMD_G/S_SPEED、ETH_CMD_G/S_DUPLEX_MODE获取/设置速率与双工模式设置前需停止驱动并禁用自动协商ETH_CMD_S_PROMISCUOUS设置混杂模式boolETH_CMD_S_FLOW_CTRL设置流控boolETH_CMD_S_PHY_LOOPBACKPHY 回环boolETH_CMD_READ/WRITE_PHY_REG读写 PHY 寄存器esp_eth_phy_reg_rw_data_tETH_CMD_S_ALL_MULTICAST、ETH_CMD_ADD/DEL_MAC_FILTER组播接收与 MAC 过滤ETH_CMD_CUSTOM_MAC_CMDS/ETH_CMD_CUSTOM_PHY_CMDSMAC/PHY 自定义命令起始偏移0x0FFF/0x1FFF见 esp_eth_com.h。此外esp_eth_transmit/esp_eth_transmit_ctrl_vargs提供通用发送能力后者支持从多个缓冲区零拷贝组帧并通过ctrl参数传递帧附加控制信息esp_eth_increase_reference/esp_eth_decrease_reference提供引用计数保护防止多任务场景下驱动被意外卸载。EMAC 硬件时间戳PTP时间戳相关 API 目前处于**实验特性**状态可能随未来版本变化。EMAC 硬件时间戳可精确跟踪以太网帧的收发时刻对PTPPrecision Time Protocol精确时间协议等应用至关重要——硬件内嵌时间戳可避免软件层延迟与处理开销带来的抖动实现纳秒级精度。基本使能与时间读写esp_eth_mac_t *mac; esp_eth_get_mac_instance(eth_hndl, mac); // 使能硬件时间戳 eth_mac_ptp_config_t ptp_cfg ETH_MAC_ESP_PTP_DEFAULT_CONFIG(); esp_eth_mac_ptp_enable(mac, ptp_cfg); // 获取当前 EMAC 时间 eth_mac_time_t ptp_time; esp_eth_mac_get_ptp_time(mac, ptp_time); // 设置 EMAC 时间 ptp_time { .seconds 42, .nanoseconds 0 }; esp_eth_mac_set_ptp_time(mac, ptp_time);PTP 模块配置项eth_mac_ptp_config_t见 esp_eth_mac_esp.h配置项说明clk_srcPTP 时钟源从soc_periph_emac_ptp_clk_src_t枚举中选择clk_src_period_nsPTP 时钟源周期纳秒。例如 40 MHz 时钟源周期为 25 nsrequired_accuracy_nsPTP 所需精度纳秒必须劣于 PTP 时钟源如 40 MHz/25 ns 时钟对应 40 nsroll_type亚秒寄存器的翻转模式数字或二进制。推荐二进制翻转模式可提供更精确的时间同步ETH_MAC_ESP_PTP_DEFAULT_CONFIG()默认EMAC_PTP_CLK_SRC_XTAL、周期 25 ns、精度 40 ns、ETH_PTP_BINARY_ROLLOVER。收发帧的时间戳可通过esp_eth_config_t::stack_input_info回调的最后一个参数接收路径与esp_eth_transmit_ctrl_vargs的ctrl参数发送路径获取更友好的用户态获取方式是使用 L2 TAP 的扩展缓冲区机制。还可通过注册回调并配置目标时间在精确时刻触发事件回调在 ISR 上下文执行应尽量简短// 注册回调函数 esp_eth_mac_set_target_time_cb(mac, ts_callback); // 设置事件触发时间 eth_mac_time_t mac_target_time { .seconds 42, .nanoseconds 0 }; esp_eth_mac_set_target_time(mac, mac_target_time);PTP 同步时间还可通过 GPIO 上的PPS每秒脉冲Pulse-Per-Second信号对外输出为外部设备提供精确硬件时间基准。PPS 默认每秒一个脉冲可通过esp_eth_mac_set_pps_out_freq调整输出频率取值 0~163840 1PPS 窄脉冲其他值产生方波时钟信号频率必须为 2 的幂且 ≤ 16384 Hz注意数字翻转模式下因位非线性翻转实际频率为平均值一秒周期内占空比偏离 50%二进制翻转模式不受此影响因此推荐使用。PPS 输出引脚用esp_eth_mac_set_pps_out_gpio配置ESP32-P4 从硅片修订版本 3 起支持 GPIO 输出 PPS。相关应用可参考 examples/ethernet/ptp。流量控制Flow ControlMCU 上的以太网受 RAM 容量限制在网络拥塞时可处理的帧数有限。以太网流控机制允许接收节点向发送方发出暂停请求直至接收方跟上其核心是IEEE 802.3x 定义的暂停帧Pause Frame。暂停帧是承载暂停命令的特殊以太网帧EtherType 为0x8808控制操作码为0x0001。仅全双工节点可发送暂停帧需要暂停链路对端时向保留组播地址01-80-C2-00-00-01发送暂停帧帧中包含 0~65535 的暂停时间2 字节整数。驱动安装后流控特性默认禁用可通过以下方式启用bool flow_ctrl_enable true; esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, flow_ctrl_enable);需要留意暂停帧能力由 PHY 在自动协商阶段向对端通告因此驱动仅在链路两端都支持时才发送暂停帧。另外在 components/esp_eth/Kconfig 中当ETH_DMA_RX_BUFFER_NUM 15时可启用ETH_SOFT_FLOW_CONTROL——ESP32 的 MAC 引擎本身不具备流控逻辑MAC 驱动可执行软件流控注意 RX 缓冲区数量较小时启用会带来明显性能损失。应用示例ESP-IDF 提供以下以太网相关示例examples/ethernet/basic演示驱动安装、附加到 esp_netif、发送 DHCP 请求并获取可 Ping 通的 IP 地址examples/ethernet/iperf使用 iPerf 测量以太网吞吐量/带宽examples/ethernet/ptp演示通过以太网进行 PTP 时间同步examples/network/vlan_support演示在以太网上创建虚拟网络接口含 VLAN 与非 VLANexamples/network/sta2eth演示使用 Wi-Fi 站点与有线接口以太网或 USB建立 1 对 1 桥接examples/network/simple_sniffer演示使用 Wi-Fi 与以太网混杂模式抓包并保存为 PCAP 格式examples/network/eth2ap演示以太网端口与 Wi-Fi AP 接口间的报文转发桥1 对多连接不初始化 TCP/IP 协议栈examples/network/bridge演示使用 LwIP IEEE 802.1D 桥基于 MAC 地址在多网段间转发以太网帧大多数examples/protocols协议示例同样适用于以太网。进阶主题自定义 PHY 驱动市场上 PHY 厂商众多、芯片型号繁杂。ESP-IDF 支持 Generic PHY 及若干特定 PHY 芯片但可能因价格、特性、供货等原因都不满足实际需求。幸运的是IEEE 802.3 第 22.2.4 节管理功能标准化了 EMAC 与 PHY 之间的管理接口MII Management Interface定义了一组管理寄存器用于控制芯片行为、链路属性与自动协商配置等。这套基础管理功能在 ESP-IDF 中由 components/esp_eth/src/phy/esp_eth_phy_802_3.c 实现使得创建新的自定义 PHY 驱动相当简单。注意部分 PHY 芯片可能不完全符合 IEEE 802.3 第 22.2.4 节请始终查阅 PHY 数据手册。这不代表无法创建自定义 PHY 驱动只是需要更多工作必须自行定义全部 PHY 管理函数。ESP-IDF 以太网驱动所需的大部分 PHY 管理功能由esp_eth_phy_802_3.c覆盖但以下内容可能需要开发芯片专属的管理函数链路状态——几乎总是芯片相关的芯片初始化——虽非严格必需但至少应自定义以确认使用的是预期芯片芯片专属特性配置。创建自定义 PHY 驱动的步骤基于 PHY 数据手册定义厂商专属寄存器布局准备派生的 PHY 管理对象信息结构其必须包含父级 IEEE 802.3 对象phy_802_3_t并可选包含支持非 IEEE 802.3 或定制功能所需的附加变量定义芯片专属管理回调函数初始化父级 IEEE 802.3 对象并重新指派芯片专属管理回调函数。在 components/esp_eth/src/phy/esp_eth_phy_generic.c 中可以看到esp_eth_phy_new_generic如何基于esp_eth_phy_802_3.c的基础实现构建通用 PHY 实例。完成新驱动后可考虑通过 ESP Component Registry 与其他用户共享。总结驱动生命周期全景以太网驱动的完整生命周期可归纳为配置 MAC/PHY → 创建实例 → 安装驱动组合 MACPHY→ 注册事件 → 创建并附加 esp_netif → 启动 → 运行期 ioctl 控制 → 停止/卸载。整个流程涉及的关键头文件均在 components/esp_eth/include 下Kconfig 配置项在 components/esp_eth/Kconfig而 examples/ethernet/basic/main/ethernet_example_main.c 提供了开箱即用的完整参考实现。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考