mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
feat(esp_eth): added PTP EMAC PPS0 support on ESP32P4v3
feat(esp_eth): added options to configure PTP module feat(esp_eth): removed all PTP ioctl commands and created API
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#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"
|
||||
@@ -126,7 +127,7 @@ typedef struct {
|
||||
#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 can set the CSR clock range up to 2.5 MHz */
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -136,18 +137,23 @@ typedef struct {
|
||||
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_PTP_ENABLE, /*!< Enable IEEE1588 Time stamping */
|
||||
ETH_MAC_ESP_CMD_S_PTP_TIME, /*!< Set PTP time in the module */
|
||||
ETH_MAC_ESP_CMD_G_PTP_TIME, /*!< Get PTP time from the module */
|
||||
ETH_MAC_ESP_CMD_ADJ_PTP_FREQ, /*!< Adjust current PTP time frequency increment by scale factor */
|
||||
ETH_MAC_ESP_CMD_ADJ_PTP_TIME, /*!< Adjust base PTP time frequency increment by PPS */
|
||||
ETH_MAC_ESP_CMD_S_TARGET_TIME, /*!< Set Target Time at which interrupt is invoked when PTP time exceeds this value*/
|
||||
ETH_MAC_ESP_CMD_S_TARGET_CB, /*!< Set pointer to a callback function invoked when PTP time exceeds Target Time */
|
||||
ETH_MAC_ESP_CMD_ENABLE_TS4ALL, /*!< Enable timestamp for all received frames */
|
||||
ETH_MAC_ESP_CMD_DUMP_REGS, /*!< Dump EMAC registers */
|
||||
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
|
||||
*
|
||||
@@ -161,6 +167,18 @@ typedef enum {
|
||||
* - 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
|
||||
|
||||
/**
|
||||
@@ -242,6 +260,152 @@ typedef bool (*ts_target_exceed_cb_from_isr_t)(esp_eth_mediator_t *eth, void *us
|
||||
* - 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 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);
|
||||
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
|
||||
#endif // CONFIG_ETH_USE_ESP32_EMAC
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -23,6 +23,7 @@ esp_err_t emac_esp_iomux_rmii_init_tx_er(int num);
|
||||
esp_err_t emac_esp_iomux_rmii_init_rx_er(int num);
|
||||
esp_err_t emac_esp_iomux_mii_init_tx_er(int num);
|
||||
esp_err_t emac_esp_iomux_mii_init_rx_er(int num);
|
||||
esp_err_t emac_esp_gpio_matrix_init_ptp_pps(int num);
|
||||
esp_err_t emac_esp_gpio_init_smi(const emac_esp_smi_gpio_config_t *smi_gpio);
|
||||
esp_err_t emac_esp_gpio_deinit_all(void);
|
||||
|
||||
|
||||
@@ -366,83 +366,6 @@ esp_err_t emac_esp_custom_ioctl(esp_eth_mac_t *mac, int cmd, void *data)
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
#ifdef SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
case ETH_MAC_ESP_CMD_PTP_ENABLE: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP enable invalid argument, cant' be NULL");
|
||||
bool enable = *((bool *)data);
|
||||
if (enable) {
|
||||
EMAC_IF_RCC_ATOMIC() {
|
||||
emac_hal_clock_enable_ptp(&emac->hal, EMAC_PTP_CLK_SRC_XTAL, true);
|
||||
}
|
||||
emac_hal_ptp_config_t ptp_config = {
|
||||
.upd_method = ETH_PTP_UPDATE_METHOD_FINE,
|
||||
.roll = ETH_PTP_DIGITAL_ROLLOVER,
|
||||
.ptp_clk_src_period_ns = 25, // = 1 / 40MHz
|
||||
.ptp_req_accuracy_ns = 40 // required accuracy (must be worse than ptp_ref_clk)
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_start(&emac->hal, &ptp_config), TAG, "failed to start PTP module");
|
||||
emac_esp_dma_ts_enable(emac->emac_dma_hndl, true);
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_stop(&emac->hal), TAG, "failed to stop PTP module");
|
||||
emac_esp_dma_ts_enable(emac->emac_dma_hndl, false);
|
||||
EMAC_IF_RCC_ATOMIC() {
|
||||
emac_hal_clock_enable_ptp(&emac->hal, 0, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ETH_MAC_ESP_CMD_S_PTP_TIME: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP set time invalid argument, cant' be NULL");
|
||||
eth_mac_time_t *time = (eth_mac_time_t *)data;
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_set_sys_time(&emac->hal, time->seconds, time->nanoseconds), TAG, "failed to set PTP time");
|
||||
break;
|
||||
}
|
||||
case ETH_MAC_ESP_CMD_G_PTP_TIME: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP get time invalid argument, cant' be NULL");
|
||||
eth_mac_time_t *time = (eth_mac_time_t *)data;
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_get_sys_time(&emac->hal, &time->seconds, &time->nanoseconds), TAG, "failed to get PTP time");
|
||||
break;
|
||||
}
|
||||
case ETH_MAC_ESP_CMD_ADJ_PTP_TIME: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP adjust time invalid argument, cant' be NULL");
|
||||
int32_t adj_ppb = *((int32_t *)data);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_adj_inc(&emac->hal, adj_ppb), TAG, "failed to adjust PTP time base");
|
||||
break;
|
||||
}
|
||||
case ETH_MAC_ESP_CMD_ADJ_PTP_FREQ: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP adjust frequency invalid argument, cant' be NULL");
|
||||
double scale_factor = *((double *)data);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_adj_freq_factor(&emac->hal, scale_factor), TAG, "failed to aject PTP time base by scale factor");
|
||||
break;
|
||||
}
|
||||
case ETH_MAC_ESP_CMD_S_TARGET_CB:
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP set target callback function invalid argument, cant' be NULL");
|
||||
emac->ts_target_exceed_cb_from_isr = (ts_target_exceed_cb_from_isr_t)data;
|
||||
break;
|
||||
case ETH_MAC_ESP_CMD_S_TARGET_TIME: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP set target time invalid argument, cant' be NULL");
|
||||
eth_mac_time_t *start_time = (eth_mac_time_t *)data;
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_set_target_time(&emac->hal, start_time->seconds, start_time->nanoseconds), TAG,
|
||||
"failed to set PTP target time");
|
||||
break;
|
||||
}
|
||||
case ETH_MAC_ESP_CMD_ENABLE_TS4ALL: {
|
||||
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "PTP enable TS for all invalid argument, cant' be NULL");
|
||||
bool enable = *(bool *)data;
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_enable_ts4all(&emac->hal, enable), TAG, "failed to enable timestamping for all frames");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case ETH_MAC_ESP_CMD_PTP_ENABLE:
|
||||
case ETH_MAC_ESP_CMD_S_PTP_TIME:
|
||||
case ETH_MAC_ESP_CMD_G_PTP_TIME:
|
||||
case ETH_MAC_ESP_CMD_ADJ_PTP_TIME:
|
||||
case ETH_MAC_ESP_CMD_ADJ_PTP_FREQ:
|
||||
case ETH_MAC_ESP_CMD_S_TARGET_CB:
|
||||
case ETH_MAC_ESP_CMD_S_TARGET_TIME:
|
||||
case ETH_MAC_ESP_CMD_ENABLE_TS4ALL:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#endif
|
||||
case ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS:
|
||||
ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "cannot set DMA tx desc flag to null");
|
||||
emac_esp_dma_set_tdes0_ctrl_bits(emac->emac_dma_hndl, *(uint32_t *)data);
|
||||
@@ -909,6 +832,111 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
esp_err_t esp_eth_mac_ptp_enable(esp_eth_mac_t *mac, const eth_mac_ptp_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
EMAC_IF_RCC_ATOMIC() {
|
||||
emac_hal_clock_enable_ptp(&emac->hal, config->clk_src, true);
|
||||
}
|
||||
emac_hal_ptp_config_t ptp_config = {
|
||||
.upd_method = ETH_PTP_UPDATE_METHOD_FINE,
|
||||
.roll = config->roll_type,
|
||||
.ptp_clk_src_period_ns = config->clk_src_period_ns,
|
||||
.ptp_req_accuracy_ns = config->required_accuracy_ns
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_start(&emac->hal, &ptp_config), TAG, "failed to start PTP module");
|
||||
emac_esp_dma_ts_enable(emac->emac_dma_hndl, true);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_ptp_disable(esp_eth_mac_t *mac)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_stop(&emac->hal), TAG, "failed to stop PTP module");
|
||||
emac_esp_dma_ts_enable(emac->emac_dma_hndl, false);
|
||||
EMAC_IF_RCC_ATOMIC() {
|
||||
emac_hal_clock_enable_ptp(&emac->hal, 0, false);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_set_ptp_time(esp_eth_mac_t *mac, const eth_mac_time_t *time)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac && time, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_set_sys_time(&emac->hal, time->seconds, time->nanoseconds), TAG, "failed to set PTP time");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_get_ptp_time(esp_eth_mac_t *mac, eth_mac_time_t *time)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac && time, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_get_sys_time(&emac->hal, &time->seconds, &time->nanoseconds), TAG, "failed to get PTP time");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_adj_ptp_freq(esp_eth_mac_t *mac, double scale_factor)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_adj_freq_factor(&emac->hal, scale_factor), TAG, "failed to adjust PTP time base by scale factor");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_adj_ptp_time(esp_eth_mac_t *mac, int32_t adj_ppb)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_adj_inc(&emac->hal, adj_ppb), TAG, "failed to adjust PTP time base");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_set_target_time(esp_eth_mac_t *mac, const eth_mac_time_t *target)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac && target, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_set_target_time(&emac->hal, target->seconds, target->nanoseconds), TAG,
|
||||
"failed to set PTP target time");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_set_target_time_cb(esp_eth_mac_t *mac, ts_target_exceed_cb_from_isr_t cb)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
emac->ts_target_exceed_cb_from_isr = cb;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_enable_ts4all(esp_eth_mac_t *mac, bool enable)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_ptp_enable_ts4all(&emac->hal, enable), TAG, "failed to enable timestamping for all frames");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_set_pps_out_gpio(esp_eth_mac_t *mac, int gpio_num)
|
||||
{
|
||||
// The mac argument is unused in implementation but kept for API consistency
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init_ptp_pps(gpio_num), TAG, "failed to set PPS0 output at GPIO %i", gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_mac_set_pps_out_freq(esp_eth_mac_t *mac, uint32_t freq_hz)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(mac, ESP_ERR_INVALID_ARG, TAG, "invalid argument, can't be NULL");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_RETURN_ON_ERROR(emac_hal_set_pps0_out_freq(&emac->hal, freq_hz), TAG, "failed to set PPS0 output frequency");
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
|
||||
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config)
|
||||
{
|
||||
esp_err_t ret_code = ESP_OK;
|
||||
|
||||
@@ -262,6 +262,13 @@ esp_err_t emac_esp_iomux_mii_init_rx_er(int num)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t emac_esp_gpio_matrix_init_ptp_pps(int num)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(num, 0, emac_io_idx.ptp_pps_idx, GPIO_MODE_OUTPUT),
|
||||
TAG, "PTP PPS GPIO matrix config failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t emac_esp_gpio_deinit_all(void)
|
||||
{
|
||||
for (int gpio_num = 0; gpio_num < 64; gpio_num++) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -366,6 +366,10 @@ esp_err_t emac_hal_ptp_start(emac_hal_context_t *hal, const emac_hal_ptp_config_
|
||||
emac_ll_ts_ptp_ether_enable(hal->ptp_regs, true);
|
||||
// Process frames with v2 format
|
||||
emac_ll_ptp_v2_proc_enable(hal->ptp_regs, true);
|
||||
// Enable time stamping frame filtering
|
||||
emac_ll_ts_mac_addr_filter_enable(hal->ptp_regs, true);
|
||||
// Process also Pdelay messages
|
||||
emac_ll_ts_ptp_snap_type_sel(hal->ptp_regs, 1);
|
||||
|
||||
/* Un-mask the Time stamp trigger interrupt */
|
||||
emac_ll_enable_corresponding_emac_intr(hal->mac_regs, EMAC_LL_CONFIG_ENABLE_MAC_INTR_MASK);
|
||||
@@ -552,6 +556,20 @@ esp_err_t emac_hal_ptp_enable_ts4all(emac_hal_context_t *hal, bool enable)
|
||||
emac_ll_ts_all_enable(hal->ptp_regs, enable);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t emac_hal_set_pps0_out_freq(emac_hal_context_t *hal, uint32_t freq_hz)
|
||||
{
|
||||
uint8_t n;
|
||||
if (freq_hz == 0) { // 0 is special case for 1PPS (narrow pulse)
|
||||
n = 0;
|
||||
} else if (!(freq_hz & (freq_hz - 1)) && freq_hz <= 16384) { // is power of two and less than maximum supported frequency
|
||||
n = 1 + __builtin_ctz(freq_hz);
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
emac_ll_set_pps0_out_freq(hal->ptp_regs, n);
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
|
||||
void emac_hal_start(emac_hal_context_t *hal)
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "hal/emac_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
/**
|
||||
* In emac_periph terms, `SIG_GPIO_OUT_IDX` indicates that the EMAC signal cannot be connected
|
||||
* via the GPIO Matrix (i.e. such connection doesn't exist for the function), so it should
|
||||
* stay in the default "unconnected state".
|
||||
*
|
||||
* Note: `SIG_GPIO_OUT_IDX` is defined for all targets and is usually used to signify "disconnect
|
||||
* from peripheral signal" (a default unconnected peripheral state).
|
||||
*/
|
||||
|
||||
const emac_io_info_t emac_io_idx = {
|
||||
.mdc_idx = EMAC_MDC_O_IDX,
|
||||
.mdo_idx = EMAC_MDO_O_IDX,
|
||||
.mdi_idx = EMAC_MDI_I_IDX,
|
||||
.mii_tx_clk_i_idx = SIG_GPIO_OUT_IDX, // indicates EMAC signal cannot be connected via GPIO Matrix on the target
|
||||
.mii_tx_clk_i_idx = SIG_GPIO_OUT_IDX,
|
||||
.mii_tx_en_o_idx = SIG_GPIO_OUT_IDX,
|
||||
.mii_txd0_o_idx = SIG_GPIO_OUT_IDX,
|
||||
.mii_txd1_o_idx = SIG_GPIO_OUT_IDX,
|
||||
@@ -27,7 +36,8 @@ const emac_io_info_t emac_io_idx = {
|
||||
.mii_tx_er_o_idx = SIG_GPIO_OUT_IDX,
|
||||
.mii_rx_er_i_idx = SIG_GPIO_OUT_IDX,
|
||||
.rmii_refclk_i_idx = SIG_GPIO_OUT_IDX,
|
||||
.rmii_refclk_o_idx = SIG_GPIO_OUT_IDX
|
||||
.rmii_refclk_o_idx = SIG_GPIO_OUT_IDX,
|
||||
.ptp_pps_idx = SIG_GPIO_OUT_IDX,
|
||||
};
|
||||
|
||||
static const emac_iomux_info_t emac_rmii_iomux_clki[] = {
|
||||
|
||||
@@ -4,11 +4,21 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "hal/emac_periph.h"
|
||||
#include "hal/config.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#if __has_include("soc/emac_reg.h")
|
||||
#include "soc/emac_reg.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* In emac_periph terms, `SIG_GPIO_OUT_IDX` indicates that the EMAC signal cannot be connected
|
||||
* via the GPIO Matrix (i.e. such connection doesn't exist for the function), so it should
|
||||
* stay in the default "unconnected state".
|
||||
*
|
||||
* Note: `SIG_GPIO_OUT_IDX` is defined for all targets and is usually used to signify "disconnect
|
||||
* from peripheral signal" (a default unconnected peripheral state).
|
||||
*/
|
||||
|
||||
const emac_io_info_t emac_io_idx = {
|
||||
.mdc_idx = MII_MDC_PAD_OUT_IDX,
|
||||
.mdo_idx = MII_MDO_PAD_OUT_IDX,
|
||||
@@ -30,7 +40,12 @@ const emac_io_info_t emac_io_idx = {
|
||||
.mii_tx_er_o_idx = EMAC_PHY_TXER_PAD_OUT_IDX,
|
||||
.mii_rx_er_i_idx = EMAC_PHY_RXER_PAD_IN_IDX,
|
||||
.rmii_refclk_i_idx = SIG_GPIO_OUT_IDX,
|
||||
.rmii_refclk_o_idx = SIG_GPIO_OUT_IDX
|
||||
.rmii_refclk_o_idx = SIG_GPIO_OUT_IDX,
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
.ptp_pps_idx = EMAC_PTP_PPS_PAD_OUT_IDX,
|
||||
#else
|
||||
.ptp_pps_idx = SIG_GPIO_OUT_IDX,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const emac_iomux_info_t emac_rmii_iomux_clki[] = {
|
||||
|
||||
@@ -667,6 +667,11 @@ static inline void emac_ll_receive_poll_demand(emac_dma_dev_t *dma_regs, uint32_
|
||||
dma_regs->dmarxpolldemand = val;
|
||||
}
|
||||
|
||||
static inline uint32_t emac_ll_get_hw_feat(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
return dma_regs->hwfeat;
|
||||
}
|
||||
|
||||
/*************** End of dma regs operation *********************/
|
||||
|
||||
/************** Start of ptp regs operation ********************/
|
||||
@@ -696,6 +701,11 @@ static inline void emac_ll_ts_ptp_snap_type_sel(emac_ptp_dev_t *ptp_regs, uint8_
|
||||
ptp_regs->timestamp_ctrl.sel_snap_type = sel;
|
||||
}
|
||||
|
||||
static inline void emac_ll_ts_mac_addr_filter_enable(emac_ptp_dev_t *ptp_regs, bool enable)
|
||||
{
|
||||
ptp_regs->timestamp_ctrl.en_mac_addr_filter = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_ts_ptp_snap_master_only_enable(emac_ptp_dev_t *ptp_regs, bool enable)
|
||||
{
|
||||
ptp_regs->timestamp_ctrl.en_snap_msg_relevant_master = enable;
|
||||
@@ -838,6 +848,11 @@ static inline void emac_ll_ts_target_int_trig_enable(emac_ptp_dev_t *ptp_regs)
|
||||
ptp_regs->timestamp_ctrl.en_ts_int_trig = 1;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_pps0_out_freq(emac_ptp_dev_t *ptp_regs, uint8_t freq_select)
|
||||
{
|
||||
ptp_regs->pps_ctrl.pps_cmd0 = freq_select;
|
||||
}
|
||||
|
||||
/************** End of ptp regs operation ********************/
|
||||
|
||||
static inline soc_module_clk_t emac_ll_get_csr_clk_src(void)
|
||||
|
||||
@@ -222,8 +222,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
eth_mac_ptp_update_method_t upd_method;
|
||||
eth_mac_ptp_roll_type_t roll;
|
||||
uint32_t ptp_clk_src_period_ns; /*!< 1/ptp_ref_clk */
|
||||
uint32_t ptp_req_accuracy_ns; /*!< required PTP accuracy in ns, must be greater than clk_src period */
|
||||
float ptp_clk_src_period_ns; /*!< 1/ptp_ref_clk */
|
||||
float ptp_req_accuracy_ns; /*!< required PTP accuracy in ns, must be greater than clk_src period */
|
||||
} emac_hal_ptp_config_t;
|
||||
#endif
|
||||
|
||||
@@ -245,8 +245,6 @@ void emac_hal_init(emac_hal_context_t *hal);
|
||||
|
||||
#define emac_hal_is_reset_done(hal) emac_ll_is_reset_done((hal)->dma_regs)
|
||||
|
||||
#define emac_hal_get_csr_freq_hz(void) emac_ll_get_csr_freq_hz()
|
||||
|
||||
void emac_hal_find_set_closest_csr_clock_range(emac_hal_context_t *hal, int mdc_freq_hz, int freq_hz);
|
||||
|
||||
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal, int freq);
|
||||
@@ -325,6 +323,8 @@ void emac_hal_set_rx_tx_desc_addr(emac_hal_context_t *hal, eth_dma_rx_descriptor
|
||||
|
||||
#define emac_hal_transmit_poll_demand(hal) emac_ll_transmit_poll_demand((hal)->dma_regs, 0)
|
||||
|
||||
#define emac_hal_get_hw_feat(hal) emac_ll_get_hw_feat((hal)->dma_regs)
|
||||
|
||||
#if SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
#define emac_hal_get_ts_status(hal) emac_ll_get_ts_status((hal)->ptp_regs);
|
||||
|
||||
@@ -458,6 +458,8 @@ esp_err_t emac_hal_get_rxdesc_timestamp(emac_hal_context_t *hal, eth_dma_rx_desc
|
||||
*/
|
||||
esp_err_t emac_hal_get_txdesc_timestamp(emac_hal_context_t *hal, eth_dma_tx_descriptor_t *txdesc, uint32_t *seconds, uint32_t *nano_seconds);
|
||||
|
||||
esp_err_t emac_hal_set_pps0_out_freq(emac_hal_context_t *hal, uint32_t freq_hz);
|
||||
|
||||
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
#endif // SOC_EMAC_SUPPORTED
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ typedef struct {
|
||||
uint32_t mii_tx_er_o_idx;
|
||||
uint32_t rmii_refclk_i_idx;
|
||||
uint32_t rmii_refclk_o_idx;
|
||||
uint32_t ptp_pps_idx;
|
||||
} emac_io_info_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "test_utils.h"
|
||||
|
||||
#include "esp_vfs_l2tap.h"
|
||||
#include "esp_eth_mac_esp.h"
|
||||
|
||||
#define ETH_FILTER_LE 0x7A05
|
||||
#define ETH_FILTER_BE 0x057A
|
||||
@@ -844,13 +845,11 @@ TEST_CASE("esp32 l2tap - time stamping", "[ethernet]")
|
||||
TEST_ASSERT_NOT_EQUAL(-1, ioctl(eth_tap_fd, L2TAP_S_RCV_FILTER, ð_type_filter));
|
||||
|
||||
// Enable time stamping in driver
|
||||
bool ts_enable = true;
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_network_hndls.eth_handle, ETH_MAC_ESP_CMD_PTP_ENABLE, &ts_enable));
|
||||
eth_mac_ptp_config_t ptp_config = ETH_MAC_ESP_PTP_DEFAULT_CONFIG();
|
||||
TEST_ESP_OK(esp_eth_mac_ptp_enable(eth_network_hndls.mac, &ptp_config));
|
||||
|
||||
test_eth_ptp_msg_t test_ptp_msg = {
|
||||
.eth_hdr = {
|
||||
// Note that PTPv2 MAC 01:80:C2:00:00:0E is reserved for "Peer delay messages" which are currently not
|
||||
// enabled to be snapped by internal EMAC, hence not tested
|
||||
.dest.addr = {0x01, 0x1b, 0x19, 0x0, 0x0, 0x0},
|
||||
.type = htons(ETH_TYPE_PTP)
|
||||
},
|
||||
@@ -1002,7 +1001,7 @@ TEST_CASE("esp32 l2tap - time stamping", "[ethernet]")
|
||||
.seconds = 10,
|
||||
.nanoseconds = 412000
|
||||
};
|
||||
esp_eth_ioctl(eth_network_hndls.eth_handle, ETH_MAC_ESP_CMD_S_PTP_TIME, &ptp_time);
|
||||
esp_eth_mac_set_ptp_time(eth_network_hndls.mac, &ptp_time);
|
||||
|
||||
ESP_LOGI(TAG, "Verify retrieval of Tx and Rx time stamps");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
||||
@@ -145,6 +145,7 @@ typedef struct emac_dma_dev_s {
|
||||
uint32_t dmarxcurrdesc; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t dmatxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t dmarxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t hwfeat; /*Hardware features*/
|
||||
} emac_dma_dev_t;
|
||||
|
||||
extern emac_dma_dev_t EMAC_DMA;
|
||||
|
||||
@@ -145,6 +145,7 @@ typedef struct emac_dma_dev_s {
|
||||
uint32_t dmarxcurrdesc; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t dmatxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t dmarxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t hwfeat; /*Hardware features*/
|
||||
} emac_dma_dev_t;
|
||||
|
||||
extern emac_dma_dev_t EMAC_DMA;
|
||||
|
||||
@@ -145,6 +145,7 @@ typedef struct emac_dma_dev_s {
|
||||
uint32_t dmarxcurrdesc; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t dmatxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t dmarxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
|
||||
uint32_t hwfeat; /*Hardware features*/
|
||||
} emac_dma_dev_t;
|
||||
|
||||
extern emac_dma_dev_t EMAC_DMA;
|
||||
|
||||
@@ -541,20 +541,36 @@ The following functions should only be invoked after the Ethernet driver has bee
|
||||
|
||||
::
|
||||
|
||||
esp_eth_mac_t *mac;
|
||||
esp_eth_get_mac_instance(eth_hndl, &mac);
|
||||
|
||||
// Enable hardware time stamping
|
||||
bool ptp_enable = true;
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_PTP_ENABLE, &ptp_enable);
|
||||
eth_mac_ptp_config_t ptp_cfg = ETH_MAC_ESP_PTP_DEFAULT_CONFIG();
|
||||
esp_eth_mac_ptp_enable(mac, &ptp_cfg);
|
||||
|
||||
// Get current EMAC time
|
||||
eth_mac_time_t ptp_time;
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_G_PTP_TIME, &ptp_time);
|
||||
esp_eth_mac_get_ptp_time(mac, &ptp_time);
|
||||
|
||||
// Set EMAC time
|
||||
ptp_time = {
|
||||
.seconds = 42,
|
||||
.nanoseconds = 0
|
||||
};
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_S_PTP_TIME, &ptp_time);
|
||||
esp_eth_mac_set_ptp_time(mac, &ptp_time);
|
||||
|
||||
The PTP module be can configured as follows:
|
||||
|
||||
.. list::
|
||||
* :cpp:member:`eth_mac_ptp_config_t::clk_src`: Clock source for PTP. Select one of the clock sources offered by the :cpp:type:`soc_periph_emac_ptp_clk_src_t` enumeration.
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::clk_src_period_ns`: Period of the clock source for PTP in nanoseconds. For example, if the clock source is 40MHz, the period is 25ns.
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::required_accuracy_ns`: Required accuracy for PTP in nanoseconds. The required accuracy must be worse than clock source for PTP. For example, if the clock source is 40MHz (25ns period), the required accuracy is 40ns.
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::roll_type`: Rollover mode (digital or binary) for subseconds register. The binary rollover mode is recommended as it provides a more precise time synchronization.
|
||||
|
||||
Time stamps for transmitted and received frames can be accessed via the last argument of the registered :cpp:member:`esp_eth_config_t::stack_input_info` function for the receive path, and via the ``ctrl`` argument of the :cpp:func:`esp_eth_transmit_ctrl_vargs` function for the transmit path. However, a more user-friendly approach to retrieve time stamp information in user space is by utilizing the L2 TAP :ref:`Extended Buffer <esp_netif_l2tap_ext_buff>` mechanism.
|
||||
|
||||
You have an option to schedule event at precise point in time by registering callback function and configuring a target time when the event is supposed to be fired. Note that the callback function is then called from ISR context so it should be as brief as possible.
|
||||
|
||||
@@ -563,16 +579,21 @@ The following functions should only be invoked after the Ethernet driver has bee
|
||||
::
|
||||
|
||||
// Register the callback function
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_S_TARGET_CB, ts_callback);
|
||||
esp_eth_mac_set_target_time_cb(mac, ts_callback);
|
||||
|
||||
// Set time when event is triggered
|
||||
eth_mac_time_t mac_target_time = {
|
||||
.seconds = 42,
|
||||
.nanoseconds = 0
|
||||
};
|
||||
esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_S_TARGET_TIME, &mac_target_time);
|
||||
esp_eth_mac_set_target_time(mac, &mac_target_time);
|
||||
|
||||
Time stamps for transmitted and received frames can be accessed via the last argument of the registered :cpp:member:`esp_eth_config_t::stack_input_info` function for the receive path, and via the ``ctrl`` argument of the :cpp:func:`esp_eth_transmit_ctrl_vargs` function for the transmit path. However, a more user-friendly approach to retrieve time stamp information in user space is by utilizing the L2 TAP :ref:`Extended Buffer <esp_netif_l2tap_ext_buff>` mechanism.
|
||||
Alternatively, the PTP-synchronized time can be exposed via a PPS (Pulse-Per-Second) signal on a GPIO. This provides a precise hardware time reference that can be used to synchronize external devices, align independent clock domains, or drive time-critical processes outside the ESP32 chip series. As the name suggests, the PPS signal is a pulse that occurs once per second by default. However, the frequency can be adjusted by setting the PPS0 output frequency using the :cpp:func:`esp_eth_mac_set_pps_out_freq` function. The command accepts an integer value in the range of 0-16384, where 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. Note that due to non-linear toggling of bits in the digital rollover mode, the actual frequency is an average number (duty cycle differs from 50% in overall one second period). This behavior does not apply to the binary rollover mode and so this mode is recommended. The PPS signal can be configured to be output at a GPIO using the :cpp:func:`esp_eth_mac_set_pps_out_gpio` function.
|
||||
|
||||
.. only:: esp32p4
|
||||
|
||||
.. note::
|
||||
The PPS signal output on GPIO pin is available starting from ESP32-P4 silicon revision 3.
|
||||
|
||||
.. _flow-control:
|
||||
|
||||
|
||||
@@ -69,6 +69,27 @@ The Ethernet PHY and Ethernet SPI Module drivers have been removed from ESP-IDF
|
||||
Add driver component from `IDF Component Manager <https://components.espressif.com/>`_ to your project using `idf.py add-dependency` and include `esp_eth_phy_xxxx.h` and `esp_eth_mac_xxxx.h` or use the `Ethernet Init component <https://components.espressif.com/components/espressif/ethernet_init>`_.
|
||||
|
||||
|
||||
PTP API Changes
|
||||
---------------
|
||||
|
||||
Ethernet `esp_eth_ioctl` PTP configuration and control commands have been removed.
|
||||
|
||||
**Removed ioctl Commands**:
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_PTP_ENABLE`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_S_PTP_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_G_PTP_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_ADJ_PTP_FREQ`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_ADJ_PTP_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_S_TARGET_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_S_TARGET_CB`
|
||||
|
||||
**Impact**: Applications using the removed ioctl commands will no longer work.
|
||||
|
||||
**Migration**:
|
||||
|
||||
Use the new PTP API instead.
|
||||
|
||||
|
||||
ESP-NETIF
|
||||
*********
|
||||
|
||||
|
||||
@@ -541,20 +541,36 @@ ESP-IDF 在宏 :c:macro:`ETH_DEFAULT_CONFIG` 中为安装驱动程序提供了
|
||||
|
||||
::
|
||||
|
||||
esp_eth_mac_t *mac;
|
||||
esp_eth_get_mac_instance(eth_hndl, &mac);
|
||||
|
||||
// 启用硬件时间戳
|
||||
bool ptp_enable = true;
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_PTP_ENABLE, &ptp_enable);
|
||||
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_ioctl(eth_hndl, ETH_MAC_ESP_CMD_G_PTP_TIME, &ptp_time);
|
||||
esp_eth_mac_get_ptp_time(mac, &ptp_time);
|
||||
|
||||
// 设置 EMAC 时间
|
||||
ptp_time = {
|
||||
.seconds = 42,
|
||||
.nanoseconds = 0
|
||||
};
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_S_PTP_TIME, &ptp_time);
|
||||
esp_eth_mac_set_ptp_time(mac, &ptp_time);
|
||||
|
||||
PTP 模块可以按如下方式配置:
|
||||
|
||||
.. list::
|
||||
* :cpp:member:`eth_mac_ptp_config_t::clk_src`:PTP 时钟源。从 :cpp:type:`soc_periph_emac_ptp_clk_src_t` 枚举中选择一个时钟源。
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::clk_src_period_ns`:PTP 时钟源的周期(以纳秒为单位)。例如,如果时钟源为 40 MHz,则周期为 25 ns。
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::required_accuracy_ns`:PTP 的所需精度(以纳秒为单位)。所需精度必须低于 PTP 时钟源的周期。例如,如果时钟源为 40 MHz(25 ns 周期),则所需精度为 40 ns。
|
||||
|
||||
* :cpp:member:`eth_mac_ptp_config_t::roll_type`:亚秒寄存器的翻转模式(数字或二进制)。推荐使用二进制翻转模式,因为它能提供更精确的时间同步。
|
||||
|
||||
接收帧的时间戳可以通过注册的 :cpp:member:`esp_eth_config_t::stack_input_info` 函数的最后一个参数进行访问,传输帧的时间戳可以通过注册的 :cpp:func:`esp_eth_transmit_ctrl_vargs` 函数的 ``ctrl`` 参数进行访问。然而,对于用户获取时间戳信息,更简便的方式是利用 L2 TAP :ref:`扩展缓冲区 <esp_netif_l2tap_ext_buff>` 机制。
|
||||
|
||||
您可以通过注册回调函数和设置事件触发的目标时间,在精确的时间点调度事件。请注意,回调函数将在中断服务程序 (ISR) 上下文中调用,因此应尽量简洁。
|
||||
|
||||
@@ -563,16 +579,21 @@ ESP-IDF 在宏 :c:macro:`ETH_DEFAULT_CONFIG` 中为安装驱动程序提供了
|
||||
::
|
||||
|
||||
// 注册回调函数
|
||||
esp_eth_ioctl(eth_hndl, ETH_MAC_ESP_CMD_S_TARGET_CB, ts_callback);
|
||||
esp_eth_mac_set_target_time_cb(mac, ts_callback);
|
||||
|
||||
// 设置事件的触发时间
|
||||
eth_mac_time_t mac_target_time = {
|
||||
.seconds = 42,
|
||||
.nanoseconds = 0
|
||||
};
|
||||
esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_S_TARGET_TIME, &mac_target_time);
|
||||
esp_eth_mac_set_target_time(mac, &mac_target_time);
|
||||
|
||||
接收帧的时间戳可以通过注册的 :cpp:member:`esp_eth_config_t::stack_input_info` 函数的最后一个参数进行访问,传输帧的时间戳可以通过注册的 :cpp:func:`esp_eth_transmit_ctrl_vargs` 函数的 ``ctrl`` 参数进行访问。然而,对于用户获取时间戳信息,更简便的方式是利用 L2 TAP :ref:`扩展缓冲区 <esp_netif_l2tap_ext_buff>` 机制。
|
||||
此外,PTP 同步的时间可以通过 GPIO 上的 PPS (Pulse-Per-Second) 信号输出。这提供了一个精确的硬件时间参考,可用于同步外部设备、对齐独立时钟域或驱动 ESP32 芯片系列之外的时间关键型进程。顾名思义,PPS 信号默认每秒产生一次脉冲。但是,可以通过 :cpp:func:`esp_eth_mac_set_pps_out_freq` 函数设置 PPS0 输出频率来调整频率。该命令接受 0-16384 范围内的整数值,其中 0 = 1 PPS(单次脉冲),其他值产生方波时钟信号。时钟频率必须是 2 的幂且小于或等于 16384 Hz。请注意,由于数字翻转模式中位的非线性切换,实际频率是一个平均值(在一秒钟的总周期内占空比不同于 50%)。此行为不适用于二进制翻转模式,因此推荐使用二进制翻转模式。可以使用 :cpp:func:`esp_eth_mac_set_pps_out_gpio` 函数配置 PPS 信号在 GPIO 上输出。
|
||||
|
||||
.. only:: esp32p4
|
||||
|
||||
.. note::
|
||||
GPIO 管脚上的 PPS 信号输出从 ESP32-P4 芯片版本 3 开始可用。
|
||||
|
||||
.. _flow-control:
|
||||
|
||||
|
||||
@@ -69,6 +69,27 @@
|
||||
请通过 `idf.py add-dependency` 命令,从 `IDF 组件管理器 <https://components.espressif.com/>`_ 添加驱动组件到你的项目,并包含相应的 `esp_eth_phy_xxxx.h` 和 `esp_eth_mac_xxxx.h` 头文件,或使用 `Ethernet Init 组件 <https://components.espressif.com/components/espressif/ethernet_init>`_。
|
||||
|
||||
|
||||
PTP API 变更
|
||||
---------------
|
||||
|
||||
以太网 `esp_eth_ioctl` PTP 配置和控制命令已被移除。
|
||||
|
||||
**移除的 ioctl 命令**:
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_PTP_ENABLE`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_S_PTP_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_G_PTP_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_ADJ_PTP_FREQ`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_ADJ_PTP_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_S_TARGET_TIME`
|
||||
- :cpp:enumerator:`eth_mac_esp_io_cmd_t::ETH_MAC_ESP_CMD_S_TARGET_CB`
|
||||
|
||||
**影响**:使用已移除 ioctl 命令的应用程序将不再工作。
|
||||
|
||||
**迁移**:
|
||||
|
||||
请改用新的 PTP API。
|
||||
|
||||
|
||||
ESP-NETIF
|
||||
*********
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "esp_eth_time.h"
|
||||
#include "esp_eth_mac_esp.h"
|
||||
|
||||
static esp_eth_handle_t s_eth_hndl;
|
||||
static esp_eth_mac_t *s_mac;
|
||||
|
||||
static int esp_eth_clock_esp_err_to_errno(esp_err_t esp_err)
|
||||
{
|
||||
@@ -29,7 +30,7 @@ int esp_eth_clock_adjtime(clockid_t clk_id, esp_eth_clock_adj_param_t *adj)
|
||||
switch (clk_id) {
|
||||
case CLOCK_PTP_SYSTEM:
|
||||
if (adj->mode == ETH_CLK_ADJ_FREQ_SCALE) {
|
||||
esp_err_t ret = esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_ADJ_PTP_FREQ, &adj->freq_scale);
|
||||
esp_err_t ret = esp_eth_mac_adj_ptp_freq(s_mac, adj->freq_scale);
|
||||
if (ret != ESP_OK) {
|
||||
errno = esp_eth_clock_esp_err_to_errno(ret);
|
||||
return -1;
|
||||
@@ -50,12 +51,12 @@ int esp_eth_clock_settime(clockid_t clock_id, const struct timespec *tp)
|
||||
{
|
||||
switch (clock_id) {
|
||||
case CLOCK_PTP_SYSTEM: {
|
||||
if (s_eth_hndl) {
|
||||
if (s_mac) {
|
||||
eth_mac_time_t ptp_time = {
|
||||
.seconds = tp->tv_sec,
|
||||
.nanoseconds = tp->tv_nsec
|
||||
};
|
||||
esp_err_t ret = esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_S_PTP_TIME, &ptp_time);
|
||||
esp_err_t ret = esp_eth_mac_set_ptp_time(s_mac, &ptp_time);
|
||||
if (ret != ESP_OK) {
|
||||
errno = esp_eth_clock_esp_err_to_errno(ret);
|
||||
return -1;
|
||||
@@ -77,9 +78,9 @@ int esp_eth_clock_gettime(clockid_t clock_id, struct timespec *tp)
|
||||
{
|
||||
switch (clock_id) {
|
||||
case CLOCK_PTP_SYSTEM: {
|
||||
if (s_eth_hndl) {
|
||||
if (s_mac) {
|
||||
eth_mac_time_t ptp_time;
|
||||
esp_err_t ret = esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_G_PTP_TIME, &ptp_time);
|
||||
esp_err_t ret = esp_eth_mac_get_ptp_time(s_mac, &ptp_time);
|
||||
if (ret != ESP_OK) {
|
||||
errno = esp_eth_clock_esp_err_to_errno(ret);
|
||||
return -1;
|
||||
@@ -105,7 +106,7 @@ int esp_eth_clock_set_target_time(clockid_t clock_id, struct timespec *tp)
|
||||
.seconds = tp->tv_sec,
|
||||
.nanoseconds = tp->tv_nsec
|
||||
};
|
||||
esp_err_t ret = esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_S_TARGET_TIME, &mac_target_time);
|
||||
esp_err_t ret = esp_eth_mac_set_target_time(s_mac, &mac_target_time);
|
||||
if (ret != ESP_OK) {
|
||||
errno = esp_eth_clock_esp_err_to_errno(ret);
|
||||
return -1;
|
||||
@@ -116,7 +117,7 @@ int esp_eth_clock_set_target_time(clockid_t clock_id, struct timespec *tp)
|
||||
int esp_eth_clock_register_target_cb(clockid_t clock_id,
|
||||
ts_target_exceed_cb_from_isr_t ts_callback)
|
||||
{
|
||||
esp_err_t ret = esp_eth_ioctl(s_eth_hndl, ETH_MAC_ESP_CMD_S_TARGET_CB, ts_callback);
|
||||
esp_err_t ret = esp_eth_mac_set_target_time_cb(s_mac, ts_callback);
|
||||
if (ret != ESP_OK) {
|
||||
errno = esp_eth_clock_esp_err_to_errno(ret);
|
||||
return -1;
|
||||
@@ -126,14 +127,24 @@ int esp_eth_clock_register_target_cb(clockid_t clock_id,
|
||||
|
||||
esp_err_t esp_eth_clock_init(clockid_t clock_id, esp_eth_clock_cfg_t *cfg)
|
||||
{
|
||||
if (s_mac != NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (cfg == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
switch (clock_id) {
|
||||
case CLOCK_PTP_SYSTEM:
|
||||
// PTP Clock is part of Ethernet system
|
||||
bool ptp_enable = true;
|
||||
if (esp_eth_ioctl(cfg->eth_hndl, ETH_MAC_ESP_CMD_PTP_ENABLE, &ptp_enable) != ESP_OK) {
|
||||
eth_mac_ptp_config_t ptp_cfg = ETH_MAC_ESP_PTP_DEFAULT_CONFIG();
|
||||
esp_eth_mac_t *mac;
|
||||
if (esp_eth_get_mac_instance(cfg->eth_hndl, &mac) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
s_eth_hndl = cfg->eth_hndl;
|
||||
if (esp_eth_mac_ptp_enable(mac, &ptp_cfg) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
s_mac = mac;
|
||||
break;
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
|
||||
@@ -123,6 +123,8 @@ int esp_eth_clock_register_target_cb(clockid_t clock_id,
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_FAIL: Failure
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Clock is already initialized
|
||||
*/
|
||||
esp_err_t esp_eth_clock_init(clockid_t clock_id, esp_eth_clock_cfg_t *cfg);
|
||||
|
||||
|
||||
@@ -290,6 +290,11 @@ static struct ptp_state_s *s_state;
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
#ifdef ESP_PTP
|
||||
static int ptp_get_esp_eth_handle(struct ptp_state_s *state, esp_eth_handle_t *eth_handle)
|
||||
{
|
||||
return ioctl(state->ptp_socket, L2TAP_G_DEVICE_DRV_HNDL, eth_handle);
|
||||
}
|
||||
|
||||
static void ptp_create_eth_frame(struct ptp_state_s *state, uint8_t *eth_frame, void *ptp_msg, uint16_t ptp_msg_len)
|
||||
{
|
||||
struct eth_hdr eth_hdr = {
|
||||
@@ -636,7 +641,7 @@ static int ptp_initialize_state(FAR struct ptp_state_s *state,
|
||||
}
|
||||
// Enable time stamping in driver
|
||||
esp_eth_handle_t eth_handle;
|
||||
if (ioctl(state->ptp_socket, L2TAP_G_DEVICE_DRV_HNDL, ð_handle) < 0)
|
||||
if (ptp_get_esp_eth_handle(state, ð_handle) < 0)
|
||||
{
|
||||
ptperr("failed to get socket eth_handle %d\n", errno);
|
||||
return ERROR;
|
||||
@@ -859,7 +864,7 @@ static int ptp_destroy_state(FAR struct ptp_state_s *state)
|
||||
#ifdef ESP_PTP
|
||||
// Remove well-known PTP multicast destination MAC addresses from the filter
|
||||
esp_eth_handle_t eth_handle;
|
||||
if (ioctl(state->ptp_socket, L2TAP_G_DEVICE_DRV_HNDL, ð_handle) < 0)
|
||||
if (ptp_get_esp_eth_handle(state, ð_handle) < 0)
|
||||
{
|
||||
ptperr("failed to get socket eth_handle %d\n", errno);
|
||||
return ERROR;
|
||||
|
||||
@@ -2,14 +2,44 @@ menu "Example Configuration"
|
||||
|
||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||
|
||||
choice EXAMPLE_PTP_PULSE_SOURCE
|
||||
prompt "Pulse Source"
|
||||
default EXAMPLE_PTP_PULSE_EMAC_PPS
|
||||
help
|
||||
Select source for sync pulse generation.
|
||||
|
||||
config EXAMPLE_PTP_PULSE_EMAC_PPS
|
||||
depends on !ESP32P4_SELECTS_REV_LESS_V3
|
||||
bool "Generate internally by EMAC PPS"
|
||||
help
|
||||
Pulse per second signal is generated internally by EMAC.
|
||||
|
||||
config EXAMPLE_PTP_PULSE_CALLBACK
|
||||
bool "Generate by interrupt and callback function"
|
||||
help
|
||||
Pulse is generated by callback function invoked by EMAC interrupt. The interrupt is
|
||||
raised on EMAC timer event which is continuously reconfigured in the callback function
|
||||
to align with configured pulse width.
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_PTP_PULSE_GPIO
|
||||
int "PPS GPIO number"
|
||||
int "Pulse GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 20
|
||||
help
|
||||
Set the GPIO number at which the Pulse signal is outputted.
|
||||
|
||||
config EXAMPLE_PTP_PPS_FREQ_HZ
|
||||
depends on EXAMPLE_PTP_PULSE_EMAC_PPS
|
||||
int "PPS Frequency Configuration"
|
||||
range 0 16384
|
||||
default 0
|
||||
help
|
||||
Select EMAC PPS output frequency as 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.
|
||||
|
||||
config EXAMPLE_PTP_PULSE_WIDTH_NS
|
||||
depends on EXAMPLE_PTP_PULSE_CALLBACK
|
||||
int "Pulse width (ns)"
|
||||
range 5000 999999999
|
||||
default 500000000
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -15,11 +15,16 @@
|
||||
#include "ptpd.h"
|
||||
|
||||
#include "esp_eth_time.h"
|
||||
#include "esp_eth_mac_esp.h"
|
||||
|
||||
#define ETH_IF_KEY "ETH_0"
|
||||
|
||||
static const char *TAG = "ptp_example";
|
||||
|
||||
#if CONFIG_EXAMPLE_PTP_PULSE_CALLBACK
|
||||
static struct timespec s_next_time;
|
||||
static bool s_gpio_level;
|
||||
#endif //CONFIG_EXAMPLE_PTP_PULSE_CALLBACK
|
||||
|
||||
void init_ethernet_and_netif(void)
|
||||
{
|
||||
@@ -60,6 +65,7 @@ void init_ethernet_and_netif(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_PTP_PULSE_CALLBACK
|
||||
IRAM_ATTR bool ts_callback(esp_eth_mediator_t *eth, void *user_args)
|
||||
{
|
||||
gpio_set_level(CONFIG_EXAMPLE_PTP_PULSE_GPIO, s_gpio_level ^= 1);
|
||||
@@ -80,13 +86,23 @@ IRAM_ATTR bool ts_callback(esp_eth_mediator_t *eth, void *user_args)
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif //CONFIG_EXAMPLE_PTP_PULSE_CALLBACK
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Starting PTP example");
|
||||
init_ethernet_and_netif();
|
||||
|
||||
int pid = ptpd_start("ETH_0");
|
||||
int pid = ptpd_start(ETH_IF_KEY);
|
||||
|
||||
#if CONFIG_EXAMPLE_PTP_PULSE_EMAC_PPS
|
||||
(void)pid; // suppress compiler warning about unused variable
|
||||
esp_eth_handle_t eth_handle = esp_netif_get_io_driver(esp_netif_get_handle_from_ifkey(ETH_IF_KEY));
|
||||
esp_eth_mac_t *mac;
|
||||
ESP_ERROR_CHECK(esp_eth_get_mac_instance(eth_handle, &mac));
|
||||
ESP_ERROR_CHECK(esp_eth_mac_set_pps_out_gpio(mac, CONFIG_EXAMPLE_PTP_PULSE_GPIO));
|
||||
ESP_ERROR_CHECK(esp_eth_mac_set_pps_out_freq(mac, CONFIG_EXAMPLE_PTP_PPS_FREQ_HZ));
|
||||
#elif CONFIG_EXAMPLE_PTP_PULSE_CALLBACK
|
||||
struct timespec cur_time;
|
||||
// wait for the clock to be available
|
||||
while (esp_eth_clock_gettime(CLOCK_PTP_SYSTEM, &cur_time) == -1) {
|
||||
@@ -147,4 +163,5 @@ void app_main(void)
|
||||
}
|
||||
clock_source_valid_last = clock_source_valid;
|
||||
}
|
||||
#endif //CONFIG_EXAMPLE_PTP_PULSE_EMAC_PPS
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user