项目文件夹

文件
2026-07-13 13:04:25 +08:00

511 行
21 KiB
C

/*
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#include "esp_eth_com.h"
#include "esp_eth_mac.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ETH_USE_ESP32_EMAC
/**
* @brief RMII Clock Mode Options
*
*/
typedef enum {
/**
* @brief Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected.
*
* @note See components/esp_hal_emac/esp32(*)/emac_periph.c for available GPIO numbers.
*
*/
EMAC_CLK_EXT_IN,
/**
* @brief Output RMII Clock from internal PLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected.
*
* @warning ESP32 Errata: If you want the Ethernet to work with Wi-Fi or BT, don’t select ESP32 as RMII CLK output as it would result in clock instability.
* Applicable only to ESP32, other ESP32 SoCs are not affected.
*
* @note See components/esp_hal_emac/esp32(*)/emac_periph.c for available GPIO numbers.
*
*/
EMAC_CLK_OUT
} emac_rmii_clock_mode_t;
/**
* @brief Ethernet MAC Clock Configuration
*
*/
typedef union {
struct {
// MII interface is not fully implemented...
// Reserved for GPIO number, clock source, etc. in MII mode
} mii; /*!< EMAC MII Clock Configuration */
struct {
emac_rmii_clock_mode_t clock_mode; /*!< RMII Clock Mode Configuration */
int clock_gpio; /*!< RMII Clock GPIO Configuration */
} rmii; /*!< EMAC RMII Clock Configuration */
struct {
int clock_rx_gpio; /*!< RGMII Rx Clock GPIO Configuration */
int clock_tx_gpio; /*!< RGMII Tx Clock GPIO Configuration */
int clock_phy_ref_gpio; /*!< RGMII PHY_REF_CLK Clock GPIO Configuration */
} rgmii; /*!< EMAC RGMII Clock Configuration */
} eth_mac_clock_config_t;
/**
* @brief EMAC SMI GPIO configuration
*/
typedef struct {
int mdc_num; /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */
int mdio_num; /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */
} emac_esp_smi_gpio_config_t;
/**
* @brief EMAC MII data interface GPIO configuration
*/
typedef struct {
int tx_clk_num; /*!< TX_CLK GPIO number */
int tx_en_num; /*!< TX_EN GPIO number */
int txd0_num; /*!< TXD0 GPIO number */
int txd1_num; /*!< TXD1 GPIO number */
int txd2_num; /*!< TXD2 GPIO number */
int txd3_num; /*!< TXD3 GPIO number */
int rx_clk_num; /*!< RX_CLK GPIO number */
int rx_dv_num; /*!< RX_DV GPIO number */
int rxd0_num; /*!< RXD0 GPIO number */
int rxd1_num; /*!< RXD1 GPIO number */
int rxd2_num; /*!< RXD2 GPIO number */
int rxd3_num; /*!< RXD3 GPIO number */
int col_in_num; /*!< COL_IN GPIO number */
int crs_in_num; /*!< CRS_IN GPIO number */
int tx_er_num; /*!< TX_ER GPIO number */
int rx_er_num; /*!< RX_ER GPIO number */
} eth_mac_mii_gpio_config_t;
/**
* @brief EMAC RMII data interface GPIO configuration
*/
typedef struct {
int tx_en_num; /*!< TX_EN GPIO number */
int txd0_num; /*!< TXD0 GPIO number */
int txd1_num; /*!< TXD1 GPIO number */
int crs_dv_num; /*!< CRS_DV GPIO number */
int rxd0_num; /*!< RXD0 GPIO number */
int rxd1_num; /*!< RXD1 GPIO number */
} eth_mac_rmii_gpio_config_t;
/**
* @brief Ethernet MAC RGMII data interface GPIO configuration
*
*/
typedef struct {
int tx_ctl_num; /*!< TX_CTL GPIO number */
int txd0_num; /*!< TXD0 GPIO number */
int txd1_num; /*!< TXD1 GPIO number */
int txd2_num; /*!< TXD2 GPIO number */
int txd3_num; /*!< TXD3 GPIO number */
int rx_ctl_num; /*!< RX_CTL GPIO number */
int rxd0_num; /*!< RXD0 GPIO number */
int rxd1_num; /*!< RXD1 GPIO number */
int rxd2_num; /*!< RXD2 GPIO number */
int rxd3_num; /*!< RXD3 GPIO number */
} eth_mac_rgmii_gpio_config_t;
#if SOC_EMAC_USE_MULTI_IO_MUX || SOC_EMAC_MII_USE_GPIO_MATRIX
/**
* @brief Ethernet MAC MII/RMII data plane GPIO configuration
*
*/
typedef union {
eth_mac_mii_gpio_config_t mii; /*!< EMAC MII Data GPIO Configuration */
eth_mac_rmii_gpio_config_t rmii; /*!< EMAC RMII Data GPIO Configuration */
eth_mac_rgmii_gpio_config_t rgmii; /*!< EMAC RGMII Data GPIO Configuration */
} eth_mac_dataif_gpio_config_t;
#endif // SOC_EMAC_USE_MULTI_IO_MUX
/**
* @brief EMAC specific configuration
*
*/
typedef struct {
emac_esp_smi_gpio_config_t smi_gpio; /*!< SMI GPIO numbers */
eth_data_interface_t interface; /*!< EMAC Data interface to PHY (MII/RMII) */
eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */
eth_mac_dma_burst_len_t dma_burst_len; /*!< EMAC DMA burst length for both Tx and Rx */
int intr_priority; /*!< EMAC interrupt priority, if set to 0 or a negative value, the driver will try to allocate an interrupt with a default priority */
#if SOC_EMAC_USE_MULTI_IO_MUX || SOC_EMAC_MII_USE_GPIO_MATRIX
eth_mac_dataif_gpio_config_t emac_dataif_gpio; /*!< EMAC MII/RMII data plane GPIO configuration */
#endif // SOC_EMAC_USE_MULTI_IO_MUX
#if !SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK
eth_mac_clock_config_t clock_config_out_in; /*!< EMAC input clock configuration for internally generated output clock (when output clock is looped back externally) */
#endif //SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK
int32_t mdc_freq_hz; /*!< EMAC MDC frequency range limit, if set to 0 or a negative value, the driver will set the CSR clock range up to 2.5 MHz */
} eth_esp32_emac_config_t;
/**
* @brief List of ESP EMAC specific commands for ioctl API
*
*/
typedef enum {
ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS = ETH_CMD_CUSTOM_MAC_CMDS_OFFSET, /*!< Set Transmit Descriptor Word 0 control bit mask (debug option)*/
ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS, /*!< Clear Transmit Descriptor Word 0 control bit mask (debug option)*/
ETH_MAC_ESP_CMD_DUMP_REGS, /*!< Dump EMAC registers (debug option) */
} eth_mac_esp_io_cmd_t;
#ifdef SOC_EMAC_IEEE1588V2_SUPPORTED
/**
* @brief Configuration of PTP module
*
* @warning Time stamping is currently Experimental Feature! Be aware that API may change.
*
*/
typedef struct {
soc_periph_emac_ptp_clk_src_t clk_src; /*!< Clock source for PTP */
float clk_src_period_ns; /*!< Period of the clock source for PTP in nanoseconds*/
float required_accuracy_ns; /*!< Required accuracy for PTP in nanoseconds (must be worse than clock source for PTP)*/
eth_mac_ptp_roll_type_t roll_type; /*!< Rollover mode (digital or binary) for subseconds register */
} eth_mac_ptp_config_t;
/**
* @brief Type of callback function invoked under Time Stamp target time exceeded interrupt
*
* @warning Time stamping is currently Experimental Feature! Be aware that API may change.
*
* @param eth: mediator of Ethernet driver
* @param user_args user specific arguments (placeholder - IDF-11429)
*
* @return
* - TRUE when high priority task has been woken by this function
* - FALSE no high priority task was woken by this function
*/
typedef bool (*ts_target_exceed_cb_from_isr_t)(esp_eth_mediator_t *eth, void *user_args);
/**
* @brief Default configuration for PTP module
*
*/
#define ETH_MAC_ESP_PTP_DEFAULT_CONFIG() \
{ \
.clk_src = EMAC_PTP_CLK_SRC_XTAL, \
.clk_src_period_ns = 25, \
.required_accuracy_ns = 40, \
.roll_type = ETH_PTP_BINARY_ROLLOVER, \
}
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
/**
* @brief Default ESP32's EMAC specific configuration
*
*/
#if CONFIG_IDF_TARGET_ESP32
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_gpio = \
{ \
.mdc_num = 23, \
.mdio_num = 18 \
}, \
.interface = EMAC_DATA_INTERFACE_RMII, \
.clock_config = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_EXT_IN, \
.clock_gpio = 0 \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
.intr_priority = 0, \
.mdc_freq_hz = 0, \
}
#elif CONFIG_IDF_TARGET_ESP32P4
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_gpio = \
{ \
.mdc_num = 31, \
.mdio_num = 52 \
}, \
.interface = EMAC_DATA_INTERFACE_RMII, \
.clock_config = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_EXT_IN, \
.clock_gpio = 50 \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
.intr_priority = 0, \
.emac_dataif_gpio = \
{ \
.rmii = \
{ \
.tx_en_num = 49, \
.txd0_num = 34, \
.txd1_num = 35, \
.crs_dv_num = 28, \
.rxd0_num = 29, \
.rxd1_num = 30 \
} \
}, \
.clock_config_out_in = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_EXT_IN, \
.clock_gpio = -1 \
} \
}, \
.mdc_freq_hz = 0, \
}
#elif CONFIG_IDF_TARGET_ESP32S31
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_gpio = \
{ \
.mdc_num = 5, \
.mdio_num = 6 \
}, \
.interface = EMAC_DATA_INTERFACE_RGMII, \
.clock_config = \
{ \
.rgmii = \
{ \
.clock_rx_gpio = 14, \
.clock_tx_gpio = 13, \
.clock_phy_ref_gpio = -1, \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_16, \
.intr_priority = 0, \
.emac_dataif_gpio = \
{ \
.rgmii = \
{ \
.tx_ctl_num = 12, \
.txd0_num = 8, \
.txd1_num = 9, \
.txd2_num = 10, \
.txd3_num = 11, \
.rx_ctl_num = 15, \
.rxd0_num = 19, \
.rxd1_num = 18, \
.rxd2_num = 17, \
.rxd3_num = 16 \
} \
}, \
.clock_config_out_in = \
{ \
.rgmii = \
{ \
.clock_rx_gpio = -1, \
.clock_tx_gpio = -1, \
.clock_phy_ref_gpio = -1 \
} \
}, \
.mdc_freq_hz = 0, \
}
#endif
/**
* @brief Create ESP32 Ethernet MAC instance
*
* @param esp32_config: EMAC specific configuration
* @param config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config);
#ifdef SOC_EMAC_IEEE1588V2_SUPPORTED
/**
* @brief Enable/Disable PTP module
*
* @param mac: Ethernet MAC instance
* @param config: PTP configuration
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_ptp_enable(esp_eth_mac_t *mac, const eth_mac_ptp_config_t *config);
/**
* @brief Disable PTP module
*
* @param mac: Ethernet MAC instance
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_ptp_disable(esp_eth_mac_t *mac);
/**
* @brief Set PTP time
*
* @param mac: Ethernet MAC instance
* @param time: PTP time
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_set_ptp_time(esp_eth_mac_t *mac, const eth_mac_time_t *time);
/**
* @brief Get PTP time
*
* @param mac: Ethernet MAC instance
* @param time: PTP time
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_get_ptp_time(esp_eth_mac_t *mac, eth_mac_time_t *time);
/**
* @brief Adjust PTP time frequency increment by scale factor
*
* @param mac: Ethernet MAC instance
* @param scale_factor: frequency scale factor
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_adj_ptp_freq(esp_eth_mac_t *mac, double scale_factor);
/**
* @brief Adjust base PTP time frequency increment by PPS
*
* @param mac: Ethernet MAC instance
* @param adj_ppb: adjustment in ppb
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_adj_ptp_time(esp_eth_mac_t *mac, int32_t adj_ppb);
/**
* @brief Adjust PTP frequency relative to its current addend value by ppb
*
* Unlike esp_eth_mac_adj_ptp_time (absolute from base) or esp_eth_mac_adj_ptp_freq
* (relative by double scale factor), this adjusts the current addend by ppb:
* addend_new = current * (1 + adj_ppb / 10^9). Calling with adj_ppb=0 is a no-op.
*
* @param mac: Ethernet MAC instance
* @param adj_ppb: relative frequency adjustment in parts per billion
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_adj_ptp_freq_ppb(esp_eth_mac_t *mac, int32_t adj_ppb);
/**
* @brief Set Target Time at which interrupt is invoked when PTP time exceeds this value
*
* @param mac: Ethernet MAC instance
* @param target: target time
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_set_target_time(esp_eth_mac_t *mac, const eth_mac_time_t *target);
/**
* @brief Set pointer to a callback function invoked when PTP time exceeds Target Time
*
* @param mac: Ethernet MAC instance
* @param cb: callback function
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_set_target_time_cb(esp_eth_mac_t *mac, ts_target_exceed_cb_from_isr_t cb);
/**
* @brief Enable timestamp for all received frames
*
* @param mac: Ethernet MAC instance
* @param enable: enable or disable
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_enable_ts4all(esp_eth_mac_t *mac, bool enable);
/**
* @brief Set PPS0 output at GPIO
*
* @param mac: Ethernet MAC instance
* @param gpio_num: GPIO number
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_set_pps_out_gpio(esp_eth_mac_t *mac, int gpio_num);
/**
* @brief Set PPS0 output frequency
*
* @param mac: Ethernet MAC instance
* @param freq_hz: Supported frequencies: 0 = 1PPS (narrow pulse), other values generate square clock signal.
* The clock frequency must be power of two and less than or equal to 16384 Hz.
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: invalid argument
* - ESP_FAIL: failure
*/
esp_err_t esp_eth_mac_set_pps_out_freq(esp_eth_mac_t *mac, uint32_t freq_hz);
/**
* @brief Get PTP timestamp resolution
*
* @param mac: Ethernet MAC instance
*
* @return
* - PTP timestamp resolution in nanoseconds
*/
uint32_t esp_eth_mac_get_ts_resolution(esp_eth_mac_t *mac);
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
#endif // CONFIG_ETH_USE_ESP32_EMAC
#ifdef __cplusplus
}
#endif