拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ESP-IDF 以太网驱动开发指南:从 IEEE 802.3 帧格式到 EMAC/PHY 配置、TCP/IP 对接与高级功能

ESP-IDF 以太网驱动开发指南从 IEEE 802.3 帧格式到 EMAC/PHY 配置、TCP/IP 对接与高级功能【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf以太网是 ESP-IDF 中最可靠的有线网络接入方案。本文以 docs/zh_CN/api-reference/network/esp_eth.rst 为核心骨架系统讲解 ESP-IDF 以太网驱动esp_eth组件的使用全流程从 IEEE 802.3 帧结构、内部 EMAC 与外部 PHY 的配置安装、SPI-Ethernet 模块接入、与 LwIP/TCP-IP 协议栈对接到时间戳、流量控制等高级功能并深入 components/esp_eth 源码印证底层实现。读完本文你将能够基于开发板实际硬件完成以太网驱动的实例化、安装、事件处理、协议栈挂载与吞吐量调优。概述ESP-IDF 提供一系列灵活度高且兼具一致性的 API为内部以太网 MACEMAC控制器和外部 SPI-Ethernet 模块提供支持。编程指南分为四个部分以太网基本概念、驱动程序配置与安装、连接驱动程序至 TCP/IP 协议栈、驱动程序的杂项控制即本文后续四个主章节。以太网基本概念以太网是一种异步的带冲突检测的载波侦听多路访问CSMA/CD协议/接口。通常来说以太网不太适用于低功耗应用然而得益于其广泛的部署、高效的网络连接、高数据率以及范围不限的可扩展性几乎所有的有线通信都可以通过以太网进行。符合 IEEE 802.3 标准的正常以太网帧长度在 64 至 1518 字节之间由五个或六个字段组成目的 MAC 地址DA、源 MAC 地址SA、类型/长度字段、数据有效载荷字段、可选的填充字段和帧校验序列字段CRC。此外数据包在以太网上传输时开头需附加 7 字节前导码和 1 字节帧起始符SOF双绞线上的帧格式如下所示原图见 docs/_static/diagrams/ethernet/data_frame_format.diag前导码与帧起始符前导码包含 7 字节的55H作用是使接收器在实际帧到达之前锁定数据流。帧前界定符SFD为二进制序列10101011物理介质层可见有时也被视作前导码的一部分。传输和接收数据时协议会自动从数据包中生成/移除前导码和帧起始符。目的地址DA6 字节长的设备 MAC 地址。若 MAC 地址第一个字节中的最低有效位为 1则为组播地址如01-00-00-F0-00、33-45-67-89-AB-CD若为保留组播地址FF-FF-FF-FF-FF-FF则为广播数据包指向共享网络中的每个节点若最低有效位为 0则为单播地址。EMAC 控制器通常集成接收过滤器用于丢弃或接收带组播、广播和/或单播目的地址的数据包传输时由主机控制器将目标地址写入传输缓冲区。源地址SA6 字节长的节点 MAC 地址。MAC 地址前三个字节为组织唯一标识符OUI由 IEEE 分配后三个字节由购买 OUI 的公司配置。ESP-IDF 中的 MAC 地址分配策略可参考 ESP-IDF 的 MAC 地址分配相关文档。传输时由主机控制器将分配的源 MAC 地址写入传输缓冲区。类型/长度字段2 字节。若值 ≤ 1500则表示为长度字段指定数据字段后的非填充数据量若值 ≥ 1536则表示后续数据包所属的协议。常见值IPv4 0800HIPv6 86DDHARP 0806H。使用专有网络的用户可以将其配置为长度字段而使用 IP/ARP 等协议的应用程序应将其配置为协议规范定义的类型。数据有效载荷可变长度字段01500 字节。更大的数据包会因违反以太网标准而被大多数节点丢弃该字段包含客户端数据如 IP 数据报。填充及帧校验序列FCS数据有效载荷较小时添加填充字段以满足 IEEE 802.3 要求——DA、SA、类型、数据有效载荷和填充字段共计必须不小于 60 字节加上 4 字节 FCS 后数据包长度不小于 64 字节即有效载荷小于 46 字节时需要填充。FCS 字段为 4 字节含根据 DA、SA、类型、数据有效载荷和填充字段计算的 32 位 CRC硬件通常自动生成/验证但数据包到达时填充字段与 CRC 会被写入接收缓冲区主机控制器也可评估。注意除基本数据帧外10/100 Mbps 以太网中还有控制帧和 VLAN 标记帧两种常见帧类型ESP-IDF 不支持这两种帧类型。配置 MAC 和 PHY以太网驱动器由 MAC 和 PHY 两部分组成。MAC 与 PHY 之间的通信可通过多种方式进行如MII媒体独立接口、RMII简化媒体独立接口等。MII 通常需要多达 18 个信号RMII 接口仅需 9 个信号。ESP-IDF 只支持 RMII 接口请将eth_esp32_emac_config_t::interface设置为EMAC_DATA_INTERFACE_RMII对应枚举eth_data_interface_t。在 RMII 模式下接收器和发射器信号的参考时钟为REF_CLK访问 PHY 和 MAC 时 REF_CLK 必须保持稳定。REF_CLK 的三种生成方式根据设计中 PHY 设备的特征REF_CLK可通过以下三种方式生成对应上图中 a/b/c 三个选项方案时钟来源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 的信号完整性——信号线越短越好并远离 RF 设备和电感。ESP32 平台的特殊警告EMAC_CLK_OUT模式会使用内部音频 PLLAPLL作为 50 MHz 时钟源请确保该配置不与 I2S 总线配置冲突。选择内部时钟时可用GPIO0输出REF_CLK但此时钟直接输出到 GPIO、与 EMAC 外设无直接关联可能无法很好地兼容所用 PHY 芯片若设计中未使用 PSRAM还可使用 GPIO16 和 GPIO17 输出参考时钟时钟源同为 APLL但这些信号通过 EMAC 外设引出。EMAC_CLK_EXT_IN模式只能选择GPIO0输入REF_CLK。注意GPIO0是 ESP32 上重要的 strapping 管脚——上电时若为低电平ESP32 将进入下载模式需手动复位重启。解决办法是在硬件中默认禁用REF_CLK避免 strapping 管脚在启动阶段受干扰随后在以太网驱动安装阶段重新启用。禁用方式包括禁用/关闭晶体振荡器电源方案 b强制复位 PHY 设备方案 a并不适用于所有 PHY 设备某些 PHY 即使处于复位状态仍会向 GPIO0 输出信号。与 Wi-Fi 共存如希望以太网与 Wi-Fi 一起工作不要选择 ESP32 作为REF_CLK的源会导致 REF_CLK 不稳定。可以选择禁用 Wi-Fi或使用 PHY 或外部振荡器作为 REF_CLK 的源。其他平台非 ESP32EMAC_CLK_OUT模式可通过 IO_MUX 选择 REF_CLK 输出管脚ESP32 为 GPIO0、GPIO16、GPIO17ESP32-P4 为 GPIO23、GPIO39。EMAC_CLK_EXT_IN模式可通过 IO_MUX 选择 REF_CLK 输入管脚ESP32 为 GPIO0ESP32-P4 为 GPIO32、GPIO44、GPIO50。ESP32-P4 的时钟与回环警告PSRAM 共享 MPLL若EMAC_CLK_OUTEMAC 通过整数分频器从 MPLL 获取 50 MHz RMII 参考时钟。当 PSRAM 速度配置为 80 MHzCONFIG_SPIRAM_SPEED时MPLL 运行在 320 MHz而 320 MHz 无法通过任何整数分频得到满足 ±50 ppm 容差要求的 50 MHz最接近候选值为 320/6 ≈ 53.33 MHz此配置下 EMAC 初始化将失败。若必须使用 80 MHz PSRAM 速度请通过外部时钟源PHY 或振荡器提供 REF_CLK并配置为EMAC_CLK_EXT_IN。REF_CLK 输出回环若不支持内部回环SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK未定义配置为EMAC_CLK_OUT时必须从外部将 REF_CLK 输出信号回环到 EMAC将eth_esp32_emac_config_t::clock_config_out_in中的clock_mode配置为EMAC_CLK_EXT_IN并选择与 REF_CLK 输入 GPIO 相关联的 GPIO 编号。GPIO 分配说明在未启用多 IO_MUX 的芯片上数据平面信号通过 IO_MUX 连接至特定 GPIO无法配置到其他 GPIO控制平面信号可通过矩阵路由到任何空闲 GPIO。在支持多 IO_MUX 的芯片上数据平面信号可通过 IO_MUX 配置为 RMII 预定义的 GPIO数据平面 GPIO 配置由驱动程序根据eth_esp32_emac_config_t::emac_dataif_gpio的内容执行控制平面信号仍可通过 GPIO 矩阵路由到任意空闲 GPIO。各芯片的 RMII 数据平面 GPIO 默认值如下表管脚名ESP32 GPIOESP32-P4 GPIOTX_EN2133、40、49TXD01934、41TXD12235、42CRS_DV2728、45、51RXD02529、46、52RXD12630、47、53MAC 配置eth_mac_config_tsw_reset_timeout_ms软件复位超时值毫秒。通常 MAC 复位应在 100 ms 内完成默认配置即 100 ms见 esp_eth_mac.h。rx_task_stack_size和rx_task_prioMAC 驱动会创建一个专门的任务处理传入的数据包这两个参数设置该任务的堆栈大小默认 4096 字节与优先级。flags指定 MAC 驱动支持的额外功能支持与以ETH_MAC_FLAG_为前缀的宏进行 OR 运算。例如要求 MAC 驱动在 cache 禁用时仍能正常工作可用ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE其值为(1 0)配置该字段。内部 MAC 模块配置eth_esp32_emac_config_tsmi_mdc_gpio_num和smi_mdio_gpio_num连接 SMI 信号的 GPIO 编号。interface配置到 PHY 的 MAC 数据接口MII/RMII。clock_config配置 EMAC 接口时钟RMII 模式下的 REF_CLK 模式及 GPIO 编号。intr_priorityMAC 中断优先级。设置为0或负值时驱动程序分配默认优先级否则使用给定优先级。注意只能设置低、中中断优先级1 到 3因为这样才能在 C 中处理。emac_dataif_gpio支持多 IO_MUX 的芯片EMAC MII/RMII 数据平面 GPIO 编号配置。clock_config_out_in不支持内部回环的芯片当 REF_CLK 在内部生成并从外部回环到 EMAC 时配置 EMAC 输入接口时钟。必须始终将 EMAC 的模式配置为EMAC_CLK_EXT_IN此选项仅在clock_config设置为EMAC_CLK_OUT时有效。内部 MAC 的内存注意事项内部 MAC 子系统通过 DMA 使用描述符链表在 CPU 域之间传输数据。描述符有发送和接收两种类型分别保存接收/已发送帧的状态信息或提供传输控制每个描述符还包含指向当前数据缓冲区和下一个描述符的指针。单个 EMAC DMA 描述符的大小为 32 字节ESP32ESP32-P4 由于需要适当的内存对齐实际占用 64 字节。默认配置可覆盖大多数用例但某些情况需对 DMA 内存进行配置以应对特定需求网络流量由短且频繁的帧主导时可能遇到吞吐量低于额定 100 Mbps 以及接收丢帧等问题发送时套接字 API 可能返回errno为ENOMEM并显示TX 缓冲区大小不足启用调试日志时。原因是默认内存配置针对较大帧优化——默认CONFIG_ETH_DMA_BUFFER_SIZE为 512 字节Kconfig范围 2561600ESP32-P4/S31 需注意 64B 对齐以平衡数据缓冲区与描述符大小的开销比。解决方法是增加缓冲区数量CONFIG_ETH_DMA_RX_BUFFER_NUM或CONFIG_ETH_DMA_TX_BUFFER_NUM或减小CONFIG_ETH_DMA_BUFFER_SIZE使其与网络中典型帧大小匹配从而合理控制内存占用。高吞吐量导致缓冲区耗尽时若套接字发送 API 间歇性返回ENOMEM且吞吐量接近额定 100 Mbps说明接近硬件限制硬件无法跟上传输请求。解决方法是增加CONFIG_ETH_DMA_TX_BUFFER_NUM以缓存更多帧、缓解传输请求短时峰值若请求流量持续超过额定吞吐量此方法将失效需在应用层通过软件限制带宽。从源码看DMA 缓冲区数量直接决定描述符链表的长度接收描述符数量为CONFIG_ETH_DMA_RX_BUFFER_NUM默认 20ESP32 为 10、发送描述符为CONFIG_ETH_DMA_TX_BUFFER_NUM默认 10各缓冲区以CONFIG_ETH_DMA_BUFFER_SIZE为粒度分配并支持缓存同步见 esp_eth_mac_esp_dma.c。另外当 RX 缓冲区数量大于 15 时可启用CONFIG_ETH_SOFT_FLOW_CONTROL软件流控但 RX 缓冲区数量较小时启用会带来明显性能损失。PHY 配置eth_phy_config_tphy_addr同一条 SMI 总线上可有多个 PHY 设备需分配唯一地址通常通过硬件设计时拉高/拉低 PHY strapping 管脚配置可配置值015。若 SMI 总线上仅有一个 PHY 设备配置为-1即可使驱动程序自动检测 PHY 地址对应宏ESP_ETH_PHY_ADDR_AUTO见 esp_eth_phy.h。reset_timeout_ms复位超时值毫秒通常 PHY 复位应在 100 ms 内完成默认值 100。autonego_timeout_ms自动协商超时值毫秒驱动与链路对端自协商确定最佳双工模式和速率默认值 4000通常取决于电路板上 PHY 设备的性能。reset_gpio_num若开发板将 PHY 复位管脚连接至任意 GPIO请配置该字段否则配置为-1默认值 5表示不复位。hw_reset_assert_time_usPHY 复位引脚被置为有效状态的时间微秒配置为0使用芯片默认复位时长。post_hw_reset_delay_msPHY 硬件复位完成后的等待时间毫秒0使用默认等待时长-1表示复位后不等待。ESP-IDF 在宏ETH_MAC_DEFAULT_CONFIG和ETH_PHY_DEFAULT_CONFIG中为 MAC 和 PHY 提供了默认配置通常只需在默认配置基础上按开发板设计覆盖少量字段。创建 MAC 和 PHY 实例以太网驱动以面向对象方式实现对 MAC 和 PHY 的任何操作都应基于实例。以下分两类场景说明。内部 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创建新 PHY 实例时可使用任何符合 IEEE 802.3 标准的以太网 PHY 芯片。然而尽管符合标准能提供基本功能某些特定功能可能无法完全实现例如某些 PHY 需要配置特定速度模式才能启用环回功能。遇到这种情况请使用 ESP-IDF 官方支持的 PHY 芯片驱动程序或参考下文自定义 PHY 驱动程序小节创建新的自定义驱动程序。乐鑫为多种特定以太网 PHY 芯片提供了驱动可在 esp-eth-drivers 仓库获取驱动以组件形式分发。可选的运行时 MAC 时钟配置可以通过用户应用程序代码选择性配置 EMAC 中的REF_CLKeth_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 模块SPI-Ethernet 模块如 DM9051、W5500 等将 MACPHY 集成在模块内通过 SPI 总线与主机通信适用于不带内部 EMAC 的芯片或需要外扩以太网口的场景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 ethernet driver is based on spi driver */ 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 实例时由于 PHY 集成在模块中实例创建函数的后缀须保持一致如esp_eth_mac_new_dm9051与esp_eth_phy_new_dm9051搭配使用。针对不同以太网模块或特定 PCB 上的 SPI 时序SPI 从机设备配置spi_device_interface_config_t可能略有不同具体请查看模块规格及 ESP-IDF 中的示例。在 ESP-IDF 源码中SPI 型 MAC 的实现集中在 esp_eth_mac_spi.h通用 IEEE 802.3 PHY 管理功能则在 esp_eth_phy_802_3.c 中实现。安装驱动程序安装以太网驱动程序需要结合 MAC 和 PHY 实例并在esp_eth_config_t中配置额外的高级选项即不仅限于 MAC 或 PHY 的选项mac由 MAC 生成器创建的实例如esp_eth_mac_new_esp32。phy由 PHY 生成器创建的实例如esp_eth_phy_new_generic。check_link_period_ms驱动程序启用操作系统定时器定期检查链接状态该字段设置间隔时间毫秒。stack_input或stack_input_info在大多数以太网物联网应用中驱动接收的以太网帧会被传递到上层如 TCP/IP 栈该字段为负责处理传入帧的函数。可在安装后通过esp_eth_update_input_path更新支持运行时更新。on_lowlevel_init_done和on_lowlevel_deinit_done指定钩子函数在初始化/去初始化低级别硬件时调用。ESP-IDF 在宏ETH_DEFAULT_CONFIG中为安装驱动程序提供了默认配置。安装代码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_eth_driver_install的原型声明位于 esp_eth_driver.h。以太网驱动程序包含事件驱动模型会向用户空间发送有用及重要的事件。安装以太网驱动程序之前需要首先初始化事件循环/** 以太网事件的事件处理程序 */ 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_start(eth_handle); // 启动以太网驱动程序状态机连接驱动程序至 TCP/IP 协议栈安装完成后以太网驱动仍处于 OSI 第二层数据链路层可以检测到 link up/down 事件、获得用户空间的 MAC 地址但无法获得 IP 地址也无法发送 HTTP 请求。ESP-IDF 使用的 TCP/IP 协议栈是 LwIP。要将以太网驱动连接至 TCP/IP 协议栈需要三步为以太网驱动程序创建网络接口将网络接口连接到以太网驱动程序注册 IP 事件处理程序/** 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 事件保证执行用户定义的处理程序时系统处于预期状态。上述完整流程在官方示例 ethernet_example_main.c 中可逐一对照eth_init()完成 MAC/PHY 默认配置加载与实例创建app_main()依次调用esp_netif_init()、esp_event_loop_create_default()、esp_netif_new()、esp_netif_attach()最后注册事件处理程序并esp_eth_start()。以太网驱动程序的杂项控制以下功能只支持在安装以太网驱动程序后调用关闭以太网驱动程序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除上述ETH_CMD_G_MAC_ADDR、ETH_CMD_G_PHY_ADDR外还包括ETH_CMD_S_MAC_ADDR设置 MAC 地址、ETH_CMD_S_PHY_ADDR设置 PHY 地址、ETH_CMD_S/G_AUTONEGO设置/获取自动协商、ETH_CMD_S/G_SPEED、ETH_CMD_S/G_DUPLEX_MODE、ETH_CMD_S_PROMISCUOUS混杂模式、ETH_CMD_S_FLOW_CTRL流控、ETH_CMD_S_PHY_LOOPBACKPHY 环回、ETH_CMD_READ/WRITE_PHY_REG直接读写 PHY 寄存器、ETH_CMD_S_ALL_MULTICAST接收所有组播、ETH_CMD_ADD/DEL_MAC_FILTERMAC 过滤等。官方 basic 示例 中还演示了在ETHERNET_EVENT_CONNECTED事件里用ETH_CMD_G_SPEED与ETH_CMD_G_DUPLEX_MODE查询链路速率与双工模式。EMAC 硬件时间戳仅支持SOC_EMAC_IEEE1588V2_SUPPORTED的芯片EMAC 时间戳功能可以精确记录以太网帧的发送和接收时间。硬件时间戳对于精确时间协议PTP等应用至关重要因为它减少了依赖软件时间戳可能出现的抖动和不准确性。将时间戳直接嵌入硬件避免了由软件层或处理开销引入的延迟从而实现纳秒级精度。警告时间戳相关的 API 当前属于实验特性未来版本中可能有所更改。以下内容介绍如何在 EMAC 中启用时间戳、获取和设置时间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 模块配置项clk_srcPTP 时钟源从soc_periph_emac_ptp_clk_src_t枚举中选择。clk_src_period_nsPTP 时钟源的周期纳秒。例如时钟源为 40 MHz则周期为 25 ns。required_accuracy_nsPTP 所需精度纳秒必须低于 PTP 时钟源的周期。例如 40 MHz25 ns 周期时钟源对应所需精度 40 ns。roll_type亚秒寄存器的翻转模式数字或二进制。推荐使用二进制翻转模式因为它能提供更精确的时间同步。相关 API 原型如esp_eth_mac_ptp_enable、esp_eth_mac_get_ptp_time、esp_eth_mac_set_ptp_time均声明于 esp_eth_mac_esp.h。接收帧的时间戳可通过注册的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 上的 PPSPulse-Per-Second信号输出为同步外部设备、对齐独立时钟域或驱动时间关键型进程提供精确的硬件时间参考。PPS 信号默认每秒产生一次脉冲但可通过esp_eth_mac_set_pps_out_freq调整 PPS0 输出频率该命令接受 016384 范围内的整数值其中 0 1 PPS单次脉冲其他值产生方波时钟信号时钟频率必须是 2 的幂且 ≤ 16384 Hz。注意数字翻转模式下因位的非线性切换实际频率为平均值一秒总周期内占空比不同于 50%此行为不适用于二进制翻转模式因此推荐使用二进制翻转模式。可用esp_eth_mac_set_pps_out_gpio配置 PPS 信号的输出 GPIOESP32-P4 上 PPS 信号输出从芯片版本 3 开始可用。数据流量控制受 RAM 大小限制网络拥堵时 MCU 上的以太网通常仅能处理有限数量的帧。以太网数据流量控制机制允许接收节点向发送方发出信号要求暂停传输直到接收方跟上。此功能通过暂停帧实现定义于 IEEE 802.3x。暂停帧是一种特殊的以太网帧携带暂停命令EtherType 字段为0x8808控制操作码为0x0001。只有配置为全双工操作的节点组可以发送暂停帧节点组向 48 位保留组播地址01-80-C2-00-00-01发送暂停帧其中包含请求暂停的时间段两字节整数范围065535。安装以太网驱动程序后数据流量控制功能默认禁用可通过以下方式启用bool flow_ctrl_enable true; esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, flow_ctrl_enable);需注意暂停帧是在自动协商期间由 PHY 向对等端公布的只有当链路两端都支持暂停帧时以太网驱动程序才会发送暂停帧。从源码看内部 MAC 驱动中还实现了基于 RX 缓冲区占用率的软件流控逻辑流控低水位线定义为CONFIG_ETH_DMA_RX_BUFFER_NUM / 3见 esp_eth_mac_esp.c与 Kconfig 中CONFIG_ETH_SOFT_FLOW_CONTROL选项配合使用。应用示例ethernet/basic 演示如何使用以太网驱动程序包括驱动安装、连接到esp_netif、发送 DHCP 请求以及获取可 ping 的 IP 地址。ethernet/iperf 演示如何使用 iPerf 测量吞吐量/带宽。ethernet/ptp 演示如何在以太网上使用精确时间协议PTP同步时间。network/vlan_support 演示如何在以太网上创建虚拟网络接口包括 VLAN 和非 VLAN 接口。network/sta2eth 演示如何使用 Wi-Fi station 和有线接口如以太网或 USB创建 1 对 1 的桥接。network/simple_sniffer 演示如何在嗅探模式下使用 Wi-Fi 和以太网捕获数据包并保存为 PCAP 格式。network/eth2ap 演示如何实现桥接器在以太网端口和 Wi-Fi AP 接口之间转发数据包创建 1 对多连接而无需初始化 TCP/IP 栈。network/bridge 演示如何使用 LwIP IEEE 802.1D 桥接器根据 MAC 地址在多个网络段之间转发以太网帧。大多数 protocols 示例也适用于以太网。进阶操作自定义 PHY 驱动程序市面上有多家 PHY 芯片制造商提供各种类型的芯片。ESP-IDF 现已支持通用 PHY和数种特定的 PHY 芯片但由于价格、功能、库存等原因有时仍无法找到满足实际需求的芯片。好在 IEEE 802.3 在 22.2.4 管理功能部分对 EMAC 和 PHY 之间的管理接口进行了标准化定义了MII 管理接口规范用于控制 PHY、收集 PHY 状态及一组管理寄存器控制芯片行为、链接属性、自动协商配置等。在 ESP-IDF 中这项基本管理功能由 esp_eth_phy_802_3.c 实现大大降低了创建新自定义 PHY 芯片驱动的难度。相关头文件为 esp_eth_phy_802_3.h。注意由于一些 PHY 芯片可能不符合 IEEE 802.3 第 22.2.4 节规定请首先查看 PHY 数据手册。即使芯片不符合规定依旧可以创建自定义 PHY 驱动程序只是需要自行定义所有 PHY 管理功能过程较为复杂。ESP-IDF 以太网驱动所需的大部分 PHY 管理功能已涵盖在上述文件中但以下几项仍可能需针对不同芯片开发具体管理功能链接状态此项总是由使用的具体芯片决定。芯片初始化即使不存在严格限制也应进行自定义以确保使用的是符合预期的芯片。芯片的具体功能配置。创建自定义 PHY 驱动程序的步骤根据 PHY 数据手册定义厂家私有的寄存器。准备衍生的 PHY 管理对象信息结构该结构必须至少包含 IEEE 802.3phy_802_3_t父对象可选择包含额外变量以支持非 IEEE 802.3 或定制功能。定义针对芯片的特定管理回调功能。初始化 IEEE 802.3 父对象并重新分配针对芯片的特定管理回调功能。实现新的自定义 PHY 驱动程序后可以通过乐鑫组件注册表将驱动分享给其他用户。关键源码与文档索引驱动公共 APIesp_eth.h、esp_eth_driver.h时钟配置esp_eth_clock.h、esp_eth_clock.cMAC 接口与内部 EMAC 实现esp_eth_mac.h、esp_eth_mac_esp.h、esp_eth_mac_esp.c、esp_eth_mac_esp_dma.cSPI 型 MACesp_eth_mac_spi.hPHY 接口与 IEEE 802.3 通用实现esp_eth_phy.h、esp_eth_phy_802_3.c网卡粘合层esp_eth_netif_glue.h、esp_eth_netif_glue.c驱动 KconfigDMA 缓冲区等调优项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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门