add esp_eth component

This commit is contained in:
suda-morris 2019-04-10 16:24:50 +08:00
parent 12f4541f19
commit 90c4827bd2
87 changed files with 5686 additions and 6083 deletions

View file

@ -26,6 +26,9 @@ PROVIDE ( SPI3 = 0x3ff65000 );
PROVIDE ( SYSCON = 0x3ff66000 );
PROVIDE ( I2C1 = 0x3ff67000 );
PROVIDE ( SDMMC = 0x3ff68000 );
PROVIDE ( EMAC_DMA = 0x3ff69000 );
PROVIDE ( EMAC_EXT = 0x3ff69800 );
PROVIDE ( EMAC_MAC = 0x3ff6A000 );
PROVIDE ( CAN = 0x3ff6B000 );
PROVIDE ( MCPWM1 = 0x3ff6C000 );
PROVIDE ( I2S1 = 0x3ff6D000 );

View file

@ -0,0 +1,15 @@
set(esp_eth_srcs "src/esp_eth.c"
"src/esp_eth_phy_dp83848.c"
"src/esp_eth_phy_ip101.c"
"src/esp_eth_phy_lan8720.c"
"src/esp_eth_phy_rtl8201.c")
if(CONFIG_IDF_TARGET_ESP32)
list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c")
endif()
idf_component_register(SRCS "${esp_eth_srcs}"
INCLUDE_DIRS "include"
LDFRAGMENTS "linker.lf"
REQUIRES "esp_event"
PRIV_REQUIRES "tcpip_adapter" "driver" "log")

131
components/esp_eth/Kconfig Normal file
View file

@ -0,0 +1,131 @@
menu "Ethernet"
menuconfig ETH_USE_ESP32_EMAC
depends on IDF_TARGET_ESP32
bool "Use ESP32 internal EMAC controller"
default y
help
ESP32 integrates a 10/100M Ethernet MAC controller.
if ETH_USE_ESP32_EMAC
choice ETH_PHY_INTERFACE
prompt "PHY interface"
default ETH_PHY_INTERFACE_RMII
help
Select the communication interface between MAC and PHY chip.
config ETH_PHY_INTERFACE_RMII
bool "Reduced Media Independent Interface (RMII)"
config ETH_PHY_INTERFACE_MII
bool "Media Independent Interface (MII)"
endchoice
if ETH_PHY_INTERFACE_RMII
choice ETH_RMII_CLK_MODE
prompt "RMII clock mode"
default ETH_RMII_CLK_INPUT
help
Select external or internal RMII clock.
config ETH_RMII_CLK_INPUT
bool "Input RMII clock from external"
help
MAC will get RMII clock from outside.
Note that ESP32 only supports GPIO0 to input the RMII clock.
config ETH_RMII_CLK_OUTPUT
bool "Output RMII clock from internal"
help
ESP32 can generate RMII clock by internal APLL.
This clock can be routed to the external PHY device.
ESP32 supports to route the RMII clock to GPIO0/16/17.
endchoice
endif
if ETH_RMII_CLK_INPUT
config ETH_RMII_CLK_IN_GPIO
int
range 0 0
default 0
help
ESP32 only supports GPIO0 to input the RMII clock.
endif
if ETH_RMII_CLK_OUTPUT
config ETH_RMII_CLK_OUTPUT_GPIO0
bool "Output RMII clock from GPIO0 (Experimental!)"
default n
help
GPIO0 can be set to output a pre-divided PLL clock (test only!).
Enabling this option will configure GPIO0 to output a 50MHz clock.
In fact this clock doesn't have directly relationship with EMAC peripheral.
Sometimes this clock won't work well with your PHY chip. You might need to
add some extra devices after GPIO0 (e.g. inverter).
Note that outputting RMII clock on GPIO0 is an experimental practice.
If you want the Ethernet to work with WiFi, don't select GPIO0 output mode for stability.
if !ETH_RMII_CLK_OUTPUT_GPIO0
config ETH_RMII_CLK_OUT_GPIO
int "RMII clock GPIO number"
range 16 17
default 17
help
Set the GPIO number to output RMII Clock.
endif
endif
config ETH_SMI_MDC_GPIO
int "SMI MDC GPIO number"
default 23
range 0 33
help
Set the GPIO number used by SMI MDC.
config ETH_SMI_MDIO_GPIO
int "SMI MDIO GPIO number"
default 18
range 0 33
help
Set the GPIO number used by SMI MDIO.
config ETH_PHY_USE_RST
bool "Use Reset Pin of PHY Chip"
default y
help
Set this option to true if you want to control PHY chip's reset using a GPIO.
Check the schematic of you board to make sure if it's necessary to use this feature.
if ETH_PHY_USE_RST
config ETH_PHY_RST_GPIO
int "PHY RST GPIO number"
default 5
range 0 33
help
Set the GPIO number used by the PHY chip's RST pin.
endif
config ETH_DMA_BUFFER_SIZE
int "Ethernet DMA buffer size (Byte)"
range 256 1600
default 512
help
Set the size of each buffer used by Ethernet MAC DMA.
config ETH_DMA_RX_BUFFER_NUM
int "Amount of Ethernet DMA Rx buffers"
range 3 20
default 10
help
Number of DMA receive buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE.
Larger number of buffers could increase throughput somehow.
config ETH_DMA_TX_BUFFER_NUM
int "Amount of Ethernet DMA Tx buffers"
range 3 20
default 10
help
Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE.
Larger number of buffers could increase throughput somehow.
endif
endmenu

View file

@ -0,0 +1,10 @@
#
# Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_SRCDIRS := src
COMPONENT_ADD_LDFRAGMENTS += linker.lf
ifndef CONFIG_IDF_TARGET_ESP32
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o
endif

View file

@ -0,0 +1,174 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_eth_com.h"
#include "esp_eth_mac.h"
#include "esp_eth_phy.h"
/**
* @brief Handle of Ethernet driver
*
*/
typedef void *esp_eth_handle_t;
/**
* @brief Configuration of Ethernet driver
*
*/
typedef struct {
/**
* @brief Ethernet MAC object
*
*/
esp_eth_mac_t *mac;
/**
* @brief Ethernet PHY object
*
*/
esp_eth_phy_t *phy;
/**
* @brief Period time of checking Ethernet link status
*
*/
uint32_t check_link_period_ms;
/**
* @brief Input frame buffer to user's stack
*
* @param[in] eth_handle: handle of Ethernet driver
* @param[in] buffer: frame buffer that will get input to upper stack
* @param[in] length: length of the frame buffer
*
* @return
* - ESP_OK: input frame buffer to upper stack successfully
* - ESP_FAIL: error occurred when inputting buffer to upper stack
*
*/
esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length);
/**
* @brief Callback function invoked when lowlevel initialization is finished
*
* @param[in] eth_handle: handle of Ethernet driver
*
* @return
* - ESP_OK: process extra lowlevel initialization successfully
* - ESP_FAIL: error occurred when processing extra lowlevel initialization
*/
esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle);
/**
* @brief Callback function invoked when lowlevel deinitialization is finished
*
* @param[in] eth_handle: handle of Ethernet driver
*
* @return
* - ESP_OK: process extra lowlevel deinitialization successfully
* - ESP_FAIL: error occurred when processing extra lowlevel deinitialization
*/
esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle);
} esp_eth_config_t;
/**
* @brief Default configuration for Ethernet driver
*
*/
#define ETH_DEFAULT_CONFIG(emac, ephy) \
{ \
.mac = emac, \
.phy = ephy, \
.check_link_period_ms = 2000, \
.stack_input = NULL, \
.on_lowlevel_init_done = NULL, \
.on_lowlevel_deinit_done = NULL, \
}
/**
* @brief Install Ethernet driver
*
* @param[in] config: configuration of the Ethernet driver
* @param[out] out_hdl: handle of Ethernet driver
*
* @return
* - ESP_OK: install esp_eth driver successfully
* - ESP_ERR_INVALID_ARG: install esp_eth driver failed because of some invalid argument
* - ESP_ERR_NO_MEM: install esp_eth driver failed because there's no memory for driver
* - ESP_FAIL: install esp_eth driver failed because some other error occurred
*/
esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl);
/**
* @brief Uninstall Ethernet driver
*
* @param[in] hdl: handle of Ethernet driver
*
* @return
* - ESP_OK: uninstall esp_eth driver successfully
* - ESP_ERR_INVALID_ARG: uninstall esp_eth driver failed because of some invalid argument
* - ESP_FAIL: uninstall esp_eth driver failed because some other error occurred
*/
esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl);
/**
* @brief General Transmit
*
* @param[in] hdl: handle of Ethernet driver
* @param[in] buf: buffer of the packet to transfer
* @param[in] length: length of the buffer to transfer
*
* @return
* - ESP_OK: transmit frame buffer successfully
* - ESP_ERR_INVALID_ARG: transmit frame buffer failed because of some invalid argument
* - ESP_FAIL: transmit frame buffer failed because some other error occurred
*/
esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, uint8_t *buf, uint32_t length);
/**
* @brief General Receive
*
* @param[in] hdl: handle of Ethernet driver
* @param[out] buf: buffer to preserve the received packet
* @param[out] length: length of the received packet
*
* @return
* - ESP_OK: receive frame buffer successfully
* - ESP_ERR_INVALID_ARG: receive frame buffer failed because of some invalid argument
* - ESP_FAIL: receive frame buffer failed because some other error occurred
*/
esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length);
/**
* @brief Misc IO function of Etherent driver
*
* @param[in] hdl: handle of Ethernet driver
* @param[in] cmd: IO control command
* @param[in] data: specificed data for command
*
* @return
* - ESP_OK: process io command successfully
* - ESP_ERR_INVALID_ARG: process io command failed because of some invalid argument
* - ESP_FAIL: process io command failed because some other error occurred
*/
esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,211 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
#include "esp_event_base.h"
/**
* @brief Maximum Ethernet payload size
*
*/
#define ETH_MAX_PAYLOAD_LEN (1500)
/**
* @brief Minimum Ethernet payload size
*
*/
#define ETH_MIN_PAYLOAD_LEN (46)
/**
* @brief Ethernet frame header size: Dest addr(6 Bytes) + Src addr(6 Bytes) + length/type(2 Bytes)
*
*/
#define ETH_HEADER_LEN (14)
/**
* @brief Ethernet frame CRC length
*
*/
#define ETH_CRC_LEN (4)
/**
* @brief Optional 802.1q VLAN Tag length
*
*/
#define ETH_VLAN_TAG_LEN (4)
/**
* @brief Jumbo frame payload size
*
*/
#define ETH_JUMBO_FRAME_PAYLOAD_LEN (9000)
/**
* @brief Maximum frame size (1522 Bytes)
*
*/
#define ETH_MAX_PACKET_SIZE (ETH_HEADER_LEN + ETH_VLAN_TAG_LEN + ETH_MAX_PAYLOAD_LEN + ETH_CRC_LEN)
/**
* @brief Minimum frame size (64 Bytes)
*
*/
#define ETH_MIN_PACKET_SIZE (ETH_HEADER_LEN + ETH_MIN_PAYLOAD_LEN + ETH_CRC_LEN)
/**
* @brief Ethernet driver state
*
*/
typedef enum {
ETH_STATE_LLINIT, /*!< Lowlevel init done */
ETH_STATE_DEINIT, /*!< Deinit done */
ETH_STATE_LINK, /*!< Link status changed */
ETH_STATE_SPEED, /*!< Speed updated */
ETH_STATE_DUPLEX, /*!< Duplex updated */
} esp_eth_state_t;
/**
* @brief Command list for ioctl API
*
*/
typedef enum {
ETH_CMD_G_MAC_ADDR, /*!< Get MAC address */
ETH_CMD_S_MAC_ADDR, /*!< Set MAC address */
ETH_CMD_G_PHY_ADDR, /*!< Get PHY address */
ETH_CMD_S_PHY_ADDR, /*!< Set PHY address */
ETH_CMD_G_SPEED, /*!< Get Speed */
ETH_CMD_S_PROMISCUOUS, /*!< Set promiscuous mode */
} esp_eth_io_cmd_t;
/**
* @brief Ethernet link status
*
*/
typedef enum {
ETH_LINK_UP, /*!< Ethernet link is up */
ETH_LINK_DOWN /*!< Ethernet link is down */
} eth_link_t;
/**
* @brief Ethernet speed
*
*/
typedef enum {
ETH_SPEED_10M, /*!< Ethernet speed is 10Mbps */
ETH_SPEED_100M /*!< Ethernet speed is 100Mbps */
} eth_speed_t;
/**
* @brief Ethernet duplex mode
*
*/
typedef enum {
ETH_DUPLEX_HALF, /*!< Ethernet is in half duplex */
ETH_DUPLEX_FULL /*!< Ethernet is in full duplex */
} eth_duplex_t;
/**
* @brief Ethernet mediator
*
*/
typedef struct esp_eth_mediator_s esp_eth_mediator_t;
/**
* @brief Ethernet mediator
*
*/
struct esp_eth_mediator_s {
/**
* @brief Read PHY register
*
* @param[in] eth: mediator of Ethernet driver
* @param[in] phy_addr: PHY Chip address (0~31)
* @param[in] phy_reg: PHY register index code
* @param[out] reg_value: PHY register value
*
* @return
* - ESP_OK: read PHY register successfully
* - ESP_FAIL: read PHY register failed because some error occurred
*
*/
esp_err_t (*phy_reg_read)(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value);
/**
* @brief Write PHY register
*
* @param[in] eth: mediator of Ethernet driver
* @param[in] phy_addr: PHY Chip address (0~31)
* @param[in] phy_reg: PHY register index code
* @param[in] reg_value: PHY register value
*
* @return
* - ESP_OK: write PHY register successfully
* - ESP_FAIL: write PHY register failed because some error occurred
*/
esp_err_t (*phy_reg_write)(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value);
/**
* @brief Deliver packet to upper stack
*
* @param[in] eth: mediator of Ethernet driver
* @param[in] buffer: packet buffer
* @param[in] length: length of the packet
*
* @return
* - ESP_OK: deliver packet to upper stack successfully
* - ESP_FAIL: deliver packet failed because some error occurred
*
*/
esp_err_t (*stack_input)(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length);
/**
* @brief Callback on Ethernet state changed
*
* @param[in] eth: mediator of Ethernet driver
* @param[in] state: new state
* @param[in] args: optional argument for the new state
*
* @return
* - ESP_OK: process the new state successfully
* - ESP_FAIL: process the new state failed because some error occurred
*
*/
esp_err_t (*on_state_changed)(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args);
};
/**
* @brief Ethernet event declarations
*
*/
typedef enum {
ETHERNET_EVENT_START, /*!< Ethernet driver start */
ETHERNET_EVENT_STOP, /*!< Ethernet driver stop */
ETHERNET_EVENT_CONNECTED, /*!< Ethernet got a valid link */
ETHERNET_EVENT_DISCONNECTED, /*!< Ethernet lost a valid link */
} eth_event_t;
/**
* @brief Ethernet event base declaration
*
*/
ESP_EVENT_DECLARE_BASE(ETH_EVENT);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,271 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "esp_eth_com.h"
#include "sdkconfig.h"
/**
* @brief Ethernet MAC
*
*/
typedef struct esp_eth_mac_s esp_eth_mac_t;
/**
* @brief Ethernet MAC
*
*/
struct esp_eth_mac_s {
/**
* @brief Set mediator for Ethernet MAC
*
* @param[in] mac: Ethernet MAC instance
* @param[in] eth: Ethernet mediator
*
* @return
* - ESP_OK: set mediator for Ethernet MAC successfully
* - ESP_ERR_INVALID_ARG: set mediator for Ethernet MAC failed because of invalid argument
*
*/
esp_err_t (*set_mediator)(esp_eth_mac_t *mac, esp_eth_mediator_t *eth);
/**
* @brief Initialize Ethernet MAC
*
* @param[in] mac: Ethernet MAC instance
*
* @return
* - ESP_OK: initialize Ethernet MAC successfully
* - ESP_ERR_TIMEOUT: initialize Ethernet MAC failed because of timeout
* - ESP_FAIL: initialize Ethernet MAC failed because some other error occurred
*
*/
esp_err_t (*init)(esp_eth_mac_t *mac);
/**
* @brief Deinitialize Ethernet MAC
*
* @param[in] mac: Ethernet MAC instance
*
* @return
* - ESP_OK: deinitialize Ethernet MAC successfully
* - ESP_FAIL: deinitialize Ethernet MAC failed because some error occurred
*
*/
esp_err_t (*deinit)(esp_eth_mac_t *mac);
/**
* @brief Transmit packet from Ethernet MAC
*
* @param[in] mac: Ethernet MAC instance
* @param[in] buf: packet buffer to transmit
* @param[in] length: length of packet
*
* @return
* - ESP_OK: transmit packet successfully
* - ESP_ERR_INVALID_ARG: transmit packet failed because of invalid argument
* - ESP_ERR_INVALID_STATE: transmit packet failed because of wrong state of MAC
* - ESP_FAIL: transmit packet failed because some other error occurred
*
*/
esp_err_t (*transmit)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length);
/**
* @brief Receive packet from Ethernet MAC
*
* @param[in] mac: Ethernet MAC instance
* @param[out] buf: packet buffer which will preserve the received frame
* @param[out] length: length of the received packet
*
* @note Memory of buf is allocated in the Layer2, make sure it get free after process.
*
* @return
* - ESP_OK: receive packet successfully
* - ESP_ERR_INVALID_ARG: receive packet failed because of invalid argument
* - ESP_FAIL: receive packet failed because some other error occurred
*
*/
esp_err_t (*receive)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length);
/**
* @brief Read PHY register
*
* @param[in] mac: Ethernet MAC instance
* @param[in] phy_addr: PHY chip address (0~31)
* @param[in] phy_reg: PHY register index code
* @param[out] reg_value: PHY register value
*
* @return
* - ESP_OK: read PHY register successfully
* - ESP_ERR_INVALID_ARG: read PHY register failed because of invalid argument
* - ESP_ERR_INVALID_STATE: read PHY register failed because of wrong state of MAC
* - ESP_FAIL: read PHY register failed because some other error occurred
*
*/
esp_err_t (*read_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value);
/**
* @brief Write PHY register
*
* @param[in] mac: Ethernet MAC instance
* @param[in] phy_addr: PHY chip address (0~31)
* @param[in] phy_reg: PHY register index code
* @param[in] reg_value: PHY register value
*
* @return
* - ESP_OK: write PHY register successfully
* - ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC
* - ESP_FAIL: write PHY register failed because some other error occurred
*
*/
esp_err_t (*write_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value);
/**
* @brief Set MAC address
*
* @param[in] mac: Ethernet MAC instance
* @param[in] addr: MAC address
*
* @return
* - ESP_OK: set MAC address successfully
* - ESP_ERR_INVALID_ARG: set MAC address failed because of invalid argument
* - ESP_FAIL: set MAC address failed because some other error occurred
*
*/
esp_err_t (*set_addr)(esp_eth_mac_t *mac, uint8_t *addr);
/**
* @brief Get MAC address
*
* @param[in] mac: Ethernet MAC instance
* @param[out] addr: MAC address
*
* @return
* - ESP_OK: get MAC address successfully
* - ESP_ERR_INVALID_ARG: get MAC address failed because of invalid argument
* - ESP_FAIL: get MAC address failed because some other error occurred
*
*/
esp_err_t (*get_addr)(esp_eth_mac_t *mac, uint8_t *addr);
/**
* @brief Set speed of MAC
*
* @param[in] ma:c Ethernet MAC instance
* @param[in] speed: MAC speed
*
* @return
* - ESP_OK: set MAC speed successfully
* - ESP_ERR_INVALID_ARG: set MAC speed failed because of invalid argument
* - ESP_FAIL: set MAC speed failed because some other error occurred
*
*/
esp_err_t (*set_speed)(esp_eth_mac_t *mac, eth_speed_t speed);
/**
* @brief Set duplex mode of MAC
*
* @param[in] mac: Ethernet MAC instance
* @param[in] duplex: MAC duplex
*
* @return
* - ESP_OK: set MAC duplex mode successfully
* - ESP_ERR_INVALID_ARG: set MAC duplex failed because of invalid argument
* - ESP_FAIL: set MAC duplex failed because some other error occurred
*
*/
esp_err_t (*set_duplex)(esp_eth_mac_t *mac, eth_duplex_t duplex);
/**
* @brief Set link status of MAC
*
* @param[in] mac: Ethernet MAC instance
* @param[in] link: Link status
*
* @return
* - ESP_OK: set link status successfully
* - ESP_ERR_INVALID_ARG: set link status failed because of invalid argument
* - ESP_FAIL: set link status failed because some other error occurred
*
*/
esp_err_t (*set_link)(esp_eth_mac_t *mac, eth_link_t link);
/**
* @brief Set promiscuous of MAC
*
* @param[in] mac: Ethernet MAC instance
* @param[in] enable: set true to enable promiscuous mode; set false to disable promiscuous mode
*
* @return
* - ESP_OK: set promiscuous mode successfully
* - ESP_FAIL: set promiscuous mode failed because some error occurred
*
*/
esp_err_t (*set_promiscuous)(esp_eth_mac_t *mac, bool enable);
/**
* @brief Free memory of Ethernet MAC
*
* @param[in] mac: Ethernet MAC instance
*
* @return
* - ESP_OK: free Ethernet MAC instance successfully
* - ESP_FAIL: free Ethernet MAC instance failed because some error occurred
*
*/
esp_err_t (*del)(esp_eth_mac_t *mac);
};
/**
* @brief Configuration of Ethernet MAC object
*
*/
typedef struct {
uint32_t sw_reset_timeout_ms; /*!< Software reset timeout value (Unit: ms) */
uint32_t rx_task_stack_size; /*!< Stack size of the receive task */
uint32_t rx_task_prio; /*!< Priority of the receive task */
uint32_t queue_len; /*!< Length of the transaction queue */
} eth_mac_config_t;
/**
* @brief Default configuration for Ethernet MAC object
*
*/
#define ETH_MAC_DEFAULT_CONFIG() \
{ \
.sw_reset_timeout_ms = 100, \
.rx_task_stack_size = 4096, \
.rx_task_prio = 15, \
.queue_len = 100, \
}
/**
* @brief Create ESP32 Ethernet MAC instance
*
* @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_mac_config_t *config);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,227 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "esp_eth_com.h"
#include "sdkconfig.h"
/**
* @brief Ethernet PHY
*
*/
typedef struct esp_eth_phy_s esp_eth_phy_t;
/**
* @brief Ethernet PHY
*
*/
struct esp_eth_phy_s {
/**
* @brief Set mediator for PHY
*
* @param[in] phy: Ethernet PHY instance
* @param[in] mediator: mediator of Ethernet driver
*
* @return
* - ESP_OK: set mediator for Ethernet PHY instance successfully
* - ESP_ERR_INVALID_ARG: set mediator for Ethernet PHY instance failed because of some invalid arguments
*
*/
esp_err_t (*set_mediator)(esp_eth_phy_t *phy, esp_eth_mediator_t *mediator);
/**
* @brief Reset Ethernet PHY
*
* @param[in] phy: Ethernet PHY instance
*
* @return
* - ESP_OK: reset Ethernet PHY successfully
* - ESP_FAIL: reset Ethernet PHY failed because some error occurred
*
*/
esp_err_t (*reset)(esp_eth_phy_t *phy);
/**
* @brief Initialize Ethernet PHY
*
* @param[in] phy: Ethernet PHY instance
*
* @return
* - ESP_OK: initialize Ethernet PHY successfully
* - ESP_FAIL: initialize Ethernet PHY failed because some error occurred
*
*/
esp_err_t (*init)(esp_eth_phy_t *phy);
/**
* @brief Deinitialize Ethernet PHY
*
* @param[in] phyL Ethernet PHY instance
*
* @return
* - ESP_OK: deinitialize Ethernet PHY successfully
* - ESP_FAIL: deinitialize Ethernet PHY failed because some error occurred
*
*/
esp_err_t (*deinit)(esp_eth_phy_t *phy);
/**
* @brief Start auto negotiation
*
* @param[in] phy: Ethernet PHY instance
*
* @return
* - ESP_OK: restart auto negotiation successfully
* - ESP_FAIL: restart auto negotiation failed because some error occurred
*
*/
esp_err_t (*negotiate)(esp_eth_phy_t *phy);
/**
* @brief Get Ethernet PHY link status
*
* @param[in] phy: Ethernet PHY instance
*
* @return
* - ESP_OK: get Ethernet PHY link status successfully
* - ESP_FAIL: get Ethernet PHY link status failed because some error occurred
*
*/
esp_err_t (*get_link)(esp_eth_phy_t *phy);
/**
* @brief Power control of Ethernet PHY
*
* @param[in] phy: Ethernet PHY instance
* @param[in] enable: set true to power on Ethernet PHY; ser false to power off Ethernet PHY
*
* @return
* - ESP_OK: control Ethernet PHY power successfully
* - ESP_FAIL: control Ethernet PHY power failed because some error occurred
*
*/
esp_err_t (*pwrctl)(esp_eth_phy_t *phy, bool enable);
/**
* @brief Set PHY chip address
*
* @param[in] phy: Ethernet PHY instance
* @param[in] addr: PHY chip address
*
* @return
* - ESP_OK: set Ethernet PHY address successfully
* - ESP_FAIL: set Ethernet PHY address failed because some error occurred
*
*/
esp_err_t (*set_addr)(esp_eth_phy_t *phy, uint32_t addr);
/**
* @brief Get PHY chip address
*
* @param[in] phy: Ethernet PHY instance
* @param[out] addr: PHY chip address
*
* @return
* - ESP_OK: get Ethernet PHY address successfully
* - ESP_ERR_INVALID_ARG: get Ethernet PHY address failed because of invalid argument
*
*/
esp_err_t (*get_addr)(esp_eth_phy_t *phy, uint32_t *addr);
/**
* @brief Free memory of Ethernet PHY instance
*
* @param[in] phy: Ethernet PHY instance
*
* @return
* - ESP_OK: free PHY instance successfully
* - ESP_FAIL: free PHY instance failed because some error occurred
*
*/
esp_err_t (*del)(esp_eth_phy_t *phy);
};
/**
* @brief Ethernet PHY configuration
*
*/
typedef struct {
uint32_t phy_addr; /*!< PHY address */
uint32_t reset_timeout_ms; /*!< Reset timeout value (Unit: ms) */
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
} eth_phy_config_t;
/**
* @brief Default configuration for Ethernet PHY object
*
*/
#define ETH_PHY_DEFAULT_CONFIG() \
{ \
.phy_addr = 1, \
.reset_timeout_ms = 100, \
.autonego_timeout_ms = 4000 \
}
/**
* @brief Create a PHY instance of IP101
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of RTL8201
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of LAN8720
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config);
/**
* @brief Create a PHY instance of DP83848
*
* @param[in] config: configuration of PHY
*
* @return
* - instance: create PHY instance successfully
* - NULL: create PHY instance failed because some error occurred
*/
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,163 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/******************Basic PHY Registers*******************/
/**
* @brief BMCR(Basic Mode Control Register)
*
*/
typedef union {
struct {
uint32_t reserved : 7; /*!< Reserved */
uint32_t collision_test : 1; /*!< Collision test */
uint32_t duplex_mode : 1; /*!< Duplex mode:Full Duplex(1) and Half Duplex(0) */
uint32_t restart_auto_nego : 1; /*!< Restart auto-negotiation */
uint32_t isolate : 1; /*!< Isolate the PHY from MII except the SMI interface */
uint32_t power_down : 1; /*!< Power off PHY except SMI interface */
uint32_t en_auto_nego : 1; /*!< Enable auto negotiation */
uint32_t speed_select : 1; /*!< Select speed: 100Mbps(1) and 10Mbps(0) */
uint32_t en_loopback : 1; /*!< Enables transmit data to be routed to the receive path */
uint32_t reset : 1; /*!< Reset PHY registers. This bit is self-clearing. */
};
uint32_t val;
} bmcr_reg_t;
#define ETH_PHY_BMCR_REG_ADDR (0x00)
/**
* @brief BMSR(Basic Mode Status Register)
*
*/
typedef union {
struct {
uint32_t ext_capability : 1; /*!< Extended register capability */
uint32_t jabber_detect : 1; /*!< Jabber condition detected */
uint32_t link_status : 1; /*!< Link status */
uint32_t auto_nego_ability : 1; /*!< Auto negotiation ability */
uint32_t remote_fault : 1; /*!< Remote fault detected */
uint32_t auto_nego_complete : 1; /*!< Auto negotiation completed */
uint32_t mf_preamble_suppress : 1; /*!< Preamble suppression capability for management frame */
uint32_t reserved : 1; /*!< Reserved */
uint32_t ext_status : 1; /*!< Extended Status */
uint32_t base100_t2_hdx : 1; /*!< 100Base-T2 Half Duplex capability */
uint32_t base100_t2_fdx : 1; /*!< 100Base-T2 Full Duplex capability */
uint32_t base10_t_hdx : 1; /*!< 10Base-T Half Duplex capability */
uint32_t base10_t_fdx : 1; /*!< 10Base-T Full Duplex capability */
uint32_t base100_tx_hdx : 1; /*!< 100Base-Tx Half Duplex capability */
uint32_t base100_tx_fdx : 1; /*!< 100Base-Tx Full Duplex capability */
uint32_t based100_t4 : 1; /*!< 100Base-T4 capability */
};
uint32_t val;
} bmsr_reg_t;
#define ETH_PHY_BMSR_REG_ADDR (0x01)
/**
* @brief PHYIDR1(PHY Identifier Register 1)
*
*/
typedef union {
struct {
uint32_t oui_msb : 16; /*!< Organizationally Unique Identifier(OUI) most significant bits */
};
uint32_t val;
} phyidr1_reg_t;
#define ETH_PHY_IDR1_REG_ADDR (0x02)
/**
* @brief PHYIDR2(PHY Identifier Register 2)
*
*/
typedef union {
struct {
uint32_t model_revision : 4; /*!< Model revision number */
uint32_t vendor_model : 6; /*!< Vendor model number */
uint32_t oui_lsb : 6; /*!< Organizationally Unique Identifier(OUI) least significant bits */
};
uint32_t val;
} phyidr2_reg_t;
#define ETH_PHY_IDR2_REG_ADDR (0x03)
/**
* @brief ANAR(Auto-Negotiation Advertisement Register)
*
*/
typedef union {
struct {
uint32_t protocol_select : 5; /*!< Binary encoded selector supported by this PHY */
uint32_t base10_t : 1; /*!< 10Base-T support */
uint32_t base10_t_fd : 1; /*!< 10Base-T full duplex support */
uint32_t base100_tx : 1; /*!< 100Base-TX support */
uint32_t base100_tx_fd : 1; /*!< 100Base-TX full duplex support */
uint32_t base100_t4 : 1; /*!< 100Base-T4 support */
uint32_t symmetric_pause : 1; /*!< Symmetric pause support for full duplex links */
uint32_t asymmetric_pause : 1; /*!< Asymmetric pause support for full duplex links */
uint32_t reserved1 : 1; /*!< Reserved */
uint32_t remote_fault : 1; /*!< Advertise remote fault detection capability */
uint32_t acknowledge : 1; /*!< Link partner ability data reception acknowledged */
uint32_t next_page : 1; /*!< Next page indication, if set, next page transfer is desired */
};
uint32_t val;
} anar_reg_t;
#define ETH_PHY_ANAR_REG_ADDR (0x04)
/**
* @brief ANLPAR(Auto-Negotiation Link Partner Ability Register)
*
*/
typedef union {
struct {
uint32_t protocol_select : 5; /*!< Link Partners binary encoded node selector */
uint32_t base10_t : 1; /*!< 10Base-T support */
uint32_t base10_t_fd : 1; /*!< 10Base-T full duplex support */
uint32_t base100_tx : 1; /*!< 100Base-TX support */
uint32_t base100_tx_fd : 1; /*!< 100Base-TX full duplex support */
uint32_t base100_t4 : 1; /*!< 100Base-T4 support */
uint32_t symmetric_pause : 1; /*!< Symmetric pause supported by Link Partner */
uint32_t asymmetric_pause : 1; /*!< Asymmetric pause supported by Link Partner */
uint32_t reserved : 1; /*!< Reserved */
uint32_t remote_fault : 1; /*!< Link partner is indicating a remote fault */
uint32_t acknowledge : 1; /*!< Acknowledges from link partner */
uint32_t next_page : 1; /*!< Next page indication */
};
uint32_t val;
} anlpar_reg_t;
#define ETH_PHY_ANLPAR_REG_ADDR (0x05)
/**
* @brief ANER(Auto-Negotiate Expansion Register)
*
*/
typedef union {
struct {
uint32_t link_partner_auto_nego_able : 1; /*!< Link partner auto-negotiation ability */
uint32_t link_page_received : 1; /*!< Link code word page has received */
uint32_t next_page_able : 1; /*!< Next page ablility */
uint32_t link_partner_next_page_able : 1; /*!< Link partner next page ability */
uint32_t parallel_detection_fault : 1; /*!< Parallel detection fault */
uint32_t reserved : 11; /*!< Reserved */
};
uint32_t val;
} aner_reg_t;
#define ETH_PHY_ANER_REG_ADDR (0x06)
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,8 @@
[mapping:esp_eth]
archive: libesp_eth.a
entries:
esp_eth_mac_esp32:emac_hal_tx_complete_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_tx_unavail_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text)

View file

@ -0,0 +1,284 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
static const char *TAG = "esp_eth";
#define ETH_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
ESP_EVENT_DEFINE_BASE(ETH_EVENT);
/**
* @brief The Ethernet driver mainly consists of PHY, MAC and
* the mediator who will handle the request/response from/to MAC, PHY and Users.
* Ethernet driver adopts an OS timer to check the link status periodically.
* This structure preserves some important Ethernet attributes (e.g. speed, duplex, link).
* Function stack_input is the channel which set by user, it will deliver all received packets.
* If stack_input is set to NULL, then all received packets will be passed to tcp/ip stack.
* on_lowlevel_init_done and on_lowlevel_deinit_done are callbacks set by user.
* In the callback, user can do any low level operations (e.g. enable/disable crystal clock).
*/
typedef struct {
esp_eth_mediator_t mediator;
esp_eth_phy_t *phy;
esp_eth_mac_t *mac;
TimerHandle_t check_link_timer;
eth_speed_t speed;
eth_duplex_t duplex;
eth_link_t link;
esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length);
esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle);
esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle);
} esp_eth_driver_t;
////////////////////////////////Mediator Functions////////////////////////////////////////////
// Following functions are owned by mediator, which will get invoked by MAC or PHY.
// Mediator functions need to find the right actor (MAC, PHY or user) to perform the operation.
// So in the head of mediator function, we have to get the esp_eth_driver_t pointer.
// With this pointer, we could deliver the task to the real actor (MAC, PHY or user).
// This might sound excessive, but is helpful to separate the PHY with MAC (they can not contact with each other directly).
// For more details, please refer to WiKi. https://en.wikipedia.org/wiki/Mediator_pattern
//////////////////////////////////////////////////////////////////////////////////////////////
static esp_err_t eth_phy_reg_read(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
esp_eth_mac_t *mac = eth_driver->mac;
return mac->read_phy_reg(mac, phy_addr, phy_reg, reg_value);
}
static esp_err_t eth_phy_reg_write(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
{
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
esp_eth_mac_t *mac = eth_driver->mac;
return mac->write_phy_reg(mac, phy_addr, phy_reg, reg_value);
}
static esp_err_t eth_stack_input(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length)
{
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
if (!eth_driver->stack_input) {
return tcpip_adapter_eth_input(buffer, length, NULL);
} else {
return eth_driver->stack_input((esp_eth_handle_t)eth_driver, buffer, length);
}
}
static esp_err_t eth_on_state_changed(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
esp_eth_mac_t *mac = eth_driver->mac;
switch (state) {
case ETH_STATE_LLINIT: {
if (eth_driver->on_lowlevel_init_done) {
ETH_CHECK(eth_driver->on_lowlevel_init_done(eth_driver) == ESP_OK, "extra lowlevel init failed", err, ESP_FAIL);
}
break;
}
case ETH_STATE_DEINIT: {
if (eth_driver->on_lowlevel_deinit_done) {
ETH_CHECK(eth_driver->on_lowlevel_deinit_done(eth_driver) == ESP_OK, "extra lowlevel deinit failed", err, ESP_FAIL);
}
break;
}
case ETH_STATE_LINK: {
eth_link_t link = (eth_link_t)args;
ETH_CHECK(mac->set_link(mac, link) == ESP_OK, "ethernet mac set link failed", err, ESP_FAIL);
eth_driver->link = link;
if (link == ETH_LINK_UP) {
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_CONNECTED event failed", err, ESP_FAIL);
} else if (link == ETH_LINK_DOWN) {
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_DISCONNECTED event failed", err, ESP_FAIL);
}
break;
}
case ETH_STATE_SPEED: {
eth_speed_t speed = (eth_speed_t)args;
ETH_CHECK(mac->set_speed(mac, speed) == ESP_OK, "ethernet mac set speed failed", err, ESP_FAIL);
eth_driver->speed = speed;
break;
}
case ETH_STATE_DUPLEX: {
eth_duplex_t duplex = (eth_duplex_t)args;
ETH_CHECK(mac->set_duplex(mac, duplex) == ESP_OK, "ethernet mac set duplex failed", err, ESP_FAIL);
eth_driver->duplex = duplex;
break;
}
default:
ETH_CHECK(false, "unknown ethernet state: %d", err, ESP_ERR_INVALID_ARG, state);
break;
}
return ESP_OK;
err:
return ret;
}
static void eth_check_link_timer_cb(TimerHandle_t xTimer)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)pvTimerGetTimerID(xTimer);
esp_eth_phy_t *phy = eth_driver->phy;
phy->get_link(phy);
}
////////////////////////////////User face APIs////////////////////////////////////////////////
// User has to pass the handle of Ethernet driver to each API.
// Different Ethernet driver instance is identified with a unique handle.
// It's helpful for us to support multiple Ethernet port on ESP32.
//////////////////////////////////////////////////////////////////////////////////////////////
esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl)
{
esp_err_t ret = ESP_OK;
ETH_CHECK(config, "eth config can't be null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(out_hdl, "eth handle can't be null", err, ESP_ERR_INVALID_ARG);
esp_eth_mac_t *mac = config->mac;
esp_eth_phy_t *phy = config->phy;
ETH_CHECK(mac && phy, "can't set eth->mac or eth->phy to null", err, ESP_ERR_INVALID_ARG);
esp_eth_driver_t *eth_driver = calloc(1, sizeof(esp_eth_driver_t));
ETH_CHECK(eth_driver, "request memory for eth_driver failed", err, ESP_ERR_NO_MEM);
eth_driver->mac = mac;
eth_driver->phy = phy;
eth_driver->link = ETH_LINK_DOWN;
eth_driver->duplex = ETH_DUPLEX_HALF;
eth_driver->speed = ETH_SPEED_10M;
eth_driver->stack_input = config->stack_input;
eth_driver->on_lowlevel_init_done = config->on_lowlevel_init_done;
eth_driver->on_lowlevel_deinit_done = config->on_lowlevel_deinit_done;
eth_driver->mediator.phy_reg_read = eth_phy_reg_read;
eth_driver->mediator.phy_reg_write = eth_phy_reg_write;
eth_driver->mediator.stack_input = eth_stack_input;
eth_driver->mediator.on_state_changed = eth_on_state_changed;
ETH_CHECK(mac->set_mediator(mac, &eth_driver->mediator) == ESP_OK, "set mediator for mac failed", err_mediator, ESP_FAIL);
ETH_CHECK(phy->set_mediator(phy, &eth_driver->mediator) == ESP_OK, "set mediator for phy failed", err_mediator, ESP_FAIL);
ETH_CHECK(mac->init(mac) == ESP_OK, "init mac failed", err_init_mac, ESP_FAIL);
ETH_CHECK(phy->init(phy) == ESP_OK, "init phy failed", err_init_phy, ESP_FAIL);
eth_driver->check_link_timer = xTimerCreate("eth_link_timer", pdMS_TO_TICKS(config->check_link_period_ms), pdTRUE,
eth_driver, eth_check_link_timer_cb);
ETH_CHECK(eth_driver->check_link_timer, "create eth_link_timer failed", err_create_timer, ESP_FAIL);
ETH_CHECK(xTimerStart(eth_driver->check_link_timer, 0) == pdPASS, "start eth_link_timer failed", err_start_timer, ESP_FAIL);
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_START event failed", err_event, ESP_FAIL);
*out_hdl = (esp_eth_handle_t)eth_driver;
return ESP_OK;
err_event:
xTimerStop(eth_driver->check_link_timer, 0);
err_start_timer:
xTimerDelete(eth_driver->check_link_timer, 0);
err_create_timer:
phy->deinit(phy);
err_init_phy:
mac->deinit(mac);
err_init_mac:
err_mediator:
free(eth_driver);
err:
return ret;
}
esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
esp_eth_mac_t *mac = eth_driver->mac;
esp_eth_phy_t *phy = eth_driver->phy;
ETH_CHECK(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, "delete eth_link_timer failed", err, ESP_FAIL);
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL);
ETH_CHECK(phy->deinit(phy) == ESP_OK, "deinit phy failed", err, ESP_FAIL);
ETH_CHECK(mac->deinit(mac) == ESP_OK, "deinit mac failed", err, ESP_FAIL);
free(eth_driver);
return ESP_OK;
err:
return ret;
}
esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, uint8_t *buf, uint32_t length)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
esp_eth_mac_t *mac = eth_driver->mac;
return mac->transmit(mac, buf, length);
err:
return ret;
}
esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
esp_eth_mac_t *mac = eth_driver->mac;
return mac->receive(mac, buf, length);
err:
return ret;
}
esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
esp_eth_mac_t *mac = eth_driver->mac;
esp_eth_phy_t *phy = eth_driver->phy;
switch (cmd) {
case ETH_CMD_S_MAC_ADDR:
ETH_CHECK(data, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(mac->set_addr(mac, (uint8_t *)data) == ESP_OK, "set mac address failed", err, ESP_FAIL);
break;
case ETH_CMD_G_MAC_ADDR:
ETH_CHECK(data, "no mem to store mac addr", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(mac->get_addr(mac, (uint8_t *)data) == ESP_OK, "get mac address failed", err, ESP_FAIL);
break;
case ETH_CMD_S_PHY_ADDR:
ETH_CHECK(data, "can't set phy addr to null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(phy->set_addr(phy, (uint32_t)data) == ESP_OK, "set phy address failed", err, ESP_FAIL);
break;
case ETH_CMD_G_PHY_ADDR:
ETH_CHECK(data, "no mem to store phy addr", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(phy->get_addr(phy, (uint32_t *)data) == ESP_OK, "get phy address failed", err, ESP_FAIL);
break;
case ETH_CMD_G_SPEED:
ETH_CHECK(data, "no mem to store speed value", err, ESP_ERR_INVALID_ARG);
*(eth_speed_t *)data = eth_driver->speed;
break;
case ETH_CMD_S_PROMISCUOUS:
ETH_CHECK(mac->set_promiscuous(mac, (bool)data) == ESP_OK, "set promiscuous mode failed", err, ESP_FAIL);
break;
default:
ETH_CHECK(false, "unknown io command: %d", err, ESP_ERR_INVALID_ARG, cmd);
break;
}
return ESP_OK;
err:
return ret;
}

View file

@ -0,0 +1,454 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "esp_system.h"
#include "esp_heap_caps.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "hal/emac.h"
#include "soc/soc.h"
#include "sdkconfig.h"
static const char *TAG = "emac_esp32";
#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
#define RX_QUEUE_WAIT_MS (20)
typedef struct {
esp_eth_mac_t parent;
esp_eth_mediator_t *eth;
emac_hal_context_t *hal;
intr_handle_t intr_hdl;
SemaphoreHandle_t rx_counting_sem;
TaskHandle_t rx_task_hdl;
const char *name;
uint32_t sw_reset_timeout_ms;
uint32_t frames_remain;
uint32_t rx_task_stack_size;
uint32_t rx_task_prio;
uint32_t queue_len;
uint8_t addr[6];
uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM];
uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM];
} emac_esp32_t;
static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
emac->eth = eth;
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
emac_hal_set_phy_data(emac->hal, reg_value);
emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, true);
/* Delay some time and Check for the Busy flag */
ets_delay_us(1000);
MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
emac_hal_set_phy_cmd(emac->hal, phy_addr, phy_reg, false);
/* Delay some time and Check for the Busy flag */
ets_delay_us(1000);
MAC_CHECK(!emac_hal_is_mii_busy(emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
/* Store value */
*reg_value = emac_hal_get_phy_data(emac->hal);
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
memcpy(emac->addr, addr, 6);
emac_hal_set_address(emac->hal, emac->addr);
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
memcpy(addr, emac->addr, 6);
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_set_link(esp_eth_mac_t *mac, eth_link_t link)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
switch (link) {
case ETH_LINK_UP:
MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL);
emac_hal_start(emac->hal);
break;
case ETH_LINK_DOWN:
MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL);
emac_hal_stop(emac->hal);
break;
default:
MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
break;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
switch (speed) {
case ETH_SPEED_10M:
emac_hal_set_speed(emac->hal, EMAC_SPEED_10M);
break;
case ETH_SPEED_100M:
emac_hal_set_speed(emac->hal, EMAC_SPEED_100M);
break;
default:
MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
break;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
switch (duplex) {
case ETH_DUPLEX_HALF:
emac_hal_set_duplex(emac->hal, EMAC_DUPLEX_HALF);
break;
case ETH_DUPLEX_FULL:
emac_hal_set_duplex(emac->hal, EMAC_DUPLEX_FULL);
break;
default:
MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
break;
}
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_set_promiscuous(esp_eth_mac_t *mac, bool enable)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
emac_hal_set_promiscuous(emac->hal, enable);
return ESP_OK;
}
static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG);
MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG);
/* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */
MAC_CHECK(emac_hal_get_tx_desc_owner(emac->hal) == EMAC_DMADESC_OWNER_CPU,
"CPU doesn't own the Tx Descriptor", err, ESP_ERR_INVALID_STATE);
emac_hal_transmit_frame(emac->hal, buf, length);
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
*length = emac_hal_receive_frame(emac->hal, buf, &emac->frames_remain);
return ESP_OK;
err:
return ret;
}
static void emac_esp32_rx_task(void *arg)
{
emac_esp32_t *emac = (emac_esp32_t *)arg;
esp_eth_mediator_t *eth = emac->eth;
uint8_t *buffer = NULL;
uint32_t length = 0;
while (1) {
if (xSemaphoreTake(emac->rx_counting_sem, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS)) == pdTRUE) {
buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE);
if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
eth->stack_input(eth, buffer, length);
} else {
free(buffer);
}
}
/* there might be some frames left in DMA buffer */
else if (emac->frames_remain) {
xSemaphoreGive(emac->rx_counting_sem);
}
}
vTaskDelete(NULL);
}
static void emac_esp32_init_smi_gpio(void)
{
/* Setup SMI MDC GPIO */
gpio_set_direction(CONFIG_ETH_SMI_MDC_GPIO, GPIO_MODE_OUTPUT);
gpio_matrix_out(CONFIG_ETH_SMI_MDC_GPIO, EMAC_MDC_O_IDX, false, false);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDC_GPIO], PIN_FUNC_GPIO);
/* Setup SMI MDIO GPIO */
gpio_set_direction(CONFIG_ETH_SMI_MDIO_GPIO, GPIO_MODE_INPUT_OUTPUT);
gpio_matrix_out(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDO_O_IDX, false, false);
gpio_matrix_in(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDI_I_IDX, false);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDIO_GPIO], PIN_FUNC_GPIO);
}
static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
esp_eth_mediator_t *eth = emac->eth;
/* enable peripheral clock */
periph_module_enable(PERIPH_EMAC_MODULE);
/* enable clock, config gpio, etc */
emac_hal_lowlevel_init(emac->hal);
/* init gpio used by gpio */
emac_esp32_init_smi_gpio();
#if CONFIG_ETH_PHY_USE_RST
gpio_pad_select_gpio(CONFIG_ETH_PHY_RST_GPIO);
gpio_set_direction(CONFIG_ETH_PHY_RST_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 1);
#endif
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
/* software reset */
emac_hal_reset(emac->hal);
uint32_t to = 0;
for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
if (emac_hal_is_reset_done(emac->hal)) {
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
/* set smi clock */
emac_hal_set_csr_clock_range(emac->hal);
/* reset descriptor chain */
emac_hal_reset_desc_chain(emac->hal);
/* init mac registers by default */
emac_hal_init_mac_default(emac->hal);
/* init dma registers by default */
emac_hal_init_dma_default(emac->hal);
/* get emac address from efuse */
MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
/* set MAC address to emac register */
emac_hal_set_address(emac->hal, emac->addr);
/* Interrupt configuration */
MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_hal_isr,
&emac->hal, &(emac->intr_hdl)) == ESP_OK,
"alloc emac interrupt failed", err, ESP_FAIL);
/* create counting semaphore */
emac->rx_counting_sem = xSemaphoreCreateCounting(emac->queue_len, 0);
MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, ESP_FAIL);
/* create rx task */
BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", emac->rx_task_stack_size, emac,
emac->rx_task_prio, &emac->rx_task_hdl);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, ESP_FAIL);
return ESP_OK;
err_task:
vSemaphoreDelete(emac->rx_counting_sem);
err_sem:
esp_intr_free(emac->intr_hdl);
err:
periph_module_disable(PERIPH_EMAC_MODULE);
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
return ret;
}
static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
esp_eth_mediator_t *eth = emac->eth;
#if CONFIG_ETH_PHY_USE_RST
gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0);
#endif
emac_hal_stop(emac->hal);
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL) == ESP_OK, "lowlevel deinit failed", err, ESP_FAIL);
MAC_CHECK(esp_intr_free(emac->intr_hdl) == ESP_OK, "free emac interrupt failed", err, ESP_FAIL);
vTaskDelete(emac->rx_task_hdl);
vSemaphoreDelete(emac->rx_counting_sem);
periph_module_disable(PERIPH_EMAC_MODULE);
return ESP_OK;
err:
return ret;
}
static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
int i = 0;
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->hal->rx_buf[i]);
}
for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->hal->tx_buf[i]);
}
free(emac->hal->descriptors);
free(emac->hal);
free(emac);
return ESP_OK;
}
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
{
esp_eth_mac_t *ret = NULL;
MAC_CHECK(config, "can't set mac config to null", err, NULL);
emac_esp32_t *emac = calloc(1, sizeof(emac_esp32_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* alloc memory for ethernet dma descriptor */
uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
void *descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
MAC_CHECK(descriptors, "calloc descriptors failed", err_desc, NULL);
emac->hal = (emac_hal_context_t *)calloc(1, sizeof(emac_hal_context_t));
MAC_CHECK(emac->hal, "calloc emac hal failed", err_hal, NULL);
int i = 0;
/* alloc memory for ethernet dma buffer */
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
if (!(emac->rx_buf[i])) {
break;
}
}
if (i != CONFIG_ETH_DMA_RX_BUFFER_NUM) {
for (--i; i >= 0; i--) {
free(emac->rx_buf[i]);
}
goto err_buffer;
}
for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
if (!(emac->tx_buf[i])) {
break;
}
}
if (i != CONFIG_ETH_DMA_TX_BUFFER_NUM) {
for (--i; i >= 0; i--) {
free(emac->tx_buf[i]);
}
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
goto err_buffer;
}
/* initialize hal layer driver */
emac_hal_init(emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
emac->rx_task_stack_size = config->rx_task_stack_size;
emac->rx_task_prio = config->rx_task_prio;
emac->queue_len = config->queue_len;
emac->name = "emac_esp32";
emac->parent.set_mediator = emac_esp32_set_mediator;
emac->parent.init = emac_esp32_init;
emac->parent.deinit = emac_esp32_deinit;
emac->parent.del = emac_esp32_del;
emac->parent.write_phy_reg = emac_esp32_write_phy_reg;
emac->parent.read_phy_reg = emac_esp32_read_phy_reg;
emac->parent.set_addr = emac_esp32_set_addr;
emac->parent.get_addr = emac_esp32_get_addr;
emac->parent.set_speed = emac_esp32_set_speed;
emac->parent.set_duplex = emac_esp32_set_duplex;
emac->parent.set_link = emac_esp32_set_link;
emac->parent.set_promiscuous = emac_esp32_set_promiscuous;
emac->parent.transmit = emac_esp32_transmit;
emac->parent.receive = emac_esp32_receive;
return &(emac->parent);
err_buffer:
free(emac->hal);
err_hal:
free(descriptors);
err_desc:
free(emac);
err:
return ret;
}
void emac_hal_rx_complete_cb(void *arg)
{
emac_hal_context_t **hal_addr = (emac_hal_context_t **)arg;
emac_esp32_t *emac = __containerof(hal_addr, emac_esp32_t, hal);
BaseType_t high_task_wakeup;
/* send message to rx thread */
xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup);
if (high_task_wakeup != pdFALSE) {
portYIELD_FROM_ISR();
}
}
void emac_hal_rx_unavail_cb(void *arg)
{
emac_hal_context_t **hal_addr = (emac_hal_context_t **)arg;
emac_esp32_t *emac = __containerof(hal_addr, emac_esp32_t, hal);
BaseType_t high_task_wakeup;
/* send message to rx thread */
xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup);
if (high_task_wakeup != pdFALSE) {
portYIELD_FROM_ISR();
}
}

View file

@ -0,0 +1,303 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "dp83848";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
/**
* @brief PHYSTS(PHY Status Register)
*
*/
typedef union {
struct {
uint32_t link_status : 1; /* Link Status */
uint32_t speed_status : 1; /* Link Status */
uint32_t duplex_status : 1; /* Duplex Status */
uint32_t loopback_status : 1; /* MII Loopback */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
uint32_t jabber_detect : 1; /* Jabber Detect */
uint32_t remote_fault : 1; /* Remote Fault */
uint32_t mii_interrupt : 1; /* MII Interrupt Pending */
uint32_t page_received : 1; /* Link Code Word Page Received */
uint32_t descrambler_lock : 1; /* Descrambler Lock */
uint32_t signal_detect : 1; /* Signal Detect */
uint32_t false_carrier_sense_latch : 1; /* False Carrier Sense Latch */
uint32_t polarity_status : 1; /* Polarity Status */
uint32_t receive_error_latch : 1; /* Receive Error Latch */
uint32_t mdix_mode : 1; /* MDI-X mode reported by auto-negotiation */
uint32_t reserved : 1; /* Reserved */
};
uint32_t val;
} physts_reg_t;
#define ETH_PHY_STS_REG_ADDR (0x10)
/**
* @brief PHYCR(PHY Control Register)
*
*/
typedef union {
struct {
uint32_t phy_addr : 5; /* PHY Address */
uint32_t led_cfg : 2; /* LED Configuration Modes */
uint32_t bypass_led_stretching : 1; /* Bypass LED Stretching */
uint32_t bist_start : 1; /* BIST Start */
uint32_t bist_status : 1; /* BIST Test Status */
uint32_t psr_15 : 1; /* BIST Sequence select */
uint32_t bist_force_error : 1; /* BIST Force Error */
uint32_t pause_trans_negotiate : 1; /* Pause Transmit Negotiated Status */
uint32_t pause_receive_negotiat : 1; /* Pause Receive Negotiated Status */
uint32_t force_mdix : 1; /* Force MDIX */
uint32_t en_auto_mdix : 1; /* Auto-MDIX Enable */
};
uint32_t val;
} phycr_reg_t;
#define ETH_PHY_CR_REG_ADDR (0x19)
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_dp83848_t;
static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for dp83848 to null", err);
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
dp83848->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t dp83848_get_link(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (dp83848->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dp83848->link_status = link;
}
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_reset(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "PHY reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
/* Start auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
physts_reg_t physts;
uint32_t to = 0;
for (to = 0; to < dp83848->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err);
if (bmsr.auto_nego_complete && physts.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= dp83848->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
speed = ETH_SPEED_100M;
}
if (physts.duplex_status) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (dp83848->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dp83848->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
} else {
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
PHY_CHECK(bmcr.power_down == 0, "power up failed", err);
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
dp83848->addr = addr;
return ESP_OK;
}
static esp_err_t dp83848_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
*addr = dp83848->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t dp83848_del(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
free(dp83848);
return ESP_OK;
}
static esp_err_t dp83848_init(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
/* Power on Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09, "wrong PHY chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t));
PHY_CHECK(dp83848, "calloc dp83848 object failed", err);
dp83848->name = "dp83848";
dp83848->addr = config->phy_addr;
dp83848->reset_timeout_ms = config->reset_timeout_ms;
dp83848->link_status = ETH_LINK_DOWN;
dp83848->autonego_timeout_ms = config->autonego_timeout_ms;
dp83848->parent.reset = dp83848_reset;
dp83848->parent.init = dp83848_init;
dp83848->parent.deinit = dp83848_deinit;
dp83848->parent.set_mediator = dp83848_set_mediator;
dp83848->parent.negotiate = dp83848_negotiate;
dp83848->parent.get_link = dp83848_get_link;
dp83848->parent.pwrctl = dp83848_pwrctl;
dp83848->parent.get_addr = dp83848_get_addr;
dp83848->parent.set_addr = dp83848_set_addr;
dp83848->parent.del = dp83848_del;
return &(dp83848->parent);
err:
return NULL;
}

View file

@ -0,0 +1,345 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "ip101";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
/**
* @brief PCR(Page Control Register)
*
*/
typedef union {
struct {
uint32_t register_page_select : 5; /* Select register page, default is 16 */
uint32_t reserved : 11; /* Reserved */
};
uint32_t val;
} pcr_reg_t;
#define ETH_PHY_PCR_REG_ADDR (0x14)
/**
* @brief ISR(Interrupt Status Register), Page 16
*
*/
typedef union {
struct {
uint32_t link_changed : 1; /* Flag to indicate link status change interrupt */
uint32_t duplex_changed : 1; /* Flag to indicate duplex change interrupt */
uint32_t speed_changed : 1; /* Flag to indicate speed change interrupt */
uint32_t intr_status : 1; /* Flag to indicate interrupt status */
uint32_t reserved1 : 4; /* Reserved */
uint32_t link_mask : 1; /* Mask link change interrupt */
uint32_t duplex_mask : 1; /* Mask duplex change interrupt */
uint32_t speed_mask : 1; /* Mask speed change interrupt */
uint32_t all_mask : 1; /* Mask all interrupt */
uint32_t reserved2 : 3; /* Reserved */
uint32_t use_intr_pin : 1; /* Set high to use INTR and INTR_32 as an interrupt pin */
};
uint32_t val;
} isr_reg_t;
#define ETH_PHY_ISR_REG_ADDR (0x11)
/**
* @brief PHY MDI/MDIX Control and Specific Status Register, Page 16
*
*/
typedef union {
struct {
uint32_t op_mode : 3; /* Operation Mode Idicator */
uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */
uint32_t reserved1 : 4; /* Reserved */
uint32_t link_up : 1; /* Indicate the link status is OK or FAIL */
uint32_t reserved2 : 7; /* Reserved */
};
uint32_t val;
} cssr_reg_t;
#define ETH_PHY_CSSR_REG_ADDR (0x1E)
/**
* @brief PSCR(PHY Specific Control Register), Page 1
*
*/
typedef union {
struct {
uint32_t reserved1 : 7; /* Reserved */
uint32_t force_link_100 : 1; /* Force Link 100 */
uint32_t force_link_10 : 1; /* Force Link 10 */
uint32_t reserved2 : 7; /* Reserved */
};
uint32_t val;
} pscr_reg_t;
#define ETH_PHY_PSCR_REG_ADDR (0x11)
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_ip101_t;
static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page)
{
esp_eth_mediator_t *eth = ip101->eth;
pcr_reg_t pcr = {
.register_page_select = page
};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_PCR_REG_ADDR, pcr.val) == ESP_OK, "write PCR failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for ip101 to null", err);
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
ip101->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t ip101_get_link(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (ip101->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
ip101->link_status = link;
}
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_reset(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* wait for reset complete */
uint32_t to = 0;
for (to = 0; to < ip101->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "PHY reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Start auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
if (bmsr.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= ip101->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
}
PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page failed", err);
/* Updata information about link, speed, duplex */
cssr_reg_t cssr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK, "read CSSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
switch (cssr.op_mode) {
case 0: //Link off
link = ETH_LINK_DOWN;
break;
case 1: //10M Half
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100M Half
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10M Full
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100M Full
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (ip101->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
ip101->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
} else {
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
PHY_CHECK(bmcr.power_down == 0, "power up failed", err);
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
ip101->addr = addr;
return ESP_OK;
}
static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
*addr = ip101->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t ip101_del(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
free(ip101);
return ESP_OK;
}
static esp_err_t ip101_init(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Power on Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong PHY chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
PHY_CHECK(ip101, "calloc ip101 object failed", err);
ip101->name = "ip101";
ip101->addr = config->phy_addr;
ip101->reset_timeout_ms = config->reset_timeout_ms;
ip101->link_status = ETH_LINK_DOWN;
ip101->autonego_timeout_ms = config->autonego_timeout_ms;
ip101->parent.reset = ip101_reset;
ip101->parent.init = ip101_init;
ip101->parent.deinit = ip101_deinit;
ip101->parent.set_mediator = ip101_set_mediator;
ip101->parent.negotiate = ip101_negotiate;
ip101->parent.get_link = ip101_get_link;
ip101->parent.pwrctl = ip101_pwrctl;
ip101->parent.get_addr = ip101_get_addr;
ip101->parent.set_addr = ip101_set_addr;
ip101->parent.del = ip101_del;
return &(ip101->parent);
err:
return NULL;
}

View file

@ -0,0 +1,385 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "lan8720";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
/**
* @brief MCSR(Mode Control Status Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t energy_is_on : 1; /* Energy is On */
uint32_t reserved2 : 4; /* Reserved */
uint32_t en_alternate_interrupt : 1; /* Enable Alternate Interrupt Mode */
uint32_t reserved3 : 2; /* Reserved */
uint32_t en_far_loopback : 1; /* Enable Far Loopback Mode */
uint32_t reserved4 : 3; /* Reserved */
uint32_t en_energy_detect_powerdown : 1; /* Enable Energy Detect Power Down */
uint32_t reserved5 : 2; /* Reserved */
};
uint32_t val;
} mcsr_reg_t;
#define ETH_PHY_MCSR_REG_ADDR (0x11)
/**
* @brief SMR(Special Modes Register)
*
*/
typedef union {
struct {
uint32_t phy_addr : 5; /* PHY Address */
uint32_t mode : 3; /* Transceiver Mode of Operation */
uint32_t reserved : 8; /* Reserved */
};
uint32_t val;
} smr_reg_t;
#define ETH_PHY_SMR_REG_ADDR (0x12)
/**
* @brief SECR(Symbol Error Counter Register)
*
*/
typedef union {
struct {
uint32_t symbol_err_count : 16; /* Symbol Error Counter */
};
uint32_t val;
} secr_reg_t;
#define EHT_PHY_SECR_REG_ADDR (0x1A)
/**
* @brief CSIR(Control Status Indications Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 4; /* Reserved */
uint32_t base10_t_polarity : 1; /* Polarity State of 10Base-T */
uint32_t reserved2 : 6; /* Reserved */
uint32_t dis_sqe : 1; /* Disable SQE test(Heartbeat) */
uint32_t reserved3 : 1; /* Reserved */
uint32_t select_channel : 1; /* Manual channel select:MDI(0) or MDIX(1) */
uint32_t reserved4 : 1; /* Reserved */
uint32_t auto_mdix_ctrl : 1; /* Auto-MDIX Control: EN(0) or DE(1) */
};
uint32_t val;
} scsir_reg_t;
#define ETH_PHY_CSIR_REG_ADDR (0x1B)
/**
* @brief ISR(Interrupt Source Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */
uint32_t parallel_detect_falut : 1; /* Parallel Detection Fault */
uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */
uint32_t link_down : 1; /* Link Down */
uint32_t remote_fault_detect : 1; /* Remote Fault Detect */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
uint32_t energy_on_generate : 1; /* ENERYON generated */
uint32_t reserved2 : 8; /* Reserved */
};
uint32_t val;
} isfr_reg_t;
#define ETH_PHY_ISR_REG_ADDR (0x1D)
/**
* @brief IMR(Interrupt Mask Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 1; /* Reserved */
uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */
uint32_t parallel_detect_falut : 1; /* Parallel Detection Fault */
uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */
uint32_t link_down : 1; /* Link Down */
uint32_t remote_fault_detect : 1; /* Remote Fault Detect */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
uint32_t energy_on_generate : 1; /* ENERYON generated */
uint32_t reserved2 : 8; /* Reserved */
};
uint32_t val;
} imr_reg_t;
#define ETH_PHY_IMR_REG_ADDR (0x1E)
/**
* @brief PSCSR(PHY Special Control Status Register)
*
*/
typedef union {
struct {
uint32_t reserved1 : 2; /* Reserved */
uint32_t speed_indication : 3; /* Speed Indication */
uint32_t reserved2 : 7; /* Reserved */
uint32_t auto_nego_done : 1; /* Auto Negotiation Done */
uint32_t reserved3 : 3; /* Reserved */
};
uint32_t val;
} pscsr_reg_t;
#define ETH_PHY_PSCSR_REG_ADDR (0x1F)
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_lan8720_t;
static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for lan8720 to null", err);
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
lan8720->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t lan8720_get_link(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (lan8720->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
lan8720->link_status = link;
}
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_reset(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* wait for reset complete */
uint32_t to = 0;
for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "PHY reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Start auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
pscsr_reg_t pscsr;
int32_t to = 0;
for (to = 0; to < lan8720->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err);
if (bmsr.auto_nego_complete && pscsr.auto_nego_done) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= lan8720->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (lan8720->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
lan8720->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
/* General Power Down Mode */
bmcr.power_down = 1;
} else {
/* Normal operation Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
PHY_CHECK(bmcr.power_down == 0, "power up failed", err);
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
lan8720->addr = addr;
return ESP_OK;
}
static esp_err_t lan8720_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
*addr = lan8720->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t lan8720_del(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
free(lan8720);
return ESP_OK;
}
static esp_err_t lan8720_init(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Power on Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong PHY chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t));
PHY_CHECK(lan8720, "calloc lan8720 object failed", err);
lan8720->name = "lan8720";
lan8720->addr = config->phy_addr;
lan8720->reset_timeout_ms = config->reset_timeout_ms;
lan8720->link_status = ETH_LINK_DOWN;
lan8720->autonego_timeout_ms = config->autonego_timeout_ms;
lan8720->parent.reset = lan8720_reset;
lan8720->parent.init = lan8720_init;
lan8720->parent.deinit = lan8720_deinit;
lan8720->parent.set_mediator = lan8720_set_mediator;
lan8720->parent.negotiate = lan8720_negotiate;
lan8720->parent.get_link = lan8720_get_link;
lan8720->parent.pwrctl = lan8720_pwrctl;
lan8720->parent.get_addr = lan8720_get_addr;
lan8720->parent.set_addr = lan8720_set_addr;
lan8720->parent.del = lan8720_del;
return &(lan8720->parent);
err:
return NULL;
}

View file

@ -0,0 +1,292 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "rtl8201";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
/**
* @brief PSMR(Power Saving Mode Register)
*
*/
typedef union {
struct {
uint16_t reserved : 15; /* Reserved */
uint16_t en_pwr_save : 1; /* Enable power saving mode */
};
uint16_t val;
} psmr_reg_t;
#define ETH_PHY_PSMR_REG_ADDR (0x18)
/**
* @brief PSR(Page Select Register)
*
*/
typedef union {
struct {
uint16_t page_select : 8; /* Select register page, default is 0 */
uint16_t reserved : 8; /* Reserved */
};
uint16_t val;
} psr_reg_t;
#define ETH_PHY_PSR_REG_ADDR (0x1F)
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_rtl8201_t;
static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page)
{
esp_eth_mediator_t *eth = rtl8201->eth;
psr_reg_t psr = {
.page_select = page
};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_PSR_REG_ADDR, psr.val) == ESP_OK, "write PSR failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for rtl8201 to null", err);
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
rtl8201->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (rtl8201->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
rtl8201->link_status = link;
}
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_reset(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "PHY reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Start auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < rtl8201->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
if (bmsr.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= rtl8201->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
}
PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page failed", err);
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (bmcr.duplex_mode) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (rtl8201->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
rtl8201->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
} else {
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
PHY_CHECK(bmcr.power_down == 0, "power up failed", err);
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
rtl8201->addr = addr;
return ESP_OK;
}
static esp_err_t rtl8201_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
*addr = rtl8201->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
}
static esp_err_t rtl8201_del(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
free(rtl8201);
return ESP_OK;
}
static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Power on Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, "wrong PHY chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
PHY_CHECK(rtl8201, "calloc rtl8201 object failed", err);
rtl8201->name = "rtl8201";
rtl8201->addr = config->phy_addr;
rtl8201->reset_timeout_ms = config->reset_timeout_ms;
rtl8201->link_status = ETH_LINK_DOWN;
rtl8201->autonego_timeout_ms = config->autonego_timeout_ms;
rtl8201->parent.reset = rtl8201_reset;
rtl8201->parent.init = rtl8201_init;
rtl8201->parent.deinit = rtl8201_deinit;
rtl8201->parent.set_mediator = rtl8201_set_mediator;
rtl8201->parent.negotiate = rtl8201_negotiate;
rtl8201->parent.get_link = rtl8201_get_link;
rtl8201->parent.pwrctl = rtl8201_pwrctl;
rtl8201->parent.get_addr = rtl8201_get_addr;
rtl8201->parent.set_addr = rtl8201_set_addr;
rtl8201->parent.del = rtl8201_del;
return &(rtl8201->parent);
err:
return NULL;
}

View file

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
PRIV_REQUIRES "unity" "test_utils" "esp_eth")

View file

@ -2,4 +2,6 @@
#Component Makefile
#
COMPONENT_SRCDIRS := .
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View file

@ -0,0 +1,91 @@
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tcpip_adapter.h"
#include "esp_event.h"
#include "unity.h"
#include "test_utils.h"
#include "esp_eth.h"
#include "esp_log.h"
static const char *TAG = "esp_eth_test";
/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
ESP_LOGI(TAG, "Ethernet Link Up");
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;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
const tcpip_adapter_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, "~~~~~~~~~~~");
}
TEST_CASE("esp32 emac io test", "[ethernet][ignore]")
{
TEST_ESP_OK(esp_event_loop_create_default());
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle));
vTaskDelay(pdMS_TO_TICKS(1000));
/* get MAC address */
uint8_t mac_addr[6];
memset(mac_addr, 0, sizeof(mac_addr));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr));
TEST_ASSERT(mac_addr[0] != 0);
/* get PHY address */
int phy_addr = -1;
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr));
TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31);
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_loop_delete_default());
}
TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]")
{
tcpip_adapter_init();
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle));
vTaskDelay(portMAX_DELAY);
}

View file

@ -6,7 +6,7 @@ idf_component_register(SRCS "default_event_loop.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "private_include"
REQUIRES log tcpip_adapter
PRIV_REQUIRES ethernet
PRIV_REQUIRES esp_eth
LDFRAGMENTS linker.lf)
if(GCC_NOT_5_2_0 AND CONFIG_ESP_EVENT_LOOP_PROFILING)

View file

@ -100,7 +100,7 @@ esp_err_t esp_event_loop_delete_default()
}
esp_err_t err;
err = esp_event_loop_delete(s_default_loop);
if (err != ESP_OK) {

View file

@ -1,8 +0,0 @@
idf_component_register(SRCS "emac_dev.c"
"emac_main.c"
"eth_phy/phy_common.c"
"eth_phy/phy_lan8720.c"
"eth_phy/phy_tlk110.c"
"eth_phy/phy_ip101.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES tcpip_adapter esp_event soc)

View file

@ -1,55 +0,0 @@
menu Ethernet
config ETH_DMA_RX_BUF_NUM
int "Number of DMA RX buffers"
range 3 20
default 10
help
Number of DMA receive buffers. Each buffer is 1600 bytes.
These buffers are allocated dynamically.
More buffers will increase throughput.
If flow ctrl is enabled, make sure this number is larger than 9.
config ETH_DMA_TX_BUF_NUM
int "Number of DMA TX buffers"
range 3 20
default 10
help
Number of DMA transmit buffers. Each buffer is 1600 bytes.
These buffers are allocated dynamically.
More buffers will increase throughput.
config ETH_EMAC_L2_TO_L3_RX_BUF_MODE
bool "Enable received buffers be copied to Layer3 from Layer2"
default y
help
If this option is selected, a copy of each received buffer will be allocated from the heap
before passing it to the IP Layer (L3).
Which means, the total amount of received buffers is limited by the heap size.
If this option is not selected, IP layer only uses the pointers to the DMA buffers owned by Ethernet MAC.
When Ethernet MAC doesn't have any available buffers left, it will drop the incoming packets.
config ETH_CHECK_LINK_STATUS_PERIOD_MS
int "Period (ms) of checking Ethernet linkup status"
range 1000 5000
default 2000
help
The emac driver uses an internal timer to check the Ethernet linkup status.
Here you should choose a valid interval time.
config ETH_EMAC_TASK_PRIORITY
int "EMAC_TASK_PRIORITY"
default 20
range 3 22
help
Priority of Ethernet MAC task.
config ETH_EMAC_TASK_STACK_SIZE
int "Stack Size of EMAC Task"
default 3072
range 2000 8000
help
Stack Size of Ethernet MAC task.
endmenu

View file

@ -1,5 +0,0 @@
#
# Component Makefile
#
COMPONENT_SRCDIRS := . eth_phy

View file

@ -1,125 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _EMAC_COMMON_H_
#define _EMAC_COMMON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_eth.h"
#include "emac_dev.h"
typedef uint32_t emac_sig_t;
typedef uint32_t emac_par_t;
typedef struct {
emac_sig_t sig;
emac_par_t par;
} emac_event_t;
enum emac_runtime_status {
EMAC_RUNTIME_NOT_INIT = 0,
EMAC_RUNTIME_INIT,
EMAC_RUNTIME_START,
EMAC_RUNTIME_STOP,
};
enum {
SIG_EMAC_RX_UNAVAIL,
SIG_EMAC_TX_DONE,
SIG_EMAC_RX_DONE,
SIG_EMAC_START,
SIG_EMAC_STOP,
SIG_EMAC_CHECK_LINK,
SIG_EMAC_MAX
};
struct emac_config_data {
eth_phy_base_t phy_addr;
eth_mode_t mac_mode;
eth_clock_mode_t clock_mode;
struct dma_extended_desc *dma_etx;
uint32_t cur_tx;
uint32_t dirty_tx;
int32_t cnt_tx;
struct dma_extended_desc *dma_erx;
uint32_t cur_rx;
uint32_t dirty_rx;
int32_t cnt_rx;
uint32_t rx_need_poll;
bool phy_link_up;
enum emac_runtime_status emac_status;
uint8_t macaddr[6];
eth_phy_func phy_init;
eth_tcpip_input_func emac_tcpip_input;
eth_gpio_config_func emac_gpio_config;
eth_phy_check_link_func emac_phy_check_link;
eth_phy_check_init_func emac_phy_check_init;
eth_phy_get_speed_mode_func emac_phy_get_speed_mode;
eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode;
bool emac_flow_ctrl_enable;
bool emac_flow_ctrl_partner_support;
eth_phy_get_partner_pause_enable_func emac_phy_get_partner_pause_enable;
eth_phy_power_enable_func emac_phy_power_enable;
uint32_t reset_timeout_ms;
bool promiscuous_enable;
};
enum emac_post_type {
EMAC_POST_ASYNC,
EMAC_POST_SYNC,
};
struct emac_post_cmd {
void *cmd;
enum emac_post_type post_type;
};
struct emac_tx_cmd {
uint8_t *buf;
uint16_t size;
int8_t err;
};
struct emac_open_cmd {
int8_t err;
};
struct emac_close_cmd {
int8_t err;
};
#define DMA_RX_BUF_NUM CONFIG_ETH_DMA_RX_BUF_NUM
#define DMA_TX_BUF_NUM CONFIG_ETH_DMA_TX_BUF_NUM
#define EMAC_TASK_PRIORITY CONFIG_ETH_EMAC_TASK_PRIORITY
#define EMAC_TASK_STACK_SIZE CONFIG_ETH_EMAC_TASK_STACK_SIZE
#define DMA_RX_BUF_SIZE 1600
#define DMA_TX_BUF_SIZE 1600
#define FLOW_CONTROL_HIGH_WATERMARK 3
#define FLOW_CONTROL_LOW_WATERMARK 6
#define PHY_LINK_CHECK_NUM 5
#define EMAC_CMD_OK 0
#define EMAC_CMD_FAIL -1
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,204 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _EMAC_DESC_H_
#define _EMAC_DESC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc.h"
#define REG_EMAC_DESC_BASE 0
#define EMAC_DESC_TDES0_REG (REG_EMAC_DESC_BASE + 0x0000)
#define EMAC_DESC_TX_OWN (BIT(31))
#define EMAC_DESC_TX_OWN_S 31
#define EMAC_DESC_INT_COMPL (BIT(30))
#define EMAC_DESC_INT_COMPL_S 30
#define EMAC_DESC_LAST_SEGMENT (BIT(29))
#define EMAC_DESC_LAST_SEGMENT_S 29
#define EMAC_DESC_FIRST_SEGMENT (BIT(28))
#define EMAC_DESC_FIRST_SEGMENT_S 28
#define EMAC_DESC_DIS_CRC (BIT(27))
#define EMAC_DESC_DIS_CRC_S 27
#define EMAC_DESC_DIS_PAD (BIT(26))
#define EMAC_DESC_DIS_PAD_S 26
#define EMAC_DESC_TX_TS_EN (BIT(25))
#define EMAC_DESC_TX_TS_EN_S 25
#define EMAC_DESC_CRC_REPLACE_CTRL (BIT(24))
#define EMAC_DESC_CRC_REPLACE_CTRL_S 24
#define EMAC_DESC_CHECKSUM_INSERT_CTRL 0x00000003
#define EMAC_DESC_CHECKSUM_INSERT_CTRL_S 22
#define EMAC_DESC_TX_END_OF_RING (BIT(21))
#define EMAC_DESC_TX_END_OF_RING_S 21
#define EMAC_DESC_SECOND_ADDR_CHAIN (BIT(20))
#define EMAC_DESC_SECOND_ADDR_CHAIN_S 20
#define EMAC_DESC_VLAN_INSERT_CTRL 0x00000003
#define EMAC_DESC_VLAN_INSERT_CTRL_S 18
#define EMAC_DESC_TX_TS_STATUS (BIT(17))
#define EMAC_DESC_TX_TS_STATUS_S 17
#define EMAC_DESC_TX_IP_HEAD_ERR (BIT(16))
#define EMAC_DESC_TX_IP_HEAD_ERR_S 16
#define EMAC_DESC_ERR_SUMMARY (BIT(15))
#define EMAC_DESC_ERR_SUMMARY_S 15
#define EMAC_DESC_JABBER_TO (BIT(14))
#define EMAC_DESC_JABBER_TO_S 14
#define EMAC_DESC_FRAME_FLUSH (BIT(13))
#define EMAC_DESC_FRAME_FLUSH_S 13
#define EMAC_DESC_TX_IP_PAYLAD_ERR (BIT(12))
#define EMAC_DESC_TX_IP_PAYLAD_ERR_S 12
#define EMAC_DESC_LOSS_OF_CARRIER (BIT(11))
#define EMAC_DESC_LOSS_OF_CARRIER_S 11
#define EMAC_DESC_NO_CARRIER (BIT(10))
#define EMAC_DESC_NO_CARRIER_S 10
#define EMAC_DESC_LATE_COLLISION_T (BIT(9))
#define EMAC_DESC_LATE_COLLISION_T_S 9
#define EMAC_DESC_EXCESSIVE_COLLISION (BIT(8))
#define EMAC_DESC_EXCESSIVE_COLLISION_S 8
#define EMAC_DESC_VLAN_FRAME (BIT(7))
#define EMAC_DESC_VLAN_FRAME_S 7
#define EMAC_DESC_COLLISION_COUNT 0x0000000F
#define EMAC_DESC_COLLISION_COUNT_S 3
#define EMAC_DESC_EXCESSIVE_DEFERRAL (BIT(2))
#define EMAC_DESC_EXCESSIVE_DEFERRAL_S 2
#define EMAC_DESC_UNDERFLOW_ERR (BIT(1))
#define EMAC_DESC_UNDERFLOW_ERR_S 1
#define EMAC_DESC_DEFFER_BIT (BIT(0))
#define EMAC_DESC_DEFFER_BIT_S 0
#define EMAC_DESC_TDES1_REG (REG_EMAC_DESC_BASE + 0x0004)
#define EMAC_DESC_SA_INSERT_CRTL 0x00000007
#define EMAC_DESC_SA_INSERT_CRTL_S 29
#define EMAC_DESC_TX_BUFFER1_SIZE 0x00001FFF
#define EMAC_DESC_TX_BUFFER1_SIZE_S 0
#define EMAC_DESC_TDES2_REG (REG_EMAC_DESC_BASE + 0x0008)
#define EMAC_DESC_TX_BUFFER1_ADDR_PTR 0xFFFFFFFF
#define EMAC_DESC_TX_BUFFER1_ADDR_PTR_S 0
#define EMAC_DESC_TDES3_REG (REG_EMAC_DESC_BASE + 0x000C)
#define EMAC_DESC_TX_NEXT_DESC_ADDR 0xFFFFFFFF
#define EMAC_DESC_TX_NEXT_DESC_ADDR_S 0
#define EMAC_DESC_TDES4_REG (REG_EMAC_DESC_BASE + 0x0010)
#define EMAC_DESC_TDES5_REG (REG_EMAC_DESC_BASE + 0x0014)
#define EMAC_DESC_TDES6_REG (REG_EMAC_DESC_BASE + 0x0018)
#define EMAC_DESC_TX_FRAME_TS_LOW 0xFFFFFFFF
#define EMAC_DESC_TX_FRAME_TS_LOW_S 0
#define EMAC_DESC_TDES7_REG (REG_EMAC_DESC_BASE + 0x001C)
#define EMAC_DESC_TX_FRAME_TS_HIGH 0xFFFFFFFF
#define EMAC_DESC_TX_FRAME_TS_HIGH_S 0
#define EMAC_DESC_RDES0_REG (REG_EMAC_DESC_BASE + 0x0000)
#define EMAC_DESC_RX_OWN (BIT(31))
#define EMAC_DESC_RX_OWN_S 31
#define EMAC_DESC_DEST_ADDR_FILTER_FAIL (BIT(30))
#define EMAC_DESC_DEST_ADDR_FILTER_FAIL_S 30
#define EMAC_DESC_FRAME_LENGTH 0x00003FFF
#define EMAC_DESC_FRAME_LENGTH_S 16
#define EMAC_DESC_ERROR_SUMMARY (BIT(15))
#define EMAC_DESC_ERROR_SUMMARY_S 15
#define EMAC_DESC_DESC_ERR (BIT(14))
#define EMAC_DESC_DESC_ERR_S 14
#define EMAC_DESC_SOURCE_ADDR_FILTER_FAIL (BIT(13))
#define EMAC_DESC_SOURCE_ADDR_FILTER_FAIL_S 13
#define EMAC_DESC_LENGTH_ERR (BIT(12))
#define EMAC_DESC_LENGTH_ERR_S 12
#define EMAC_DESC_OVERFLOW_ERR (BIT(11))
#define EMAC_DESC_OVERFLOW_ERR_S 11
#define EMAC_DESC_VLAN_TAG (BIT(10))
#define EMAC_DESC_VLAN_TAG_S 10
#define EMAC_DESC_FRIST_DESC (BIT(9))
#define EMAC_DESC_FRIST_DESC_S 9
#define EMAC_DESC_LAST_DESC (BIT(8))
#define EMAC_DESC_LAST_DESC_S 8
#define EMAC_DESC_TS_AV_IP_CHK_ERR (BIT(7))
#define EMAC_DESC_TS_AV_IP_CHK_ERR_S 7
#define EMAC_DESC_LATE_COLLISION (BIT(6))
#define EMAC_DESC_LATE_COLLISION_S 6
#define EMAC_DESC_FRAME_TYPE (BIT(5))
#define EMAC_DESC_FRAME_TYPE_S 5
#define EMAC_DESC_RX_WDT_TO (BIT(4))
#define EMAC_DESC_RX_WDT_TO_S 4
#define EMAC_DESC_RX_ERR (BIT(3))
#define EMAC_DESC_RX_ERR_S 3
#define EMAC_DESC_DRIBBLE_BIT_ERR (BIT(2))
#define EMAC_DESC_DRIBBLE_BIT_ERR_S 2
#define EMAC_DESC_CRC_ERR (BIT(1))
#define EMAC_DESC_CRC_ERR_S 1
#define EMAC_DESC_EXT_STATUS_AVAIL (BIT(0))
#define EMAC_DESC_EXT_STATUS_AVAIL_S 0
#define EMAC_DESC_RDES1_REG (REG_EMAC_DESC_BASE + 0x0004)
#define EMAC_DESC_DIS_INT_ON_COMPLET (BIT(31))
#define EMAC_DESC_DIS_INT_ON_COMPLET_S 31
#define EMAC_DESC_RX_END_OF_RING (BIT(15))
#define EMAC_DESC_RX_END_OF_RING_S 15
#define EMAC_DESC_RX_SECOND_ADDR_CHAIN (BIT(14))
#define EMAC_DESC_RX_SECOND_ADDR_CHAIN_S 14
#define EMAC_DESC_RX_BUFFER1_SIZE 0x00001FFF
#define EMAC_DESC_RX_BUFFER1_SIZE_S 0
#define EMAC_DESC_RDES2_REG (REG_EMAC_DESC_BASE + 0x0008)
#define EMAC_DESC_RX_BUFFER1_ADDR_PTR 0xFFFFFFFF
#define EMAC_DESC_RX_BUFFER1_ADDR_PTR_S 0
#define EMAC_DESC_RDES3_REG (REG_EMAC_DESC_BASE + 0x000c)
#define EMAC_DESC_RX_NEXT_DESC_ADDR 0xFFFFFFFF
#define EMAC_DESC_RX_NEXT_DESC_ADDR_S 0
#define EMAC_DESC_RDES4_REG (REG_EMAC_DESC_BASE + 0x0010)
#define EMAC_DESC_VLAN_TAG_PRIOR_VALUE 0x00000007
#define EMAC_DESC_VLAN_TAG_PRIOR_VALUE_S 18
#define EMAC_DESC_TS_DROP (BIT(14))
#define EMAC_DESC_TS_DROP_S 14
#define EMAC_DESC_PTP_VERSION (BIT(13))
#define EMAC_DESC_PTP_VERSION_S 13
#define EMAC_DESC_PTP_FRAME_TYPE (BIT(12))
#define EMAC_DESC_PTP_FRAME_TYPE_S 12
#define EMAC_DESC_MESSAGE_TYPE 0x0000000F
#define EMAC_DESC_MESSAGE_TYPE_S 8
#define EMAC_DESC_IPV6_PACK_RECEIVE (BIT(7))
#define EMAC_DESC_IPV6_PACK_RECEIVE_S 7
#define EMAC_DESC_IPV4_PACK_RECEIVE (BIT(6))
#define EMAC_DESC_IPV4_PACK_RECEIVE_S 6
#define EMAC_DESC_IP_CHECKSUM_BYPASS (BIT(5))
#define EMAC_DESC_IP_CHECKSUM_BYPASS_S 5
#define EMAC_DESC_RX_IP_PAYLAD_ERR (BIT(4))
#define EMAC_DESC_RX_IP_PAYLAD_ERR_S 4
#define EMAC_DESC_RX_IP_HEAD_ERR (BIT(3))
#define EMAC_DESC_RX_IP_HEAD_ERR_S 3
#define EMAC_DESC_IP_PAYLOAD_TYPE 0x00000007
#define EMAC_DESC_IP_PAYLOAD_TYPE_S 0
#define EMAC_DESC_RDES5_REG (REG_EMAC_DESC_BASE + 0x0014)
#define EMAC_DESC_RDES6_REG (REG_EMAC_DESC_BASE + 0x0018)
#define EMAC_DESC_RX_FRAME_TS_LOW 0xFFFFFFFF
#define EMAC_DESC_RX_FRAME_TS_LOW_S 0
#define EMAC_DESC_RDES7_REG (REG_EMAC_DESC_BASE + 0x001C)
#define EMAC_DESC_RX_FRAME_TS_HIGH 0xFFFFFFFF
#define EMAC_DESC_RX_FRAME_TS_HIGH_S 0
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,107 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/gpio.h"
#include "soc/dport_reg.h"
#include "soc/rtc_periph.h"
#include "soc/gpio_periph.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "emac_common.h"
void emac_enable_flowctrl(void)
{
REG_SET_BIT(EMAC_GMACFC_REG, EMAC_TFCE);
REG_SET_BIT(EMAC_GMACFC_REG, EMAC_RFCE);
REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_DZPQ);
REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PAUSE_TIME, 0x1648);
REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PLT, 0x1);
}
void emac_disable_flowctrl(void)
{
REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_TFCE);
REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_RFCE);
REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_DZPQ);
REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PAUSE_TIME, 0);
REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PLT, 0);
}
void emac_enable_dma_tx(void)
{
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND);
}
void emac_enable_dma_rx(void)
{
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_RX);
}
void emac_disable_dma_tx(void)
{
REG_CLR_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND);
}
void emac_disable_dma_rx(void)
{
REG_CLR_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_RX);
}
void emac_enable_clk(bool enable)
{
if (enable == true) {
DPORT_REG_SET_BIT(EMAC_CLK_EN_REG, EMAC_CLK_EN);
} else {
DPORT_REG_CLR_BIT(EMAC_CLK_EN_REG, EMAC_CLK_EN);
}
}
void emac_dma_init(void)
{
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FWD_UNDER_GF);
REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPT_SECOND_FRAME);
REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4);
}
void emac_mac_enable_txrx(void)
{
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACRX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACTX);
}
void emac_mac_init(void)
{
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACDUPLEX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACMII);
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED);
REG_SET_BIT(EMAC_GMACFF_REG, EMAC_PAM);
}
void emac_enable_promiscuous(void)
{
REG_SET_BIT(EMAC_GMACFF_REG, EMAC_PMODE);
}
void emac_disable_promiscuous(void)
{
REG_CLR_BIT(EMAC_GMACFF_REG, EMAC_PMODE);
}

View file

@ -1,115 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _EMAC_DEV_H_
#define _EMAC_DEV_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_types.h"
#include "soc/emac_periph.h"
#define EMAC_INTR_ENABLE_BIT (EMAC_DMAIN_TIE | EMAC_DMAIN_RIE | EMAC_DMAIN_RBUE | EMAC_DMAIN_NISE)
struct dma_desc {
uint32_t desc0;
uint32_t desc1;
uint32_t desc2;
uint32_t desc3;
};
typedef struct dma_extended_desc {
struct dma_desc basic;
uint32_t desc4;
uint32_t desc5;
uint32_t desc6;
uint32_t desc7;
} dma_extended_desc_t;
void emac_enable_clk(bool enable);
esp_err_t emac_reset(void);
void emac_set_gpio_pin_rmii(void);
void emac_set_gpio_pin_mii(void);
uint32_t emac_read_mac_version(void);
void emac_dma_init(void);
void emac_mac_init(void);
void emac_enable_dma_tx(void);
void emac_enable_dma_rx(void);
void emac_disable_dma_tx(void);
void emac_disable_dma_rx(void);
void emac_enable_flowctrl(void);
void emac_disable_flowctrl(void);
void emac_mac_enable_txrx(void);
void emac_enable_promiscuous(void);
void emac_disable_promiscuous(void);
static inline uint32_t emac_read_tx_cur_reg(void)
{
return REG_READ(EMAC_DMATXCURRDESC_REG);
}
static inline uint32_t emac_read_rx_cur_reg(void)
{
return REG_READ(EMAC_DMARXCURRDESC_REG);
}
static inline void emac_poll_tx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1);
}
static inline void emac_poll_rx_cmd(void)
{
//write any to wake up dma
REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1);
}
static inline void emac_disable_rx_intr(void)
{
REG_CLR_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RIE);
}
static inline void emac_enable_rx_intr(void)
{
REG_SET_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RIE);
}
static inline void emac_disable_rx_unavail_intr(void)
{
REG_CLR_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RBUE);
}
static inline void emac_enable_rx_unavail_intr(void)
{
REG_SET_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RBUE);
}
static inline void IRAM_ATTR emac_send_pause_frame_enable(void)
{
REG_SET_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL);
}
static inline void emac_send_pause_zero_frame_enable(void)
{
REG_CLR_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL);
}
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,80 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "eth_phy/phy.h"
#include "eth_phy/phy_reg.h"
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "phy_common";
void phy_rmii_configure_data_interface_pins(void)
{
// CRS_DRV to GPIO27
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
// TXD0 to GPIO19
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
// TX_EN to GPIO21
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
// TXD1 to GPIO22
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
// RXD0 to GPIO25
gpio_set_direction(25, GPIO_MODE_INPUT);
// RXD1 to GPIO26
gpio_set_direction(26, GPIO_MODE_INPUT);
// RMII CLK to GPIO0
gpio_set_direction(0, GPIO_MODE_INPUT);
}
void phy_rmii_smi_configure_pins(uint8_t mdc_gpio, uint8_t mdio_gpio)
{
// setup SMI MDC pin
gpio_set_direction(mdc_gpio, GPIO_MODE_OUTPUT);
gpio_matrix_out(mdc_gpio, EMAC_MDC_O_IDX, 0, 0);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdc_gpio], PIN_FUNC_GPIO);
// setup SMI MDIO pin
gpio_set_direction(mdio_gpio, GPIO_MODE_INPUT_OUTPUT);
gpio_matrix_out(mdio_gpio, EMAC_MDO_O_IDX, 0, 0);
gpio_matrix_in(mdio_gpio, EMAC_MDI_I_IDX, 0);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdio_gpio], PIN_FUNC_GPIO);
}
void phy_mii_enable_flow_ctrl(void)
{
uint32_t data = esp_eth_smi_read(MII_AUTO_NEG_ADVERTISEMENT_REG);
data |= MII_ASM_DIR | MII_PAUSE;
esp_eth_smi_write(MII_AUTO_NEG_ADVERTISEMENT_REG, data);
}
bool phy_mii_check_link_status(void)
{
if ((esp_eth_smi_read(MII_BASIC_MODE_STATUS_REG) & MII_LINK_STATUS)) {
ESP_LOGD(TAG, "phy_mii_check_link_status(UP)");
return true;
} else {
ESP_LOGD(TAG, "phy_mii_check_link_status(DOWN)");
return false;
}
}
bool phy_mii_get_partner_pause_enable(void)
{
if ((esp_eth_smi_read(MII_PHY_LINK_PARTNER_ABILITY_REG) & MII_PARTNER_PAUSE)) {
ESP_LOGD(TAG, "phy_mii_get_partner_pause_enable(TRUE)");
return true;
} else {
ESP_LOGD(TAG, "phy_mii_get_partner_pause_enable(FALSE)");
return false;
}
}

View file

@ -1,126 +0,0 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy/phy_reg.h"
#include "eth_phy/phy_ip101.h"
#define IP101_PHY_ID1 0x243
#define IP101_PHY_ID2 0xc54
#define IP101_PHY_ID2_MASK 0xFFF0
#define PHY_STATUS_REG (0x1e)
#define DUPLEX_STATUS BIT(2)
#define SPEED_STATUS BIT(1)
static const char *TAG = "ip101";
void phy_ip101_check_phy_init(void)
{
phy_ip101_dump_registers();
esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
}
eth_speed_mode_t phy_ip101_get_speed_mode(void)
{
if ((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS) == SPEED_STATUS) {
ESP_LOGD(TAG, "phy_ip101_get_speed_mode(100)");
return ETH_SPEED_MODE_100M;
} else {
ESP_LOGD(TAG, "phy_ip101_get_speed_mode(10)");
return ETH_SPEED_MODE_10M;
}
}
eth_duplex_mode_t phy_ip101_get_duplex_mode(void)
{
if ((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS) == DUPLEX_STATUS) {
ESP_LOGD(TAG, "phy_ip101_get_duplex_mode(FULL)");
return ETH_MODE_FULLDUPLEX;
} else {
ESP_LOGD(TAG, "phy_ip101_get_duplex_mode(HALF)");
return ETH_MODE_HALFDUPLEX;
}
}
void phy_ip101_power_enable(bool enable)
{
if (enable) {
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
// TODO: only do this if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
}
esp_err_t phy_ip101_init(void)
{
esp_err_t res1, res2;
ESP_LOGD(TAG, "phy_ip101_init()");
phy_ip101_dump_registers();
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET);
do {
// Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, IP101_PHY_ID1, UINT16_MAX, 1000);
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, IP101_PHY_ID2, IP101_PHY_ID2_MASK, 1000);
} while (res1 != ESP_OK || res2 != ESP_OK);
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
ets_delay_us(300);
// TODO: only do this if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
if (res1 == ESP_OK && res2 == ESP_OK) {
return ESP_OK;
} else {
return ESP_ERR_TIMEOUT;
}
}
const eth_config_t phy_ip101_default_ethernet_config = {
.phy_addr = 0x1,
.mac_mode = ETH_MODE_RMII,
.clock_mode = ETH_CLOCK_GPIO0_OUT,
.flow_ctrl_enable = true,
.phy_init = phy_ip101_init,
.phy_check_init = phy_ip101_check_phy_init,
.phy_check_link = phy_mii_check_link_status,
.phy_get_speed_mode = phy_ip101_get_speed_mode,
.phy_get_duplex_mode = phy_ip101_get_duplex_mode,
.phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable,
.phy_power_enable = phy_ip101_power_enable,
.reset_timeout_ms = 1000,
.promiscuous_enable = false,
};
void phy_ip101_dump_registers()
{
ESP_LOGD(TAG, "IP101 Registers:");
ESP_LOGD(TAG, "BCR 0x%04x", esp_eth_smi_read(0x0));
ESP_LOGD(TAG, "BSR 0x%04x", esp_eth_smi_read(0x1));
ESP_LOGD(TAG, "PHY1 0x%04x", esp_eth_smi_read(0x2));
ESP_LOGD(TAG, "PHY2 0x%04x", esp_eth_smi_read(0x3));
ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4));
ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5));
ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6));
ESP_LOGD(TAG, "PSCR 0x%04x", esp_eth_smi_read(0x16));
ESP_LOGD(TAG, "ISR 0x%04x", esp_eth_smi_read(0x17));
ESP_LOGD(TAG, "ICR 0x%04x", esp_eth_smi_read(0x18));
ESP_LOGD(TAG, "CSSR 0x%04x", esp_eth_smi_read(0x30));
}

View file

@ -1,138 +0,0 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy/phy_reg.h"
#include "eth_phy/phy_lan8720.h"
#define LAN8720_PHY_ID1 0x0007
#define LAN8720_PHY_ID2 0xc0f0
#define LAN8720_PHY_ID2_MASK 0xFFF0
/* LAN8720-specific registers */
#define PHY_SPECIAL_CONTROL_STATUS_REG (0x1f)
#define AUTO_NEGOTIATION_DONE BIT(12)
#define DUPLEX_INDICATION_FULL BIT(4)
#define SPEED_INDICATION_100T BIT(3)
#define SPEED_INDICATION_10T BIT(2)
#define SPEED_DUPLEX_INDICATION_10T_HALF 0x04
#define SPEED_DUPLEX_INDICATION_10T_FULL 0x14
#define SPEED_DUPLEX_INDICATION_100T_HALF 0x08
#define SPEED_DUPLEX_INDICATION_100T_FULL 0x18
static const char *TAG = "lan8720";
void phy_lan8720_check_phy_init(void)
{
phy_lan8720_dump_registers();
esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
esp_eth_smi_wait_set(PHY_SPECIAL_CONTROL_STATUS_REG, AUTO_NEGOTIATION_DONE, 0);
}
eth_speed_mode_t phy_lan8720_get_speed_mode(void)
{
if (esp_eth_smi_read(PHY_SPECIAL_CONTROL_STATUS_REG) & SPEED_INDICATION_100T) {
ESP_LOGD(TAG, "phy_lan8720_get_speed_mode(100)");
return ETH_SPEED_MODE_100M;
} else {
ESP_LOGD(TAG, "phy_lan8720_get_speed_mode(10)");
return ETH_SPEED_MODE_10M;
}
}
eth_duplex_mode_t phy_lan8720_get_duplex_mode(void)
{
if (esp_eth_smi_read(PHY_SPECIAL_CONTROL_STATUS_REG) & DUPLEX_INDICATION_FULL) {
ESP_LOGD(TAG, "phy_lan8720_get_duplex_mode(FULL)");
return ETH_MODE_FULLDUPLEX;
} else {
ESP_LOGD(TAG, "phy_lan8720_get_duplex_mode(HALF)");
return ETH_MODE_HALFDUPLEX;
}
}
void phy_lan8720_power_enable(bool enable)
{
if (enable) {
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
// TODO: only enable if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
}
esp_err_t phy_lan8720_init(void)
{
ESP_LOGD(TAG, "phy_lan8720_init()");
phy_lan8720_dump_registers();
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET);
esp_err_t res1, res2;
// Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, LAN8720_PHY_ID1, UINT16_MAX, 1000);
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, LAN8720_PHY_ID2, LAN8720_PHY_ID2_MASK, 1000);
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
ets_delay_us(300);
// TODO: only enable if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
if (res1 == ESP_OK && res2 == ESP_OK) {
return ESP_OK;
} else {
return ESP_ERR_TIMEOUT;
}
}
const eth_config_t phy_lan8720_default_ethernet_config = {
.phy_addr = 0,
.mac_mode = ETH_MODE_RMII,
.clock_mode = ETH_CLOCK_GPIO0_IN,
.flow_ctrl_enable = true,
.phy_init = phy_lan8720_init,
.phy_check_init = phy_lan8720_check_phy_init,
.phy_power_enable = phy_lan8720_power_enable,
.phy_check_link = phy_mii_check_link_status,
.phy_get_speed_mode = phy_lan8720_get_speed_mode,
.phy_get_duplex_mode = phy_lan8720_get_duplex_mode,
.phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable,
.reset_timeout_ms = 1000,
.promiscuous_enable = false,
};
void phy_lan8720_dump_registers()
{
ESP_LOGD(TAG, "LAN8720 Registers:");
ESP_LOGD(TAG, "BCR 0x%04x", esp_eth_smi_read(0x0));
ESP_LOGD(TAG, "BSR 0x%04x", esp_eth_smi_read(0x1));
ESP_LOGD(TAG, "PHY1 0x%04x", esp_eth_smi_read(0x2));
ESP_LOGD(TAG, "PHY2 0x%04x", esp_eth_smi_read(0x3));
ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4));
ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5));
ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6));
ESP_LOGD(TAG, "MCSR 0x%04x", esp_eth_smi_read(0x17));
ESP_LOGD(TAG, "SM 0x%04x", esp_eth_smi_read(0x18));
ESP_LOGD(TAG, "SECR 0x%04x", esp_eth_smi_read(0x26));
ESP_LOGD(TAG, "CSIR 0x%04x", esp_eth_smi_read(0x27));
ESP_LOGD(TAG, "ISR 0x%04x", esp_eth_smi_read(0x29));
ESP_LOGD(TAG, "IMR 0x%04x", esp_eth_smi_read(0x30));
ESP_LOGD(TAG, "PSCSR 0x%04x", esp_eth_smi_read(0x31));
}

View file

@ -1,169 +0,0 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy/phy_reg.h"
#include "eth_phy/phy_tlk110.h"
#define TLK110_PHY_ID1 0x2000
#define TLK110_PHY_ID2 0xa210
#define TLK110_PHY_ID2_MASK 0xFFF0
/* TLK110-specific registers */
#define SW_STRAP_CONTROL_REG (0x9)
#define SW_STRAP_CONFIG_DONE BIT(15)
#define AUTO_MDIX_ENABLE BIT(14)
#define AUTO_NEGOTIATION_ENABLE BIT(13)
#define AN_1 BIT(12)
#define AN_0 BIT(11)
#define LED_CFG BIT(10)
#define RMII_ENHANCED_MODE BIT(9)
#define DEFAULT_STRAP_CONFIG (AUTO_MDIX_ENABLE | AUTO_NEGOTIATION_ENABLE | AN_1 | AN_0 | LED_CFG)
#define PHY_STATUS_REG (0x10)
#define AUTO_NEGOTIATION_STATUS BIT(4)
#define DUPLEX_STATUS BIT(2)
#define SPEED_STATUS BIT(1)
#define CABLE_DIAGNOSTIC_CONTROL_REG (0x1e)
#define DIAGNOSTIC_DONE BIT(1)
#define PHY_RESET_CONTROL_REG (0x1f)
#define SOFTWARE_RESET BIT(15)
static const char *TAG = "tlk110";
void phy_tlk110_check_phy_init(void)
{
phy_tlk110_dump_registers();
esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
esp_eth_smi_wait_set(PHY_STATUS_REG, AUTO_NEGOTIATION_STATUS, 0);
esp_eth_smi_wait_set(CABLE_DIAGNOSTIC_CONTROL_REG, DIAGNOSTIC_DONE, 0);
}
eth_speed_mode_t phy_tlk110_get_speed_mode(void)
{
if ((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS) != SPEED_STATUS) {
ESP_LOGD(TAG, "phy_tlk110_get_speed_mode(100)");
return ETH_SPEED_MODE_100M;
} else {
ESP_LOGD(TAG, "phy_tlk110_get_speed_mode(10)");
return ETH_SPEED_MODE_10M;
}
}
eth_duplex_mode_t phy_tlk110_get_duplex_mode(void)
{
if ((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS) == DUPLEX_STATUS) {
ESP_LOGD(TAG, "phy_tlk110_get_duplex_mode(FULL)");
return ETH_MODE_FULLDUPLEX;
} else {
ESP_LOGD(TAG, "phy_tlk110_get_duplex_mode(HALF)");
return ETH_MODE_HALFDUPLEX;
}
}
void phy_tlk110_power_enable(bool enable)
{
if (enable) {
esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
// TODO: only do this if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
}
esp_err_t phy_tlk110_init(void)
{
ESP_LOGD(TAG, "phy_tlk110_init()");
phy_tlk110_dump_registers();
esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET);
esp_err_t res1, res2;
// Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, TLK110_PHY_ID1, UINT16_MAX, 1000);
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, TLK110_PHY_ID2, TLK110_PHY_ID2_MASK, 1000);
esp_eth_smi_write(SW_STRAP_CONTROL_REG,
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
ets_delay_us(300);
// TODO: only do this if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
if (res1 == ESP_OK && res2 == ESP_OK) {
return ESP_OK;
} else {
return ESP_ERR_TIMEOUT;
}
}
const eth_config_t phy_tlk110_default_ethernet_config = {
.phy_addr = 0x1,
.mac_mode = ETH_MODE_RMII,
.clock_mode = ETH_CLOCK_GPIO0_IN,
.flow_ctrl_enable = true,
.phy_init = phy_tlk110_init,
.phy_check_init = phy_tlk110_check_phy_init,
.phy_check_link = phy_mii_check_link_status,
.phy_get_speed_mode = phy_tlk110_get_speed_mode,
.phy_get_duplex_mode = phy_tlk110_get_duplex_mode,
.phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable,
.phy_power_enable = phy_tlk110_power_enable,
.reset_timeout_ms = 1000,
.promiscuous_enable = false,
};
void phy_tlk110_dump_registers()
{
ESP_LOGD(TAG, "TLK110 Registers:");
ESP_LOGD(TAG, "BMCR 0x%04x", esp_eth_smi_read(0x0));
ESP_LOGD(TAG, "BMSR 0x%04x", esp_eth_smi_read(0x1));
ESP_LOGD(TAG, "PHYIDR1 0x%04x", esp_eth_smi_read(0x2));
ESP_LOGD(TAG, "PHYIDR2 0x%04x", esp_eth_smi_read(0x3));
ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4));
ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5));
ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6));
ESP_LOGD(TAG, "ANNPTR 0x%04x", esp_eth_smi_read(0x7));
ESP_LOGD(TAG, "ANLNPTR 0x%04x", esp_eth_smi_read(0x8));
ESP_LOGD(TAG, "SWSCR1 0x%04x", esp_eth_smi_read(0x9));
ESP_LOGD(TAG, "SWSCR2 0x%04x", esp_eth_smi_read(0xa));
ESP_LOGD(TAG, "SWSCR3 0x%04x", esp_eth_smi_read(0xb));
ESP_LOGD(TAG, "REGCR 0x%04x", esp_eth_smi_read(0xd));
ESP_LOGD(TAG, "ADDAR 0x%04x", esp_eth_smi_read(0xe));
ESP_LOGD(TAG, "PHYSTS 0x%04x", esp_eth_smi_read(0x10));
ESP_LOGD(TAG, "PHYSCR 0x%04x", esp_eth_smi_read(0x11));
ESP_LOGD(TAG, "MISR1 0x%04x", esp_eth_smi_read(0x12));
ESP_LOGD(TAG, "MISR2 0x%04x", esp_eth_smi_read(0x13));
ESP_LOGD(TAG, "FCSCR 0x%04x", esp_eth_smi_read(0x14));
ESP_LOGD(TAG, "RECR 0x%04x", esp_eth_smi_read(0x15));
ESP_LOGD(TAG, "BISCR 0x%04x", esp_eth_smi_read(0x16));
ESP_LOGD(TAG, "RBR 0x%04x", esp_eth_smi_read(0x17));
ESP_LOGD(TAG, "LEDCR 0x%04x", esp_eth_smi_read(0x18));
ESP_LOGD(TAG, "PHYCR 0x%04x", esp_eth_smi_read(0x19));
ESP_LOGD(TAG, "10BTSCR 0x%04x", esp_eth_smi_read(0x1a));
ESP_LOGD(TAG, "BICSR1 0x%04x", esp_eth_smi_read(0x1b));
ESP_LOGD(TAG, "BICSR2 0x%04x", esp_eth_smi_read(0x1c));
ESP_LOGD(TAG, "CDCR 0x%04x", esp_eth_smi_read(0x1e));
ESP_LOGD(TAG, "TRXCPSR 0x%04x", esp_eth_smi_read(0x42));
ESP_LOGD(TAG, "PWRBOCR 0x%04x", esp_eth_smi_read(0xae));
ESP_LOGD(TAG, "VRCR 0x%04x", esp_eth_smi_read(0xD0));
ESP_LOGD(TAG, "ALCDRR1 0x%04x", esp_eth_smi_read(0x155));
ESP_LOGD(TAG, "CDSCR1 0x%04x", esp_eth_smi_read(0x170));
ESP_LOGD(TAG, "CDSCR2 0x%04x", esp_eth_smi_read(0x171));
}

View file

@ -1,322 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_ETH_H__
#define __ESP_ETH_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include "esp_event_base.h"
#include "esp_types.h"
#include "esp_err.h"
/**
* @brief Ethernet interface mode
*
*/
typedef enum {
ETH_MODE_RMII = 0, /*!< RMII mode */
ETH_MODE_MII, /*!< MII mode */
} eth_mode_t;
/**
* @brief Ethernet clock mode
*
*/
typedef enum {
ETH_CLOCK_GPIO0_IN = 0, /*!< RMII clock input to GPIO0 */
ETH_CLOCK_GPIO0_OUT = 1, /*!< RMII clock output from GPIO0 */
ETH_CLOCK_GPIO16_OUT = 2, /*!< RMII clock output from GPIO16 */
ETH_CLOCK_GPIO17_OUT = 3 /*!< RMII clock output from GPIO17 */
} eth_clock_mode_t;
/**
* @brief Ethernet Speed
*
*/
typedef enum {
ETH_SPEED_MODE_10M = 0, /*!< Ethernet speed: 10Mbps */
ETH_SPEED_MODE_100M, /*!< Ethernet speed: 100Mbps */
} eth_speed_mode_t;
/**
* @brief Ethernet Duplex
*
*/
typedef enum {
ETH_MODE_HALFDUPLEX = 0, /*!< Ethernet half duplex */
ETH_MODE_FULLDUPLEX, /*!< Ethernet full duplex */
} eth_duplex_mode_t;
/**
* @brief Ethernet PHY address
*
*/
typedef enum {
PHY0 = 0, /*!< PHY address 0 */
PHY1, /*!< PHY address 1 */
PHY2, /*!< PHY address 2 */
PHY3, /*!< PHY address 3 */
PHY4, /*!< PHY address 4 */
PHY5, /*!< PHY address 5 */
PHY6, /*!< PHY address 6 */
PHY7, /*!< PHY address 7 */
PHY8, /*!< PHY address 8 */
PHY9, /*!< PHY address 9 */
PHY10, /*!< PHY address 10 */
PHY11, /*!< PHY address 11 */
PHY12, /*!< PHY address 12 */
PHY13, /*!< PHY address 13 */
PHY14, /*!< PHY address 14 */
PHY15, /*!< PHY address 15 */
PHY16, /*!< PHY address 16 */
PHY17, /*!< PHY address 17 */
PHY18, /*!< PHY address 18 */
PHY19, /*!< PHY address 19 */
PHY20, /*!< PHY address 20 */
PHY21, /*!< PHY address 21 */
PHY22, /*!< PHY address 22 */
PHY23, /*!< PHY address 23 */
PHY24, /*!< PHY address 24 */
PHY25, /*!< PHY address 25 */
PHY26, /*!< PHY address 26 */
PHY27, /*!< PHY address 27 */
PHY28, /*!< PHY address 28 */
PHY29, /*!< PHY address 29 */
PHY30, /*!< PHY address 30 */
PHY31 /*!< PHY address 31 */
} eth_phy_base_t;
typedef bool (*eth_phy_check_link_func)(void);
typedef void (*eth_phy_check_init_func)(void);
typedef eth_speed_mode_t (*eth_phy_get_speed_mode_func)(void);
typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void);
typedef esp_err_t (*eth_phy_func)(void);
typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb);
typedef void (*eth_gpio_config_func)(void);
typedef bool (*eth_phy_get_partner_pause_enable_func)(void);
typedef void (*eth_phy_power_enable_func)(bool enable);
/**
* @brief ethernet configuration
*
*/
typedef struct {
eth_phy_base_t phy_addr; /*!< PHY address (0~31) */
eth_mode_t mac_mode; /*!< MAC mode: only support RMII now */
eth_clock_mode_t clock_mode; /*!< external/internal clock mode selection */
eth_tcpip_input_func tcpip_input; /*!< tcpip input func */
eth_phy_func phy_init; /*!< phy init func */
eth_phy_check_link_func phy_check_link; /*!< phy check link func */
eth_phy_check_init_func phy_check_init; /*!< phy check init func */
eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */
eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */
eth_gpio_config_func gpio_config; /*!< gpio config func */
bool flow_ctrl_enable; /*!< flag of flow ctrl enable */
eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */
eth_phy_power_enable_func phy_power_enable; /*!< enable or disable phy power */
uint32_t reset_timeout_ms; /*!< timeout value for reset emac */
bool promiscuous_enable; /*!< set true to enable promiscuous mode */
} eth_config_t;
/** Ethernet event declarations */
typedef enum {
ETHERNET_EVENT_START, /**< ESP32 ethernet start */
ETHERNET_EVENT_STOP, /**< ESP32 ethernet stop */
ETHERNET_EVENT_CONNECTED, /**< ESP32 ethernet phy link up */
ETHERNET_EVENT_DISCONNECTED, /**< ESP32 ethernet phy link down */
} eth_event_t;
/** @brief Ethernet event base declaration */
ESP_EVENT_DECLARE_BASE(ETH_EVENT);
/**
* @brief Init ethernet mac
*
* @note config can not be NULL, and phy chip must be suitable to phy init func.
*
* @param[in] config mac init data.
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_eth_init(eth_config_t *config);
/**
* @brief Deinit ethernet mac
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_ERR_INVALID_STATE
*/
esp_err_t esp_eth_deinit(void);
/**
* @brief Init Ethernet mac driver only
*
* For the most part, you need not call this function directly. It gets called
* from esp_eth_init().
*
* This function may be called, if you only need to initialize the Ethernet
* driver without having to use the network stack on top.
*
* @note config can not be NULL, and phy chip must be suitable to phy init func.
* @param[in] config mac init data.
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_eth_init_internal(eth_config_t *config);
/**
* @brief Send packet from tcp/ip to mac
*
* @note buf can not be NULL, size must be less than 1580
*
* @param[in] buf: start address of packet data.
*
* @param[in] size: size (byte) of packet data.
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size);
/**
* @brief Enable ethernet interface
*
* @note Should be called after esp_eth_init
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_eth_enable(void);
/**
* @brief Disable ethernet interface
*
* @note Should be called after esp_eth_init
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_eth_disable(void);
/**
* @brief Get mac addr
*
* @note mac addr must be a valid unicast address
*
* @param[out] mac: start address of mac address.
*/
void esp_eth_get_mac(uint8_t mac[6]);
/**
* @brief Write PHY reg with SMI interface.
*
* @note PHY base addr must be right.
*
* @param[in] reg_num: PHY reg num.
*
* @param[in] value: value which is written to PHY reg.
*/
void esp_eth_smi_write(uint32_t reg_num, uint16_t value);
/**
* @brief Read PHY reg with SMI interface.
*
* @note PHY base addr must be right.
*
* @param[in] reg_num: PHY reg num.
*
* @return value that is read from PHY reg
*/
uint16_t esp_eth_smi_read(uint32_t reg_num);
/**
* @brief Continuously read a PHY register over SMI interface, wait until the register has the desired value.
*
* @note PHY base address must be right.
*
* @param reg_num: PHY register number
* @param value: Value to wait for (masked with value_mask)
* @param value_mask: Mask of bits to match in the register.
* @param timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout.
*
* @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
*/
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms);
/**
* @brief Continuously read a PHY register over SMI interface, wait until the register has all bits in a mask set.
*
* @note PHY base address must be right.
*
* @param reg_num: PHY register number
* @param value_mask: Value mask to wait for (all bits in this mask must be set)
* @param timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout.
*
* @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
*/
static inline esp_err_t esp_eth_smi_wait_set(uint32_t reg_num, uint16_t value_mask, int timeout_ms)
{
return esp_eth_smi_wait_value(reg_num, value_mask, value_mask, timeout_ms);
}
/**
* @brief Free emac rx buf.
*
* @note buf can not be null, and it is tcpip input buf.
*
* @param[in] buf: start address of received packet data.
*
*/
void esp_eth_free_rx_buf(void *buf);
/**
* @brief Set mac of ethernet interface.
*
* @note user can call this function after emac_init, and the new mac address will be enabled after emac_enable.
*
* @param[in] mac: the Mac address.
*
* @return
* - ESP_OK: succeed
* - ESP_ERR_INVALID_MAC: invalid mac address
*/
esp_err_t esp_eth_set_mac(const uint8_t mac[6]);
/**
* @brief Get Ethernet link speed
*
* @return eth_speed_mode_t ETH_SPEED_MODE_10M when link speed is 10Mbps
* ETH_SPEED_MODE_100M when link speed is 100Mbps
*/
eth_speed_mode_t esp_eth_get_speed(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,76 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_eth.h"
/**
* @brief Common PHY-management functions.
*
* @note These are not enough to drive any particular Ethernet PHY.
* They provide a common configuration structure and management functions.
*
*/
/**
* @brief Configure fixed pins for RMII data interface.
*
* @note This configures GPIOs 0, 19, 22, 25, 26, 27 for use with RMII data interface.
* These pins cannot be changed, and must be wired to ethernet functions.
* This is not sufficient to fully configure the Ethernet PHY.
* MDIO configuration interface pins (such as SMI MDC, MDO, MDI) must also be configured correctly in the GPIO matrix.
*
*/
void phy_rmii_configure_data_interface_pins(void);
/**
* @brief Configure variable pins for SMI ethernet functions.
*
* @param mdc_gpio MDC GPIO Pin number
* @param mdio_gpio MDIO GPIO Pin number
*
* @note Calling this function along with mii_configure_default_pins() will fully configure the GPIOs for the ethernet PHY.
*/
void phy_rmii_smi_configure_pins(uint8_t mdc_gpio, uint8_t mdio_gpio);
/**
* @brief Enable flow control in standard PHY MII register.
*
*/
void phy_mii_enable_flow_ctrl(void);
/**
* @brief Check Ethernet link status via MII interface
*
* @return true Link is on
* @return false Link is off
*/
bool phy_mii_check_link_status(void);
/**
* @brief Check pause frame ability of partner via MII interface
*
* @return true Partner is able to process pause frame
* @return false Partner can not process pause frame
*/
bool phy_mii_get_partner_pause_enable(void);
#ifdef __cplusplus
}
#endif

View file

@ -1,75 +0,0 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "phy.h"
/**
* @brief Dump IP101 PHY SMI configuration registers
*
*/
void phy_ip101_dump_registers();
/**
* @brief Default IP101 phy_check_init function
*
*/
void phy_ip101_check_phy_init(void);
/**
* @brief Default IP101 phy_get_speed_mode function
*
* @return eth_speed_mode_t Ethernet speed mode
*/
eth_speed_mode_t phy_ip101_get_speed_mode(void);
/**
* @brief Default IP101 phy_get_duplex_mode function
*
* @return eth_duplex_mode_t Ethernet duplex mode
*/
eth_duplex_mode_t phy_ip101_get_duplex_mode(void);
/**
* @brief Default IP101 phy_power_enable function
*
*/
void phy_ip101_power_enable(bool);
/**
* @brief Default IP101 phy_init function
*
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t phy_ip101_init(void);
/**
* @brief Default IP101 PHY configuration
*
* @note This configuration is not suitable for use as-is,
* it will need to be modified for your particular PHY hardware setup.
*
*/
extern const eth_config_t phy_ip101_default_ethernet_config;
#ifdef __cplusplus
}
#endif

View file

@ -1,75 +0,0 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "phy.h"
/**
* @brief Dump LAN8720 PHY SMI configuration registers
*
*/
void phy_lan8720_dump_registers();
/**
* @brief Default LAN8720 phy_check_init function
*
*/
void phy_lan8720_check_phy_init(void);
/**
* @brief Default LAN8720 phy_get_speed_mode function
*
* @return eth_speed_mode_t Ethernet speed mode
*/
eth_speed_mode_t phy_lan8720_get_speed_mode(void);
/**
* @brief Default LAN8720 phy_get_duplex_mode function
*
* @return eth_duplex_mode_t Ethernet duplex mode
*/
eth_duplex_mode_t phy_lan8720_get_duplex_mode(void);
/**
* @brief Default LAN8720 phy_power_enable function
*
*/
void phy_lan8720_power_enable(bool);
/**
* @brief Default LAN8720 phy_init function
*
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t phy_lan8720_init(void);
/**
* @brief Default LAN8720 PHY configuration
*
* @note This configuration is not suitable for use as-is,
* it will need to be modified for your particular PHY hardware setup.
*
*/
extern const eth_config_t phy_lan8720_default_ethernet_config;
#ifdef __cplusplus
}
#endif

View file

@ -1,56 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <esp_bit_defs.h>
/**
* @brief This header contains register/bit masks for the standard PHY MII registers that should be supported by all PHY models.
*
*/
#define MII_BASIC_MODE_CONTROL_REG (0x0)
#define MII_SOFTWARE_RESET BIT(15)
#define MII_SPEED_SELECT BIT(13)
#define MII_AUTO_NEGOTIATION_ENABLE BIT(12)
#define MII_POWER_DOWN BIT(11)
#define MII_RESTART_AUTO_NEGOTIATION BIT(9)
#define MII_DUPLEX_MODE BIT(8)
#define MII_BASIC_MODE_STATUS_REG (0x1)
#define MII_AUTO_NEGOTIATION_COMPLETE BIT(5)
#define MII_LINK_STATUS BIT(2)
#define MII_PHY_IDENTIFIER_1_REG (0x2)
#define MII_PHY_IDENTIFIER_2_REG (0x3)
#define MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG (0x4)
#define MII_ASM_DIR BIT(11)
#define MII_PAUSE BIT(10)
#define MII_PHY_LINK_PARTNER_ABILITY_REG (0x5)
#define MII_PARTNER_ASM_DIR BIT(11)
#define MII_PARTNER_PAUSE BIT(10)
/******************************legacy*******************************/
#define MII_AUTO_NEG_ADVERTISEMENT_REG MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG
#ifdef __cplusplus
}
#endif

View file

@ -1,75 +0,0 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "phy.h"
/**
* @brief Dump TLK110 PHY SMI configuration registers
*
*/
void phy_tlk110_dump_registers();
/**
* @brief Default TLK110 phy_check_init function
*
*/
void phy_tlk110_check_phy_init(void);
/**
* @brief Default TLK110 phy_get_speed_mode function
*
* @return eth_speed_mode_t Ethernet speed mode
*/
eth_speed_mode_t phy_tlk110_get_speed_mode(void);
/**
* @brief Default TLK110 phy_get_duplex_mode function
*
* @return eth_duplex_mode_t Ethernet duplex mode
*/
eth_duplex_mode_t phy_tlk110_get_duplex_mode(void);
/**
* @brief Default TLK110 phy_power_enable function
*
*/
void phy_tlk110_power_enable(bool);
/**
* @brief Default TLK110 phy_init function
*
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t phy_tlk110_init(void);
/**
* @brief Default TLK110 PHY configuration
*
* @note This configuration is not suitable for use as-is,
* it will need to be modified for your particular PHY hardware setup.
*
*/
extern const eth_config_t phy_tlk110_default_ethernet_config;
#ifdef __cplusplus
}
#endif

View file

@ -1,9 +0,0 @@
# sdkconfig replacement configurations for deprecated options formatted as
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
CONFIG_DMA_RX_BUF_NUM CONFIG_ETH_DMA_RX_BUF_NUM
CONFIG_DMA_TX_BUF_NUM CONFIG_ETH_DMA_TX_BUF_NUM
CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE
CONFIG_EMAC_CHECK_LINK_PERIOD_MS CONFIG_ETH_CHECK_LINK_STATUS_PERIOD_MS
CONFIG_EMAC_TASK_PRIORITY CONFIG_ETH_EMAC_TASK_PRIORITY
CONFIG_EMAC_TASK_STACK_SIZE CONFIG_ETH_EMAC_TASK_STACK_SIZE

View file

@ -1,3 +0,0 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES unity ethernet)

View file

@ -1,133 +0,0 @@
/**
* @brief This test has just run in the ESP32_Ethernet_V3 board, which featured
* in PoE submodule and TLK110 PHY. The 50MHz clock used by MAC and PHY is
* supplied by external oscillator through GPIO0.
*
* @file test_emac_deinit.c
* @author morris
* @date 2018-08-24
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_event_loop.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "unity.h"
#include "esp32/rom/gpio.h"
#include "tcpip_adapter.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "eth_phy/phy_tlk110.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
static const char *TAG = "eth_test_deinit";
#define PIN_PHY_POWER 17
#define PIN_SMI_MDC 23
#define PIN_SMI_MDIO 18
#define CONFIG_PHY_ADDRESS 31
#define CONFIG_PHY_CLOCK_MODE 0
static EventGroupHandle_t eth_event_group = NULL;
static const int GOTIP_BIT = BIT0;
static void phy_device_power_enable_via_gpio(bool enable)
{
if (!enable) {
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(PIN_PHY_POWER);
gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
if (enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
ESP_LOGI(TAG, "power on ethernet phy");
} else {
gpio_set_level(PIN_PHY_POWER, 0);
ESP_LOGI(TAG, "power off ethernet phy");
}
vTaskDelay(1); // Allow the power up/down to take effect, min 300us
if (enable) {
/* operates the default phy-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
static void eth_gpio_config_rmii(void)
{
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
static esp_err_t eth_event_handler(void *ctx, system_event_t *event)
{
tcpip_adapter_ip_info_t ip;
switch (event->event_id) {
case SYSTEM_EVENT_ETH_CONNECTED:
ESP_LOGI(TAG, "Ethernet Link Up");
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
break;
case SYSTEM_EVENT_ETH_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip));
ESP_LOGI(TAG, "Ethernet Got IP Addr");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip.ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip.netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip.gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
xEventGroupSetBits(eth_event_group, GOTIP_BIT);
break;
case SYSTEM_EVENT_ETH_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
return ESP_OK;
}
TEST_CASE("start event loop", "[ethernet][ignore]")
{
eth_event_group = xEventGroupCreate();
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(eth_event_handler, NULL));
}
TEST_CASE("test emac deinit", "[ethernet][ignore]")
{
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.clock_mode = CONFIG_PHY_CLOCK_MODE;
config.phy_power_enable = phy_device_power_enable_via_gpio;
ESP_ERROR_CHECK(esp_eth_init(&config));
ESP_ERROR_CHECK(esp_eth_enable());
xEventGroupWaitBits(eth_event_group, GOTIP_BIT, true, true, portMAX_DELAY);
vTaskDelay(15000 / portTICK_RATE_MS);
ESP_ERROR_CHECK(esp_eth_disable());
ESP_ERROR_CHECK(esp_eth_deinit());
}

View file

@ -6,7 +6,7 @@ set(include_dirs
port/esp32/include/arch
)
set(srcs
set(srcs
"apps/dhcpserver/dhcpserver.c"
"apps/ping/esp_ping.c"
"apps/ping/ping.c"
@ -92,7 +92,7 @@ set(srcs
"port/esp32/netif/wlanif.c")
if(CONFIG_LWIP_PPP_SUPPORT)
list(APPEND srcs
list(APPEND srcs
"lwip/src/netif/ppp/auth.c"
"lwip/src/netif/ppp/ccp.c"
"lwip/src/netif/ppp/chap-md5.c"
@ -129,7 +129,7 @@ idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
LDFRAGMENTS linker.lf
REQUIRES vfs esp_wifi
PRIV_REQUIRES ethernet tcpip_adapter nvs_flash)
PRIV_REQUIRES esp_eth tcpip_adapter nvs_flash)
# lots of LWIP source files evaluate macros that check address of stack variables
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address)

View file

@ -56,204 +56,174 @@
#define IFNAME1 'n'
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
* @brief Free resources allocated in L2 layer
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
* @param buf memory alloc in L2 layer
* @note this function is also the callback when invoke pbuf_free
*/
static void
ethernet_low_level_init(struct netif *netif)
static void ethernet_free_rx_buf_l2(void *buf)
{
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
free(buf);
}
/* set MAC hardware address */
/**
* In this function, the hardware should be initialized.
* Invoked by ethernetif_init().
*
* @param netif lwip network interface which has already been initialized
*/
static void ethernet_low_level_init(struct netif *netif)
{
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
#if ESP_LWIP
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
netif->flags |= NETIF_FLAG_IGMP;
#endif
#endif
#ifndef CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE
netif->l2_buffer_free_notify = esp_eth_free_rx_buf;
#endif
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
* @brief This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become availale since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
* @param netif lwip network interface structure for this ethernetif
* @param p MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return err_t ERR_OK if the packet has been sent to Ethernet DMA buffer successfully
* ERR_MEM if private data couldn't be allocated
* ERR_IF if netif is not supported
* ERR_ABORT if there's some wrong when send pbuf payload to DMA buffer
*/
static err_t ESP_IRAM_ATTR
ethernet_low_level_output(struct netif *netif, struct pbuf *p)
static err_t ethernet_low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q = p;
esp_interface_t eth_if = tcpip_adapter_get_esp_if(netif);
esp_err_t ret;
struct pbuf *q = p;
esp_interface_t eth_if = tcpip_adapter_get_esp_if(netif);
esp_err_t ret = ESP_FAIL;
esp_eth_handle_t eth_handle = (esp_eth_handle_t)netif->state;
if (eth_if != ESP_IF_ETH) {
LWIP_DEBUGF(NETIF_DEBUG, ("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len));
return ERR_IF;
}
if (q->next == NULL) {
ret = esp_eth_tx(q->payload, q->len);
} else {
LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
if (q != NULL) {
q->l2_owner = NULL;
pbuf_copy(q, p);
} else {
return ERR_MEM;
if (eth_if != ESP_IF_ETH) {
LWIP_DEBUGF(NETIF_DEBUG, ("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len));
return ERR_IF;
}
if (q->next == NULL) {
ret = esp_eth_transmit(eth_handle, q->payload, q->len);
} else {
LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
if (q != NULL) {
#if ESP_LWIP
/* This pbuf RAM was not allocated on layer2, no extra free operation needed in pbuf_free */
q->l2_owner = NULL;
q->l2_buf = NULL;
#endif
pbuf_copy(q, p);
} else {
return ERR_MEM;
}
ret = esp_eth_transmit(eth_handle, q->payload, q->len);
/* content in payload has been copied to DMA buffer, it's safe to free pbuf now */
pbuf_free(q);
}
/* Check error */
if (ret != ESP_OK) {
return ERR_ABRT;
} else {
return ERR_OK;
}
ret = esp_eth_tx(q->payload, q->len);
pbuf_free(q);
}
/* error occured when no memory or peripheral wrong state */
if (ret != ESP_OK)
{
return ERR_ABRT;
} else {
return ERR_OK;
}
}
/**
* This function should be called when a packet is ready to be read
* @brief This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
* @param buffer the ethernet buffer
* @param len the len of buffer
*
* @note When CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE is enabled, a copy of buffer
* will be made for high layer (LWIP) and ethernet is responsible for
* freeing the buffer. Otherwise, high layer and ethernet share the
* same buffer and high layer is responsible for freeing the buffer.
* @param netif lwip network interface structure for this ethernetif
* @param buffer ethernet buffer
* @param len length of buffer
*/
void ESP_IRAM_ATTR
ethernetif_input(struct netif *netif, void *buffer, uint16_t len)
void ethernetif_input(struct netif *netif, void *buffer, uint16_t len)
{
struct pbuf *p;
struct pbuf *p;
if(buffer== NULL || !netif_is_up(netif)) {
#ifndef CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE
if (buffer) {
esp_eth_free_rx_buf(buffer);
if (buffer == NULL || !netif_is_up(netif)) {
if (buffer) {
ethernet_free_rx_buf_l2(buffer);
}
return;
}
/* acquire new pbuf, type: PBUF_REF */
p = pbuf_alloc(PBUF_RAW, len, PBUF_REF);
if (p == NULL) {
ethernet_free_rx_buf_l2(buffer);
return;
}
p->payload = buffer;
#if ESP_LWIP
p->l2_owner = netif;
p->l2_buf = buffer;
#endif
return;
}
#ifdef CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE
p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
if (p == NULL) {
return;
}
p->l2_owner = NULL;
memcpy(p->payload, buffer, len);
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
#else
p = pbuf_alloc(PBUF_RAW, len, PBUF_REF);
if (p == NULL){
esp_eth_free_rx_buf(buffer);
return;
}
p->payload = buffer;
p->l2_owner = netif;
p->l2_buf = buffer;
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
#endif
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
/* the pbuf will be free in upper layer, eg: ethernet_input */
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
* Set up the network interface. It calls the function low_level_init() to do the
* actual init work of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
* @return ERR_OK if the ethernetif is initialized
*/
err_t
ethernetif_init(struct netif *netif)
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("netif != NULL", (netif != NULL));
esp_eth_handle_t eth_handle = (esp_eth_handle_t)netif->state;
/* Initialize interface hostname */
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
#if ESP_LWIP
netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
#else
netif->hostname = "lwip";
netif->hostname = "lwip";
#endif
#endif /* LWIP_NETIF_HOSTNAME */
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
if(esp_eth_get_speed() == ETH_SPEED_MODE_100M){
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
} else {
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
}
/* Initialize the snmp variables and counters inside the struct netif. */
eth_speed_t speed;
esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &speed);
if (speed == ETH_SPEED_100M) {
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
} else {
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
}
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = etharp_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = ethernet_low_level_output;
netif->linkoutput = ethernet_low_level_output;
netif->l2_buffer_free_notify = ethernet_free_rx_buf_l2;
/* initialize the hardware */
ethernet_low_level_init(netif);
ethernet_low_level_init(netif);
return ERR_OK;
return ERR_OK;
}

View file

@ -3049,13 +3049,13 @@ void _mdns_disable_pcb(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protoc
/**
* @brief Dispatch interface changes based on system events
*/
static void _mdns_handle_system_event(esp_event_base_t event_base,
static void _mdns_handle_system_event(esp_event_base_t event_base,
int32_t event_id, tcpip_adapter_if_t interface)
{
if (!_mdns_server) {
return;
}
tcpip_adapter_dhcp_status_t dcst;
if (event_base == WIFI_EVENT) {
switch(event_id) {
@ -3723,7 +3723,7 @@ static void _mdns_execute_action(mdns_action_t * action)
switch(action->type) {
case ACTION_SYSTEM_EVENT:
_mdns_handle_system_event(action->data.sys_event.event_base,
_mdns_handle_system_event(action->data.sys_event.event_base,
action->data.sys_event.event_id, action->data.sys_event.interface);
break;
case ACTION_HOSTNAME_SET:
@ -4120,7 +4120,7 @@ esp_err_t mdns_handle_system_event(void *ctx, system_event_t *event)
return ESP_OK;
}
static void event_handler(void* arg, esp_event_base_t event_base,
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (!_mdns_server) {
@ -4142,7 +4142,7 @@ static void event_handler(void* arg, esp_event_base_t event_base,
if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) {
free(action);
}
}
}
esp_err_t mdns_init()

View file

@ -0,0 +1,633 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "soc/gpio_periph.h"
#include "soc/rtc.h"
#include "hal/emac.h"
#define ETH_CRC_LENGTH (4)
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
uint8_t **rx_buf, uint8_t **tx_buf)
{
hal->dma_regs = &EMAC_DMA;
hal->mac_regs = &EMAC_MAC;
hal->ext_regs = &EMAC_EXT;
hal->descriptors = descriptors;
hal->rx_buf = rx_buf;
hal->tx_buf = tx_buf;
}
void emac_hal_lowlevel_init(emac_hal_context_t *hal)
{
/* GPIO configuration */
/* TX_EN to GPIO21 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
/* TXD0 to GPIO19 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
/* TXD1 to GPIO22 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
/* RXD0 to GPIO25 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_EMAC_RXD0);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
/* RXD1 to GPIO26 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_EMAC_RXD1);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
/* CRS_DV to GPIO27 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
#if CONFIG_ETH_RMII_CLK_INPUT
#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
/* RMII clock (50MHz) input to GPIO0 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
#else
#error "ESP32 EMAC only support input RMII clock to GPIO0"
#endif
#endif
#if CONFIG_ETH_RMII_CLK_OUTPUT
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
/* APLL clock output to GPIO0 (must be configured to 50MHz!) */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 16
/* RMII CLK (50MHz) output to GPIO16 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 17
/* RMII CLK (50MHz) output to GPIO17 */
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
#endif
#endif // CONFIG_ETH_RMII_CLK_OUTPUT
/* Clock configuration */
#if CONFIG_ETH_PHY_INTERFACE_MII
hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 0;
hal->ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1;
hal->ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1;
#elif CONFIG_ETH_PHY_INTERFACE_RMII
hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
#if CONFIG_ETH_RMII_CLK_INPUT
hal->ext_regs->ex_clk_ctrl.ext_en = 1;
hal->ext_regs->ex_clk_ctrl.int_en = 0;
hal->ext_regs->ex_oscclk_conf.clk_sel = 1;
#elif CONFIG_ETH_RMII_CLK_OUTPUT
hal->ext_regs->ex_clk_ctrl.ext_en = 0;
hal->ext_regs->ex_clk_ctrl.int_en = 1;
hal->ext_regs->ex_oscclk_conf.clk_sel = 0;
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 400MHz / 8 */
/* sdm2 = 6, sdm1 = 0, sdm0 = 0, o_div = 2 */
rtc_clk_apll_enable(true, 0, 0, 6, 2);
hal->ext_regs->ex_clkout_conf.div_num = 0;
hal->ext_regs->ex_clkout_conf.h_div_num = 0;
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
/* Choose the APLL clock to output on GPIO */
REG_WRITE(PIN_CTRL, 6);
#endif // CONFIG_RMII_CLK_OUTPUT_GPIO0
#endif // CONFIG_ETH_RMII_CLK_INPUT
#endif // CONFIG_ETH_PHY_INTERFACE_MII
}
void emac_hal_reset(emac_hal_context_t *hal)
{
hal->dma_regs->dmabusmode.sw_rst = 1;
}
bool emac_hal_is_reset_done(emac_hal_context_t *hal)
{
return hal->dma_regs->dmabusmode.sw_rst ? false : true;
}
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal)
{
/* Tell MAC system clock Frequency, which will determin the frequency range of MDC(1MHz~2.5MHz) */
if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 20 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 35) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 2;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 35 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 60) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 3;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 60 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 100) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 0;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 100 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 150) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 1;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ > 150 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 250) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 4;
} else {
hal->mac_regs->emacgmiiaddr.miicsrclk = 5;
}
}
void emac_hal_reset_desc_chain(emac_hal_context_t *hal)
{
/* reset DMA descriptors */
hal->rx_desc = (eth_dma_rx_descriptor_t *)(hal->descriptors);
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->descriptors +
sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM);
/* init rx chain */
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
/* Set Own bit of the Rx descriptor Status: DMA */
hal->rx_desc[i].RDES0.Own = 1;
/* Set Buffer1 size and Second Address Chained bit */
hal->rx_desc[i].RDES1.SecondAddressChained = 1;
hal->rx_desc[i].RDES1.ReceiveBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* Enable Ethernet DMA Rx Descriptor interrupt */
hal->rx_desc[i].RDES1.DisableInterruptOnComplete = 0;
/* point to the buffer */
hal->rx_desc[i].Buffer1Addr = (uint32_t)(hal->rx_buf[i]);
/* point to next descriptor */
hal->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc + i + 1);
}
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
hal->rx_desc[CONFIG_ETH_DMA_RX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc);
/* init tx chain */
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
/* Set Second Address Chained bit */
hal->tx_desc[i].TDES0.SecondAddressChained = 1;
hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* Enable Ethernet DMA Tx Descriptor interrupt */
hal->tx_desc[1].TDES0.InterruptOnComplete = 1;
/* Set the DMA Tx descriptors checksum insertion */
hal->tx_desc[i].TDES0.ChecksumInsertControl = EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL;
/* Enable Transmit Timestamp */
hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1;
/* point to the buffer */
hal->tx_desc[i].Buffer1Addr = (uint32_t)(hal->tx_buf[i]);
/* point to next descriptor */
hal->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc + i + 1);
}
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
hal->tx_desc[CONFIG_ETH_DMA_TX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc);
/* set base address of the first descriptor */
hal->dma_regs->dmarxbaseaddr = (uint32_t)hal->rx_desc;
hal->dma_regs->dmatxbaseaddr = (uint32_t)hal->tx_desc;
}
void emac_hal_init_mac_default(emac_hal_context_t *hal)
{
/* MACCR Configuration */
typeof(hal->mac_regs->gmacconfig) maccr = hal->mac_regs->gmacconfig;
/* Enable the watchdog on the receiver, frame longer than 2048 Bytes is not allowed */
maccr.watchdog = EMAC_WATCHDOG_ENABLE;
/* Enable the jabber timer on the transmitter, frame longer than 2048 Bytes is not allowed */
maccr.jabber = EMAC_JABBER_ENABLE;
/* minimum IFG between frames during transmission is 96 bit times */
maccr.interframegap = EMAC_INTERFRAME_GAP_96BIT;
/* Enable Carrier Sense During Transmission */
maccr.disablecrs = EMAC_CARRIERSENSE_ENABLE;
/* Select port: 10/100 Mbps */
maccr.mii = EMAC_PORT_10_100MBPS;
/* Select speed: here set default 100M, afterwards, will reset by auto-negotiation */
maccr.fespeed = EMAC_SPEED_100M;
/* Allow the reception of frames when the TX_EN signal is asserted in Half-Duplex mode */
maccr.rxown = EMAC_RECEIVE_OWN_ENABLE;
/* Disable internal loopback mode */
maccr.loopback = EMAC_LOOPBACK_DISABLE;
/* Select duplex mode: here set default full duplex, afterwards, will reset by auto-negotiation */
maccr.duplex = EMAC_DUPLEX_FULL;
/* Select the checksum mode for received frame payload's TCP/UDP/ICMP headers */
maccr.rxipcoffload = EMAC_CHECKSUM_HW;
/* Enable MAC retry transmission when a colision occurs in half duplex mode */
maccr.retry = EMAC_RETRY_TRANSMISSION_ENABLE;
/* MAC passes all incoming frames to host, without modifying them */
maccr.padcrcstrip = EMAC_AUTO_PAD_CRC_STRIP_DISABLE;
/* Set Back-Off limit time before retry a transmittion after a collision */
maccr.backofflimit = EMAC_BACKOFF_LIMIT_10;
/* Disable deferral check, MAC defers until the CRS signal goes inactive */
maccr.deferralcheck = EMAC_DEFERRAL_CHECK_DISABLE;
/* Set preamble length 7 Bytes */
maccr.pltf = EMAC_PREAMBLE_LENGTH_7;
hal->mac_regs->gmacconfig = maccr;
/* MACFFR Configuration */
typeof(hal->mac_regs->gmacff) macffr = hal->mac_regs->gmacff;
/* Receiver module passes only those frames to the Application that pass the SA or DA address filter */
macffr.receive_all = EMAC_RECEIVE_ALL_DISABLE;
/* Disable source address filter */
macffr.safe = EMAC_SOURCE_ADDR_FILTER_DISABLE;
macffr.saif = 0;
/* MAC blocks all control frames */
macffr.pcf = EMAC_CONTROL_FRAME_BLOCKALL;
/* AFM module passes all received broadcast frames and multicast frames */
macffr.dbf = EMAC_RECEPT_BROADCAST_ENABLE;
macffr.pam = 1;
/* Address Check block operates in normal filtering mode for the DA address */
macffr.daif = EMAC_DEST_ADDR_FILTER_NORMAL;
/* Disable Promiscuous Mode */
macffr.pmode = EMAC_PROMISCUOUS_DISABLE;
hal->mac_regs->gmacff = macffr;
/* MACFCR Configuration */
typeof(hal->mac_regs->gmacfc) macfcr = hal->mac_regs->gmacfc;
/* Pause time */
macfcr.pause_time = EMAC_PAUSE_TIME;
/* Enable generation of Zero-Quanta Pause Control frames */
macfcr.dzpq = EMAC_ZERO_QUANTA_PAUSE_ENABLE;
/* Threshold of the PAUSE to be checked for automatic retransmission of PAUSE Frame */
macfcr.plt = EMAC_PAUSE_LOW_THRESHOLD_MINUS_28;
/* Don't allow MAC detect Pause frames with MAC address0 unicast address and unique multicast address */
macfcr.upfd = EMAC_UNICAST_PAUSE_DETECT_DISABLE;
/* Enable MAC to decode the received Pause frame and disable its transmitter for a specific time */
macfcr.rfce = EMAC_RECEIVE_FLOW_CONTROL_ENABLE;
/* Enable MAC to transmit Pause frames in full duplex mode or the MAC back-pressure operation in half duplex mode */
macfcr.tfce = EMAC_TRANSMIT_FLOW_CONTROL_ENABLE;
hal->mac_regs->gmacfc = macfcr;
}
void emac_hal_init_dma_default(emac_hal_context_t *hal)
{
/* DMAOMR Configuration */
typeof(hal->dma_regs->dmaoperation_mode) dmaomr = hal->dma_regs->dmaoperation_mode;
/* Enable Dropping of TCP/IP Checksum Error Frames */
dmaomr.dis_drop_tcpip_err_fram = EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE;
/* Enable Receive Store Forward */
dmaomr.rx_store_forward = EMAC_RECEIVE_STORE_FORWARD_ENABLE;
/* Enable Flushing of Received Frames because of the unavailability of receive descriptors or buffers */
dmaomr.dis_flush_recv_frames = EMAC_FLUSH_RECEIVED_FRAME_ENABLE;
/* Enable Transmit Store Forward */
dmaomr.tx_str_fwd = EMAC_TRANSMIT_STORE_FORWARD_ENABLE;
/* Flush Transmit FIFO */
dmaomr.flush_tx_fifo = 1;
/* Transmit Threshold Control */
dmaomr.tx_thresh_ctrl = EMAC_TRANSMIT_THRESHOLD_CONTROL_64;
/* Disable Forward Error Frame */
dmaomr.fwd_err_frame = EMAC_FORWARD_ERROR_FRAME_DISABLE;
/* Disable forward undersized good frame */
dmaomr.fwd_under_gf = EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE;
/* Receive Threshold Control */
dmaomr.rx_thresh_ctrl = EMAC_RECEIVE_THRESHOLD_CONTROL_64;
/* Allow the DMA to process a second frame of Transmit data even before obtaining the status for the first frame */
dmaomr.opt_second_frame = EMAC_OPERATE_SECOND_FRAME_ENABLE;
hal->dma_regs->dmaoperation_mode = dmaomr;
/* DMABMR Configuration */
typeof(hal->dma_regs->dmabusmode) dmabmr = hal->dma_regs->dmabusmode;
/* Enable Mixed Burst */
dmabmr.dmamixedburst = EMAC_MIXED_BURST_ENABLE;
/* Enable Address Aligned Beates */
dmabmr.dmaaddralibea = EMAC_ADDR_ALIGN_BEATS_ENABLE;
/* Use Separate PBL */
dmabmr.use_sep_pbl = EMAC_USE_SEPARATE_PBL;
/* Set Rx/Tx DMA Burst Length */
dmabmr.rx_dma_pbl = EMAC_DMA_BURST_LENGTH_32BEAT;
dmabmr.prog_burst_len = EMAC_DMA_BURST_LENGTH_32BEAT;
/* Enable Enhanced Descriptor,8 Words(32 Bytes) */
dmabmr.alt_desc_size = EMAC_ENHANCED_DESCRIPTOR_ENABLE;
/* Specifies the number of word to skip between two unchained descriptors (Ring mode) */
dmabmr.desc_skip_len = 0;
/* DMA Arbitration Scheme */
dmabmr.dma_arb_sch = EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN;
/* Set priority ratio in the weighted round-robin arbitration between Rx DMA and Tx DMA */
dmabmr.pri_ratio = EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1;
hal->dma_regs->dmabusmode = dmabmr;
}
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed)
{
hal->mac_regs->gmacconfig.fespeed = speed;
}
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex)
{
hal->mac_regs->gmacconfig.duplex = duplex;
}
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable)
{
if (enable) {
hal->mac_regs->gmacff.pmode = 1;
} else {
hal->mac_regs->gmacff.pmode = 0;
}
}
bool emac_hal_is_mii_busy(emac_hal_context_t *hal)
{
return hal->mac_regs->emacgmiiaddr.miibusy ? true : false;
}
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write)
{
typeof(hal->mac_regs->emacgmiiaddr) macmiiar = hal->mac_regs->emacgmiiaddr;
macmiiar.miidev = phy_addr;
/* Set the PHY register address */
macmiiar.miireg = phy_reg;
if (write) {
/* Set write mode */
macmiiar.miiwrite = 1;
} else {
/* Set read mode */
macmiiar.miiwrite = 0;
}
/* Set MII busy bit */
macmiiar.miibusy = 1;
/* Write the result value into the MII Address register */
hal->mac_regs->emacgmiiaddr = macmiiar;
}
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value)
{
hal->mac_regs->emacmiidata.mii_data = reg_value;
}
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal)
{
return hal->mac_regs->emacmiidata.mii_data;
}
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr)
{
/* Make sure mac address is unicast type */
if (!(mac_addr[0] & 0x01)) {
hal->mac_regs->emacaddr0high.address0_hi = (mac_addr[5] << 8) | mac_addr[4];
hal->mac_regs->emacaddr0low = (mac_addr[3] << 24) | (mac_addr[2] << 16) | (mac_addr[1] << 8) | (mac_addr[0]);
}
}
void emac_hal_start(emac_hal_context_t *hal)
{
typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode;
typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig;
/* Enable Ethernet MAC and DMA Interrupt */
hal->dma_regs->dmain_en.val = 0xFFFFFFFF;
/* Flush Transmit FIFO */
opm.flush_tx_fifo = 1;
/* Start DMA transmission */
opm.start_stop_transmission_command = 1;
/* Start DMA reception */
opm.start_stop_rx = 1;
/* Enable transmit state machine of the MAC for transmission on the MII */
cfg.tx = 1;
/* Enable receive state machine of the MAC for reception from the MII */
cfg.rx = 1;
hal->dma_regs->dmaoperation_mode = opm;
hal->mac_regs->gmacconfig = cfg;
/* Clear all pending interrupts */
hal->dma_regs->dmastatus.val = 0xFFFFFFFF;
}
void emac_hal_stop(emac_hal_context_t *hal)
{
typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode;
typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig;
/* Flush Transmit FIFO */
opm.flush_tx_fifo = 1;
/* Stop DMA transmission */
opm.start_stop_transmission_command = 0;
/* Stop DMA reception */
opm.start_stop_rx = 0;
/* Disable receive state machine of the MAC for reception from the MII */
cfg.rx = 0;
/* Disable transmit state machine of the MAC for transmission on the MII */
cfg.tx = 0;
hal->dma_regs->dmaoperation_mode = opm;
hal->mac_regs->gmacconfig = cfg;
/* Disable Ethernet MAC and DMA Interrupt */
hal->dma_regs->dmain_en.val = 0x0;
}
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal)
{
return hal->tx_desc->TDES0.Own;
}
void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length)
{
/* Get the number of Tx buffers to use for the frame */
uint32_t bufcount = 0;
uint32_t lastlen = length;
while (lastlen > CONFIG_ETH_DMA_BUFFER_SIZE) {
lastlen -= CONFIG_ETH_DMA_BUFFER_SIZE;
bufcount++;
}
if (lastlen) {
bufcount++;
}
/* A frame is transmitted in multiple descriptor */
for (uint32_t i = 0; i < bufcount; i++) {
/* Clear FIRST and LAST segment bits */
hal->tx_desc->TDES0.FirstSegment = 0;
hal->tx_desc->TDES0.LastSegment = 0;
if (i == 0) {
/* Setting the first segment bit */
hal->tx_desc->TDES0.FirstSegment = 1;
}
if (i == (bufcount - 1)) {
/* Setting the last segment bit */
hal->tx_desc->TDES0.LastSegment = 1;
/* Enable transmit interrupt */
hal->tx_desc->TDES0.InterruptOnComplete = 1;
/* Program size */
hal->tx_desc->TDES1.TransmitBuffer1Size = lastlen;
/* copy data from uplayer stack buffer */
memcpy((void *)(hal->tx_desc->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, lastlen);
} else {
/* Program size */
hal->tx_desc->TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* copy data from uplayer stack buffer */
memcpy((void *)(hal->tx_desc->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE);
}
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
hal->tx_desc->TDES0.Own = EMAC_DMADESC_OWNER_DMA;
/* Point to next descriptor */
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->tx_desc->Buffer2NextDescAddr);
}
hal->dma_regs->dmatxpolldemand = 0;
}
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain)
{
eth_dma_rx_descriptor_t *desc_iter = NULL;
eth_dma_rx_descriptor_t *first_desc = NULL;
uint32_t iter = 0;
uint32_t seg_count = 0;
uint32_t len = 0;
uint32_t frame_count = 0;
first_desc = hal->rx_desc;
desc_iter = hal->rx_desc;
/* Traverse descriptors owned by CPU */
while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (iter < CONFIG_ETH_DMA_RX_BUFFER_NUM) && !frame_count) {
iter++;
seg_count++;
/* Last segment in frame */
if (desc_iter->RDES0.LastDescriptor) {
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
/* update unhandled frame count */
frame_count++;
}
/* First segment in frame */
if (desc_iter->RDES0.FirstDescriptor) {
first_desc = desc_iter;
}
/* point to next descriptor */
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
/* there's at least one frame to process */
if (frame_count) {
/* check how many frames left to handle */
while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (iter < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
iter++;
if (desc_iter->RDES0.LastDescriptor) {
frame_count++;
}
/* point to next descriptor */
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
desc_iter = first_desc;
for (iter = 0; iter < seg_count - 1; iter++) {
/* copy data to buffer */
memcpy(buf + iter * CONFIG_ETH_DMA_BUFFER_SIZE,
(void *)(desc_iter->Buffer1Addr), CONFIG_ETH_DMA_BUFFER_SIZE);
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA;
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
memcpy(buf + iter * CONFIG_ETH_DMA_BUFFER_SIZE,
(void *)(desc_iter->Buffer1Addr), len % CONFIG_ETH_DMA_BUFFER_SIZE);
desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA;
/* update rxdesc */
hal->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
/* poll rx demand */
hal->dma_regs->dmarxpolldemand = 0;
frame_count--;
}
*frames_remain = frame_count;
return len;
}
void emac_hal_isr(void *arg)
{
emac_hal_context_t *hal = *(emac_hal_context_t **)arg;
typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus;
/* DMA Normal Interrupt */
if (dma_status.norm_int_summ) {
/* Transmit Interrupt */
if (dma_status.trans_int) {
emac_hal_tx_complete_cb(arg);
hal->dma_regs->dmastatus.trans_int = 1;
}
/* Transmit Buffer Unavailable */
if (dma_status.trans_buf_unavail) {
emac_hal_tx_unavail_cb(arg);
hal->dma_regs->dmastatus.trans_buf_unavail = 1;
}
/* Receive Interrupt */
if (dma_status.recv_int) {
emac_hal_rx_complete_cb(arg);
hal->dma_regs->dmastatus.recv_int = 1;
}
/* Early Receive Interrupt */
if (dma_status.early_recv_int) {
emac_hal_rx_early_cb(arg);
hal->dma_regs->dmastatus.early_recv_int = 1;
}
hal->dma_regs->dmastatus.norm_int_summ = 1;
}
/* DMA Abnormal Interrupt */
if (dma_status.abn_int_summ) {
/* Transmit Process Stopped */
if (dma_status.trans_proc_stop) {
hal->dma_regs->dmastatus.trans_proc_stop = 1;
}
/* Transmit Jabber Timeout */
if (dma_status.trans_jabber_to) {
hal->dma_regs->dmastatus.trans_jabber_to = 1;
}
/* Receive FIFO Overflow */
if (dma_status.recv_ovflow) {
hal->dma_regs->dmastatus.recv_ovflow = 1;
}
/* Transmit Underflow */
if (dma_status.trans_undflow) {
hal->dma_regs->dmastatus.trans_undflow = 1;
}
/* Receive Buffer Unavailable */
if (dma_status.recv_buf_unavail) {
emac_hal_rx_unavail_cb(arg);
hal->dma_regs->dmastatus.recv_buf_unavail = 1;
}
/* Receive Process Stopped */
if (dma_status.recv_proc_stop) {
hal->dma_regs->dmastatus.recv_proc_stop = 1;
}
/* Receive Watchdog Timeout */
if (dma_status.recv_wdt_to) {
hal->dma_regs->dmastatus.recv_wdt_to = 1;
}
/* Early Transmit Interrupt */
if (dma_status.early_trans_int) {
hal->dma_regs->dmastatus.early_trans_int = 1;
}
/* Fatal Bus Error */
if (dma_status.fatal_bus_err_int) {
hal->dma_regs->dmastatus.fatal_bus_err_int = 1;
}
hal->dma_regs->dmastatus.abn_int_summ = 1;
}
}
__attribute__((weak)) void emac_hal_tx_complete_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
__attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
__attribute__((weak)) void emac_hal_rx_complete_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
__attribute__((weak)) void emac_hal_rx_early_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
__attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}

View file

@ -0,0 +1,399 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/emac_dma_struct.h"
#include "soc/emac_mac_struct.h"
#include "soc/emac_ext_struct.h"
#define EMAC_MEDIA_INTERFACE_MII (0)
#define EMAC_MEDIA_INTERFACE_RMII (1)
#define EMAC_WATCHDOG_ENABLE (0)
#define EMAC_WATCHDOG_DISABLE (1)
#define EMAC_JABBER_ENABLE (0)
#define EMAC_JABBER_DISABLE (1)
#define EMAC_INTERFRAME_GAP_96BIT (0)
#define EMAC_INTERFRAME_GAP_88BIT (1)
#define EMAC_INTERFRAME_GAP_80BIT (2)
#define EMAC_INTERFRAME_GAP_72BIT (3)
#define EMAC_INTERFRAME_GAP_64BIT (4)
#define EMAC_INTERFRAME_GAP_56BIT (5)
#define EMAC_INTERFRAME_GAP_48BIT (6)
#define EMAC_INTERFRAME_GAP_40BIT (7)
#define EMAC_CARRIERSENSE_ENABLE (0)
#define EMAC_CARRIERSENSE_DISABLE (1)
#define EMAC_PORT_1000MBPS (0)
#define EMAC_PORT_10_100MBPS (1)
#define EMAC_SPEED_10M (0)
#define EMAC_SPEED_100M (1)
#define EMAC_RECEIVE_OWN_ENABLE (0)
#define EMAC_RECEIVE_OWN_DISABLE (1)
#define EMAC_LOOPBACK_DISABLE (0)
#define EMAC_LOOPBACK_ENABLE (1)
#define EMAC_DUPLEX_HALF (0)
#define EMAC_DUPLEX_FULL (1)
#define EMAC_CHECKSUM_SW (0)
#define EMAC_CHECKSUM_HW (1)
#define EMAC_RETRY_TRANSMISSION_ENABLE (0)
#define EMAC_RETRY_TRANSMISSION_DISABLE (1)
#define EMAC_AUTO_PAD_CRC_STRIP_DISABLE (0)
#define EMAC_AUTO_PAD_CRC_STRIP_ENABLE (1)
#define EMAC_BACKOFF_LIMIT_10 (0)
#define EMAC_BACKOFF_LIMIT_8 (1)
#define EMAC_BACKOFF_LIMIT_4 (2)
#define EMAC_BACKOFF_LIMIT_1 (3)
#define EMAC_DEFERRAL_CHECK_DISABLE (0)
#define EMAC_DEFERRAL_CHECK_ENABLE (1)
#define EMAC_PREAMBLE_LENGTH_7 (0)
#define EMAC_PREAMBLE_LENGTH_5 (1)
#define EMAC_PREAMBLE_LENGTH_3 (2)
#define EMAC_RECEIVE_ALL_DISABLE (0)
#define EMAC_RECEIVE_ALL_ENABLE (1)
#define EMAC_SOURCE_ADDR_FILTER_DISABLE (0)
#define EMAC_SOURCE_ADDR_FILTER_NORMAL (2)
#define EMAC_SOURCE_ADDR_FILTER_INVERSE (3)
#define EMAC_CONTROL_FRAME_BLOCKALL (0)
#define EMAC_CONTROL_FRAME_FORWARDALL_PAUSE (1)
#define EMAC_CONTROL_FRAME_FORWARDALL (2)
#define EMAC_CONTROL_FRAME_FORWARDFILT (3)
#define EMAC_RECEPT_BROADCAST_ENABLE (0)
#define EMAC_RECEPT_BROADCAST_DISABLE (1)
#define EMAC_DEST_ADDR_FILTER_NORMAL (0)
#define EMAC_DEST_ADDR_FILTER_INVERSE (1)
#define EMAC_PROMISCUOUS_DISABLE (0)
#define EMAC_PROMISCUOUS_ENABLE (1)
#define EMAC_PAUSE_TIME 0x1648
#define EMAC_ZERO_QUANTA_PAUSE_ENABLE (0)
#define EMAC_ZERO_QUANTA_PAUSE_DISABLE (1)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_256
#define EMAC_UNICAST_PAUSE_DETECT_DISABLE (0)
#define EMAC_UNICAST_PAUSE_DETECT_ENABLE (1)
#define EMAC_RECEIVE_FLOW_CONTROL_DISABLE (0)
#define EMAC_RECEIVE_FLOW_CONTROL_ENABLE (1)
#define EMAC_TRANSMIT_FLOW_CONTROL_DISABLE (0)
#define EMAC_TRANSMIT_FLOW_CONTROL_ENABLE (1)
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE (0)
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_DISABLE (1)
#define EMAC_RECEIVE_STORE_FORWARD_DISABLE (0)
#define EMAC_RECEIVE_STORE_FORWARD_ENABLE (1)
#define EMAC_FLUSH_RECEIVED_FRAME_ENABLE (0)
#define EMAC_FLUSH_RECEIVED_FRAME_DISABLE (1)
#define EMAC_TRANSMIT_STORE_FORWARD_DISABLE (0)
#define EMAC_TRANSMIT_STORE_FORWARD_ENABLE (1)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_64 (0)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_128 (1)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_192 (2)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_256 (3)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_40 (4)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_32 (5)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_24 (6)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_16 (7)
#define EMAC_FORWARD_ERROR_FRAME_DISABLE (0)
#define EMAC_FORWARD_ERROR_FRAME_ENABLE (1)
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE (0)
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_ENABLE (1)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_64 (0)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_32 (1)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_96 (2)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_128 (3)
#define EMAC_OPERATE_SECOND_FRAME_DISABLE (0)
#define EMAC_OPERATE_SECOND_FRAME_ENABLE (1)
#define EMAC_MIXED_BURST_DISABLE (0)
#define EMAC_MIXED_BURST_ENABLE (1)
#define EMAC_ADDR_ALIGN_BEATS_DISABLE (0)
#define EMAC_ADDR_ALIGN_BEATS_ENABLE (1)
#define EMAC_UNUSE_SEPARATE_PBL (0)
#define EMAC_USE_SEPARATE_PBL (1)
#define EMAC_DMA_BURST_LENGTH_1BEAT (1)
#define EMAC_DMA_BURST_LENGTH_2BEAT (2)
#define EMAC_DMA_BURST_LENGTH_4BEAT (4)
#define EMAC_DMA_BURST_LENGTH_8BEAT (8)
#define EMAC_DMA_BURST_LENGTH_16BEAT (16)
#define EMAC_DMA_BURST_LENGTH_32BEAT (32)
#define EMAC_ENHANCED_DESCRIPTOR_DISABLE (0)
#define EMAC_ENHANCED_DESCRIPTOR_ENABLE (1)
#define EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN (0)
#define EMAC_DMA_ARBITRATION_SCHEME_FIXEDPRIO (1)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
/**
* @brief Ethernet DMA TX Descriptor
*
*/
typedef struct {
volatile union {
struct {
uint32_t Deferred : 1; /*!< MAC defers before transmission */
uint32_t UnderflowErr : 1; /*!< DMA encountered an empty transmit buffer */
uint32_t ExcessiveDeferral : 1; /*!< Excessive deferral of over 24,288 bit times */
uint32_t CollisionCount : 4; /*!< Number of collisions occurred before transmitted */
uint32_t VLanFrame : 1; /*!< Transmitted frame is a VLAN-type frame */
uint32_t ExcessiveCollision : 1; /*!< Transmission aborted after 16 successive collisions */
uint32_t LateCollision : 1; /*!< Collision occurred after the collision window */
uint32_t NoCarrier : 1; /*!< Carrier Sense signal from the PHY was not asserted */
uint32_t LossCarrier : 1; /*!< Loss of carrier occurred during transmission */
uint32_t PayloadChecksumErr : 1; /*!< Checksum error in TCP/UDP/ICMP datagram payload */
uint32_t FrameFlushed : 1; /*!< DMA or MTL flushed the frame */
uint32_t JabberTimeout : 1; /*!< MAC transmitter has experienced a jabber timeout */
uint32_t ErrSummary : 1; /*!< Error Summary */
uint32_t IPHeadErr : 1; /*!< IP Header Error */
uint32_t TxTimestampStatus : 1; /*!< Timestamp captured for the transmit frame */
uint32_t VLANInsertControl : 2; /*!< VLAN tagging or untagging before transmitting */
uint32_t SecondAddressChained : 1; /*!< Second address in the descriptor is Next Descriptor address */
uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */
uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */
uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */
uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */
uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */
uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */
uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */
uint32_t LastSegment : 1; /*!< Buffer contains the last segment of a frame */
uint32_t InterruptOnComplete : 1; /*!< Interrupt after frame transmitted */
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
};
uint32_t Value;
} TDES0;
union {
struct {
uint32_t TransmitBuffer1Size : 13; /*!< First data buffer byte size */
uint32_t Reserved : 3; /*!< Reserved */
uint32_t TransmitBuffer2Size : 13; /*!< Second data buffer byte size */
uint32_t SAInsertControl : 3; /*!< Control MAC add or replace Source Address field */
};
uint32_t Value;
} TDES1;
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
uint32_t Reserved1; /*!< Reserved */
uint32_t Reserved2; /*!< Reserved */
uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */
uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */
} eth_dma_tx_descriptor_t;
#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */
#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */
/**
* @brief Ethernet DMA RX Descriptor
*
*/
typedef struct {
volatile union {
struct {
uint32_t ExtendStatusAvailable : 1; /*!< Extended statsu is available in RDES4 */
uint32_t CRCErr : 1; /*!< CRC error occurred on frame */
uint32_t DribbleBitErr : 1; /*!< frame contains non int multiple of 8 bits */
uint32_t ReceiveErr : 1; /*!< Receive error */
uint32_t ReceiveWatchdogTimeout : 1; /*!< Receive Watchdog timeout */
uint32_t FrameType : 1; /*!< Ethernet type or IEEE802.3 */
uint32_t LateCollision : 1; /*!< Late collision occurred during reception */
uint32_t TSAvailIPChecksumErrGiantFrame : 1; /*!< Timestamp available or IP Checksum error or Giant frame */
uint32_t LastDescriptor : 1; /*!< Last buffer of the frame */
uint32_t FirstDescriptor : 1; /*!< First buffer of the frame */
uint32_t VLANTag : 1; /*!< VLAN Tag: received frame is a VLAN frame */
uint32_t OverflowErr : 1; /*!< Frame was damaged due to buffer overflow */
uint32_t LengthErr : 1; /*!< Frame size not matching with length field */
uint32_t SourceAddrFilterFail : 1; /*!< SA field of frame failed the SA filter */
uint32_t DescriptorErr : 1; /*!< Frame truncated and DMA doesn't own next descriptor */
uint32_t ErrSummary : 1; /*!< Error Summary, OR of all errors in RDES */
uint32_t FrameLength : 14; /*!< Byte length of received frame */
uint32_t DestinationAddrFilterFail : 1; /*!< Frame failed in the DA Filter in the MAC */
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
};
uint32_t Value;
} RDES0;
union {
struct {
uint32_t ReceiveBuffer1Size : 13; /*!< First data buffer size in bytes */
uint32_t Reserved1 : 1; /*!< Reserved */
uint32_t SecondAddressChained : 1; /*!< Seconde address is the Next Descriptor address */
uint32_t ReceiveEndOfRing : 1; /*!< Descriptor reached its final descriptor */
uint32_t ReceiveBuffer2Size : 13; /*!< Second data buffer size in bytes */
uint32_t Reserved : 2; /*!< Reserved */
uint32_t DisableInterruptOnComplete : 1; /*!< Disable the assertion of interrupt to host */
};
uint32_t Value;
} RDES1;
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
volatile union {
struct {
uint32_t IPPayloadType : 3; /*!< Type of payload in the IP datagram */
uint32_t IPHeadErr : 1; /*!< IP header error */
uint32_t IPPayloadErr : 1; /*!< IP payload error */
uint32_t IPChecksumBypass : 1; /*!< Checksum offload engine is bypassed */
uint32_t IPv4PacketReceived : 1; /*!< Received packet is an IPv4 packet */
uint32_t IPv6PacketReceived : 1; /*!< Received packet is an IPv6 packet */
uint32_t MessageType : 4; /*!< PTP Message Type */
uint32_t PTPFrameType : 1; /*!< PTP message is over Ethernet or IPv4/IPv6 */
uint32_t PTPVersion : 1; /*!< Version of PTP protocol */
uint32_t TimestampDropped : 1; /*!< Timestamp dropped because of overflow */
uint32_t Reserved1 : 1; /*!< Reserved */
uint32_t AVPacketReceived : 1; /*!< AV packet is received */
uint32_t AVTaggedPacketReceived : 1; /*!< AV tagged packet is received */
uint32_t VLANTagPrioVal : 3; /*!< VLAN tag's user value in the received packekt */
uint32_t Reserved2 : 3; /*!< Reserved */
uint32_t Layer3FilterMatch : 1; /*!< Received frame matches one of the enabled Layer3 IP */
uint32_t Layer4FilterMatch : 1; /*!< Received frame matches one of the enabled Layer4 IP */
uint32_t Layer3Layer4FilterNumberMatch : 2; /*!< Number of Layer3 and Layer4 Filter that matches the received frame */
uint32_t Reserved3 : 4; /*!< Reserved */
};
uint32_t Value;
} ExtendedStatus;
uint32_t Reserved; /*!< Reserved */
uint32_t TimeStampLow; /*!< Receive frame timestamp low */
uint32_t TimeStampHigh; /*!< Receive frame timestamp high */
} eth_dma_rx_descriptor_t;
#define EMAC_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
#define EMAC_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
#define EMAC_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
#define EMAC_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
#define EMAC_DMADESC_OWNER_CPU (0)
#define EMAC_DMADESC_OWNER_DMA (1)
typedef struct {
emac_mac_dev_t *mac_regs;
emac_dma_dev_t *dma_regs;
emac_ext_dev_t *ext_regs;
uint8_t **rx_buf;
uint8_t **tx_buf;
void *descriptors;
eth_dma_rx_descriptor_t *rx_desc;
eth_dma_tx_descriptor_t *tx_desc;
} emac_hal_context_t;
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
uint8_t **rx_buf, uint8_t **tx_buf);
void emac_hal_reset_desc_chain(emac_hal_context_t *hal);
void emac_hal_lowlevel_init(emac_hal_context_t *hal);
void emac_hal_reset(emac_hal_context_t *hal);
bool emac_hal_is_reset_done(emac_hal_context_t *hal);
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal);
void emac_hal_init_mac_default(emac_hal_context_t *hal);
void emac_hal_init_dma_default(emac_hal_context_t *hal);
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed);
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex);
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable);
bool emac_hal_is_mii_busy(emac_hal_context_t *hal);
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write);
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value);
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal);
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr);
void emac_hal_start(emac_hal_context_t *hal);
void emac_hal_stop(emac_hal_context_t *hal);
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal);
void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain);
void emac_hal_isr(void *arg);
void emac_hal_tx_complete_cb(void *arg);
void emac_hal_tx_unavail_cb (void *arg);
void emac_hal_rx_complete_cb (void *arg);
void emac_hal_rx_early_cb(void *arg);
void emac_hal_rx_unavail_cb(void *arg);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,162 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
typedef volatile struct {
union {
struct {
uint32_t sw_rst : 1; /*When this bit is set the MAC DMA Controller resets the logic and all internal registers of the MAC. It is cleared automatically after the reset operation is complete in all of the ETH_MAC clock domains. Before reprogramming any register of the ETH_MAC you should read a zero (0) value in this bit.*/
uint32_t dma_arb_sch : 1; /*This bit specifies the arbitration scheme between the transmit and receive paths.1'b0: weighted round-robin with RX:TX or TX:RX priority specified in PR (bit[15:14]). 1'b1 Fixed priority (Rx priority to Tx).*/
uint32_t desc_skip_len : 5; /*This bit specifies the number of Word to skip between two unchained descriptors.The address skipping starts from the end of current descriptor to the start of next descriptor. When the DSL(DESC_SKIP_LEN) value is equal to zero the descriptor table is taken as contiguous by the DMA in Ring mode.*/
uint32_t alt_desc_size : 1; /*When set the size of the alternate descriptor increases to 32 bytes.*/
uint32_t prog_burst_len : 6; /*These bits indicate the maximum number of beats to be transferred in one DMA transaction. If the number of beats to be transferred is more than 32 then perform the following steps: 1. Set the PBLx8 mode 2. Set the PBL(PROG_BURST_LEN).*/
uint32_t pri_ratio : 2; /*These bits control the priority ratio in the weighted round-robin arbitration between the Rx DMA and Tx DMA. These bits are valid only when Bit 1 (DA) is reset. The priority ratio Rx:Tx represented by each bit: 2'b00 -- 1: 1 2'b01 -- 2: 0 2'b10 -- 3: 1 2'b11 -- 4: 1*/
uint32_t fixed_burst : 1; /*This bit controls whether the AHB master interface performs fixed burst transfers or not. When set the AHB interface uses only SINGLE INCR4 INCR8 or INCR16 during start of the normal burst transfers. When reset the AHB interface uses SINGLE and INCR burst transfer Operations.*/
uint32_t rx_dma_pbl : 6; /*This field indicates the maximum number of beats to be transferred in one Rx DMA transaction. This is the maximum value that is used in a single block Read or Write.The Rx DMA always attempts to burst as specified in the RPBL(RX_DMA_PBL) bit each time it starts a burst transfer on the host bus. You can program RPBL with values of 1 2 4 8 16 and 32. Any other value results in undefined behavior. This field is valid and applicable only when USP(USE_SEP_PBL) is set high.*/
uint32_t use_sep_pbl : 1; /*When set high this bit configures the Rx DMA to use the value configured in Bits[22:17] as PBL. The PBL value in Bits[13:8] is applicable only to the Tx DMA operations. When reset to low the PBL value in Bits[13:8] is applicable for both DMA engines.*/
uint32_t pblx8_mode : 1; /*When set high this bit multiplies the programmed PBL value (Bits[22:17] and Bits[13:8]) eight times. Therefore the DMA transfers the data in 8 16 32 64 128 and 256 beats depending on the PBL value.*/
uint32_t dmaaddralibea : 1; /*When this bit is set high and the FIXED_BURST bit is 1 the AHB interface generates all bursts aligned to the start address LS bits. If the FIXED_BURST bit is 0 the first burst (accessing the start address of data buffer) is not aligned but subsequent bursts are aligned to the address.*/
uint32_t dmamixedburst : 1; /*When this bit is set high and the FIXED_BURST bit is low the AHB master interface starts all bursts of a length more than 16 with INCR (undefined burst) whereas it reverts to fixed burst transfers (INCRx and SINGLE) for burst length of 16 and less.*/
uint32_t reserved27 : 1;
uint32_t reserved28 : 2;
uint32_t reserved30 : 1;
uint32_t reserved31 : 1;
};
uint32_t val;
} dmabusmode;
uint32_t dmatxpolldemand; /*When these bits are written with any value the DMA reads the current descriptor to which the Register (Current Host Transmit Descriptor Register) is pointing. If that descriptor is not available (owned by the Host) the transmission returns to the suspend state and Bit[2] (TU) of Status Register is asserted. If the descriptor is available the transmission resumes.*/
uint32_t dmarxpolldemand; /*When these bits are written with any value the DMA reads the current descriptor to which the Current Host Receive Descriptor Register is pointing. If that descriptor is not available (owned by the Host) the reception returns to the Suspended state and Bit[7] (RU) of Status Register is asserted. If the descriptor is available the Rx DMA returns to the active state.*/
uint32_t dmarxbaseaddr; /*This field contains the base address of the first descriptor in the Receive Descriptor list. The LSB Bits[1:0] are ignored and internally taken as all-zero by the DMA. Therefore these LSB bits are read-only.*/
uint32_t dmatxbaseaddr; /*This field contains the base address of the first descriptor in the Transmit Descriptor list. The LSB Bits[1:0] are ignored and are internally taken as all-zero by the DMA.Therefore these LSB bits are read-only.*/
union {
struct {
uint32_t trans_int : 1; /*This bit indicates that the frame transmission is complete. When transmission is complete Bit[31] (OWN) of TDES0 is reset and the specific frame status information is updated in the Descriptor.*/
uint32_t trans_proc_stop : 1; /*This bit is set when the transmission is stopped.*/
uint32_t trans_buf_unavail : 1; /*This bit indicates that the host owns the Next Descriptor in the Transmit List and the DMA cannot acquire it. Transmission is suspended. Bits[22:20] explain the Transmit Process state transitions. To resume processing Transmit descriptors the host should change the ownership of the descriptor by setting TDES0[31] and then issue a Transmit Poll Demand Command.*/
uint32_t trans_jabber_to : 1; /*This bit indicates that the Transmit Jabber Timer expired which happens when the frame size exceeds 2 048 (10 240 bytes when the Jumbo frame is enabled). When the Jabber Timeout occurs the transmission process is aborted and placed in the Stopped state. This causes the Transmit Jabber Timeout TDES0[14] flag to assert.*/
uint32_t recv_ovflow : 1; /*This bit indicates that the Receive Buffer had an Overflow during frame reception. If the partial frame is transferred to the application the overflow status is set in RDES0[11].*/
uint32_t trans_undflow : 1; /*This bit indicates that the Transmit Buffer had an Underflow during frame transmission. Transmission is suspended and an Underflow Error TDES0[1] is set.*/
uint32_t recv_int : 1; /*This bit indicates that the frame reception is complete. When reception is complete the Bit[31] of RDES1 (Disable Interrupt on Completion) is reset in the last Descriptor and the specific frame status information is updated in the descriptor. The reception remains in the Running state.*/
uint32_t recv_buf_unavail : 1; /*This bit indicates that the host owns the Next Descriptor in the Receive List and the DMA cannot acquire it. The Receive Process is suspended. To resume processing Receive descriptors the host should change the ownership of the descriptor and issue a Receive Poll Demand command. If no Receive Poll Demand is issued the Receive Process resumes when the next recognized incoming frame is received. This bit is set only when the previous Receive Descriptor is owned by the DMA.*/
uint32_t recv_proc_stop : 1; /*This bit is asserted when the Receive Process enters the Stopped state.*/
uint32_t recv_wdt_to : 1; /*When set this bit indicates that the Receive Watchdog Timer expired while receiving the current frame and the current frame is truncated after the watchdog timeout.*/
uint32_t early_trans_int : 1; /*This bit indicates that the frame to be transmitted is fully transferred to the MTL Transmit FIFO.*/
uint32_t reserved11 : 2;
uint32_t fatal_bus_err_int : 1; /*This bit indicates that a bus error occurred as described in Bits [25:23]. When this bit is set the corresponding DMA engine disables all of its bus accesses.*/
uint32_t early_recv_int : 1; /*This bit indicates that the DMA filled the first data buffer of the packet. This bit is cleared when the software writes 1 to this bit or when Bit[6] (RI) of this register is set (whichever occurs earlier).*/
uint32_t abn_int_summ : 1; /*Abnormal Interrupt Summary bit value is the logical OR of the following when the corresponding interrupt bits are enabled in Interrupt Enable Register: Bit[1]: Transmit Process Stopped. Bit[3]: Transmit Jabber Timeout. Bit[4]: Receive FIFO Overflow. Bit[5]: Transmit Underflow. Bit[7]: Receive Buffer Unavailable. Bit[8]: Receive Process Stopped. Bit[9]: Receive Watchdog Timeout. Bit[10]: Early Transmit Interrupt. Bit[13]: Fatal Bus Error. Only unmasked bits affect the Abnormal Interrupt Summary bit. This is a sticky bit and must be cleared (by writing 1 to this bit) each time a corresponding bit which causes AIS to be set is cleared.*/
uint32_t norm_int_summ : 1; /*Normal Interrupt Summary bit value is the logical OR of the following bits when the corresponding interrupt bits are enabled in Interrupt Enable Register: Bit[0]: Transmit Interrupt. Bit[2]: Transmit Buffer Unavailable. Bit[6]: Receive Interrupt. Bit[14]: Early Receive Interrupt. Only unmasked bits affect the Normal Interrupt Summary bit.This is a sticky bit and must be cleared (by writing 1 to this bit) each time a corresponding bit which causes NIS to be set is cleared.*/
uint32_t recv_proc_state : 3; /*This field indicates the Receive DMA FSM state. This field does not generate an interrupt. 3'b000: Stopped. Reset or Stop Receive Command issued. 3'b001: Running. Fetching Receive Transfer Descriptor. 3'b010: Reserved for future use. 3'b011: Running. Waiting for RX packets. 3'b100: Suspended. Receive Descriptor Unavailable. 3'b101: Running. Closing Receive Descriptor. 3'b110: TIME_STAMP write state. 3'b111: Running. Transferring the TX packets data from receive buffer to host memory.*/
uint32_t trans_proc_state : 3; /*This field indicates the Transmit DMA FSM state. This field does not generate an interrupt. 3'b000: Stopped. Reset or Stop Transmit Command issued. 3'b001: Running. Fetching Transmit Transfer Descriptor. 3'b010: Reserved for future use. 3'b011: Running. Waiting for TX packets. 3'b100: Suspended. Receive Descriptor Unavailable. 3'b101: Running. Closing Transmit Descriptor. 3'b110: TIME_STAMP write state. 3'b111: Running. Transferring the TX packets data from transmit buffer to host memory.*/
uint32_t error_bits : 3; /*This field indicates the type of error that caused a Bus Error for example error response on the AHB interface. This field is valid only when Bit[13] (FBI) is set. This field does not generate an interrupt. 3'b000: Error during Rx DMA Write Data Transfer. 3'b011: Error during Tx DMA Read Data Transfer. 3'b100: Error during Rx DMA Descriptor Write Access. 3'b101: Error during Tx DMA Descriptor Write Access. 3'b110: Error during Rx DMA Descriptor Read Access. 3'b111: Error during Tx DMA Descriptor Read Access.*/
uint32_t reserved26 : 1;
uint32_t reserved27 : 1;
uint32_t pmt_int : 1; /*This bit indicates an interrupt event in the PMT module of the ETH_MAC. The software must read the PMT Control and Status Register in the MAC to get the exact cause of interrupt and clear its source to reset this bit to 1'b0.*/
uint32_t ts_tri_int : 1; /*This bit indicates an interrupt event in the Timestamp Generator block of the ETH_MAC.The software must read the corresponding registers in the ETH_MAC to get the exact cause of the interrupt and clear its source to reset this bit to 1'b0.*/
uint32_t reserved30 : 1;
uint32_t reserved31 : 1;
};
uint32_t val;
} dmastatus;
union {
struct {
uint32_t reserved0 : 1;
uint32_t start_stop_rx : 1; /*When this bit is set the Receive process is placed in the Running state. The DMA attempts to acquire the descriptor from the Receive list and processes the incoming frames.When this bit is cleared the Rx DMA operation is stopped after the transfer of the current frame.*/
uint32_t opt_second_frame : 1; /*When this bit is set it instructs the DMA to process the second frame of the Transmit data even before the status for the first frame is obtained.*/
uint32_t rx_thresh_ctrl : 2; /*These two bits control the threshold level of the MTL Receive FIFO. Transfer (request) to DMA starts when the frame size within the MTL Receive FIFO is larger than the threshold. 2'b00: 64 2'b01: 32 2'b10: 96 2'b11: 128 .*/
uint32_t drop_gfrm : 1; /*When set the MAC drops the received giant frames in the Rx FIFO that is frames that are larger than the computed giant frame limit.*/
uint32_t fwd_under_gf : 1; /*When set the Rx FIFO forwards Undersized frames (that is frames with no Error and length less than 64 bytes) including pad-bytes and CRC.*/
uint32_t fwd_err_frame : 1; /*When this bit is reset the Rx FIFO drops frames with error status (CRC error collision error giant frame watchdog timeout or overflow).*/
uint32_t reserved8 : 1;
uint32_t reserved9 : 2;
uint32_t reserved11 : 2;
uint32_t start_stop_transmission_command : 1; /*When this bit is set transmission is placed in the Running state and the DMA checks the Transmit List at the current position for a frame to be transmitted.When this bit is reset the transmission process is placed in the Stopped state after completing the transmission of the current frame.*/
uint32_t tx_thresh_ctrl : 3; /*These bits control the threshold level of the MTL Transmit FIFO. Transmission starts when the frame size within the MTL Transmit FIFO is larger than the threshold. In addition full frames with a length less than the threshold are also transmitted. These bits are used only when Tx_Str_fwd is reset. 3'b000: 64 3'b001: 128 3'b010: 192 3'b011: 256 3'b100: 40 3'b101: 32 3'b110: 24 3'b111: 16 .*/
uint32_t reserved17 : 3;
uint32_t flush_tx_fifo : 1; /*When this bit is set the transmit FIFO controller logic is reset to its default values and thus all data in the Tx FIFO is lost or flushed. This bit is cleared internally when the flushing operation is complete.*/
uint32_t tx_str_fwd : 1; /*When this bit is set transmission starts when a full frame resides in the MTL Transmit FIFO. When this bit is set the Tx_Thresh_Ctrl values specified in Tx_Thresh_Ctrl are ignored.*/
uint32_t reserved22 : 1;
uint32_t reserved23 : 1;
uint32_t dis_flush_recv_frames : 1; /*When this bit is set the Rx DMA does not flush any frames because of the unavailability of receive descriptors or buffers.*/
uint32_t rx_store_forward : 1; /*When this bit is set the MTL reads a frame from the Rx FIFO only after the complete frame has been written to it.*/
uint32_t dis_drop_tcpip_err_fram : 1; /*When this bit is set the MAC does not drop the frames which only have errors detected by the Receive Checksum engine.When this bit is reset all error frames are dropped if the Fwd_Err_Frame bit is reset.*/
uint32_t reserved27 : 5;
};
uint32_t val;
} dmaoperation_mode;
union {
struct {
uint32_t dmain_tie : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit[16]) the Transmit Interrupt is enabled. When this bit is reset the Transmit Interrupt is disabled.*/
uint32_t dmain_tse : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Transmission Stopped Interrupt is enabled. When this bit is reset the Transmission Stopped Interrupt is disabled.*/
uint32_t dmain_tbue : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit 16) the Transmit Buffer Unavailable Interrupt is enabled. When this bit is reset the Transmit Buffer Unavailable Interrupt is Disabled.*/
uint32_t dmain_tjte : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Transmit Jabber Timeout Interrupt is enabled. When this bit is reset the Transmit Jabber Timeout Interrupt is disabled.*/
uint32_t dmain_oie : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Overflow Interrupt is enabled. When this bit is reset the Overflow Interrupt is disabled.*/
uint32_t dmain_uie : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Transmit Underflow Interrupt is enabled. When this bit is reset the Underflow Interrupt is disabled.*/
uint32_t dmain_rie : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit[16]) the Receive Interrupt is enabled. When this bit is reset the Receive Interrupt is disabled.*/
uint32_t dmain_rbue : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Buffer Unavailable Interrupt is enabled. When this bit is reset the Receive Buffer Unavailable Interrupt is disabled.*/
uint32_t dmain_rse : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Stopped Interrupt is enabled. When this bit is reset the Receive Stopped Interrupt is disabled.*/
uint32_t dmain_rwte : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Watchdog Timeout Interrupt is enabled. When this bit is reset the Receive Watchdog Timeout Interrupt is disabled.*/
uint32_t dmain_etie : 1; /*When this bit is set with an Abnormal Interrupt Summary Enable (Bit[15]) the Early Transmit Interrupt is enabled. When this bit is reset the Early Transmit Interrupt is disabled.*/
uint32_t reserved11 : 2;
uint32_t dmain_fbee : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Fatal Bus Error Interrupt is enabled. When this bit is reset the Fatal Bus Error Enable Interrupt is disabled.*/
uint32_t dmain_erie : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit[16]) the Early Receive Interrupt is enabled. When this bit is reset the Early Receive Interrupt is disabled.*/
uint32_t dmain_aise : 1; /*When this bit is set abnormal interrupt summary is enabled. When this bit is reset the abnormal interrupt summary is disabled. This bit enables the following interrupts in Status Register: Bit[1]: Transmit Process Stopped. Bit[3]: Transmit Jabber Timeout. Bit[4]: Receive Overflow. Bit[5]: Transmit Underflow. Bit[7]: Receive Buffer Unavailable. Bit[8]: Receive Process Stopped. Bit[9]: Receive Watchdog Timeout. Bit[10]: Early Transmit Interrupt. Bit[13]: Fatal Bus Error.*/
uint32_t dmain_nise : 1; /*When this bit is set normal interrupt summary is enabled. When this bit is reset normal interrupt summary is disabled. This bit enables the following interrupts in Status Register: Bit[0]: Transmit Interrupt. Bit[2]: Transmit Buffer Unavailable. Bit[6]: Receive Interrupt. Bit[14]: Early Receive Interrupt.*/
uint32_t reserved17 : 15;
};
uint32_t val;
} dmain_en;
union {
struct {
uint32_t missed_fc : 16; /*This field indicates the number of frames missed by the controller because of the Host Receive Buffer being unavailable. This counter is incremented each time the DMA discards an incoming frame. The counter is cleared when this register is read.*/
uint32_t overflow_bmfc : 1; /*This bit is set every time Missed Frame Counter (Bits[15:0]) overflows that is the DMA discards an incoming frame because of the Host Receive Buffer being unavailable with the missed frame counter at maximum value. In such a scenario the Missed frame counter is reset to all-zeros and this bit indicates that the rollover happened.*/
uint32_t overflow_fc : 11; /*This field indicates the number of frames missed by the application. This counter is incremented each time the MTL FIFO overflows. The counter is cleared when this register is read.*/
uint32_t overflow_bfoc : 1; /*This bit is set every time the Overflow Frame Counter (Bits[27:17]) overflows that is the Rx FIFO overflows with the overflow frame counter at maximum value. In such a scenario the overflow frame counter is reset to all-zeros and this bit indicates that the rollover happened.*/
uint32_t reserved29 : 3;
};
uint32_t val;
} dmamissedfr;
union {
struct {
uint32_t riwtc : 8; /*This bit indicates the number of system clock cycles multiplied by 256 for which the watchdog timer is set. The watchdog timer gets triggered with the programmed value after the Rx DMA completes the transfer of a frame for which the RI(RECV_INT) status bit is not set because of the setting in the corresponding descriptor RDES1[31]. When the watchdog timer runs out the RI bit is set and the timer is stopped. The watchdog timer is reset when the RI bit is set high because of automatic setting of RI as per RDES1[31] of any received frame.*/
uint32_t reserved8 : 24;
};
uint32_t val;
} dmarintwdtimer;
uint32_t reserved_28;
uint32_t reserved_2c;
uint32_t reserved_30;
uint32_t reserved_34;
uint32_t reserved_38;
uint32_t reserved_3c;
uint32_t reserved_40;
uint32_t reserved_44;
uint32_t dmatxcurrdesc; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/
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.*/
} emac_dma_dev_t;
extern emac_dma_dev_t EMAC_DMA;
#ifdef __cplusplus
}
#endif

View file

@ -1,161 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _EMAC_EX_H_
#define _EMAC_EX_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "soc.h"
#define REG_EMAC_EX_BASE (DR_REG_EMAC_BASE + 0x800)
#define EMAC_EX_CLKOUT_CONF_REG (REG_EMAC_EX_BASE + 0x0000)
#define EMAC_EX_CLK_OUT_DLY_NUM 0x00000003
#define EMAC_EX_CLK_OUT_DLY_NUM_M (EMAC_EX_CLK_OUT_DLY_NUM_V << EMAC_EX_CLK_OUT_DLY_NUM_S)
#define EMAC_EX_CLK_OUT_DLY_NUM_V 0x00000003
#define EMAC_EX_CLK_OUT_DLY_NUM_S 8
#define EMAC_EX_CLK_OUT_H_DIV_NUM 0x0000000F
#define EMAC_EX_CLK_OUT_H_DIV_NUM_M (EMAC_EX_CLK_OUT_H_DIV_NUM_V << EMAC_EX_CLK_OUT_H_DIV_NUM_S)
#define EMAC_EX_CLK_OUT_H_DIV_NUM_V 0x0000000F
#define EMAC_EX_CLK_OUT_H_DIV_NUM_S 4
#define EMAC_EX_CLK_OUT_DIV_NUM 0x0000000F
#define EMAC_EX_CLK_OUT_DIV_NUM_M (EMAC_EX_CLK_OUT_DIV_NUM_V << EMAC_EX_CLK_OUT_DIV_NUM_S)
#define EMAC_EX_CLK_OUT_DIV_NUM_V 0x0000000F
#define EMAC_EX_CLK_OUT_DIV_NUM_S 0
#define EMAC_EX_OSCCLK_CONF_REG (REG_EMAC_EX_BASE + 0x0004)
#define EMAC_EX_OSC_CLK_SEL (BIT(24))
#define EMAC_EX_OSC_CLK_SEL_M (BIT(24))
#define EMAC_EX_OSC_CLK_SEL_V 1
#define EMAC_EX_OSC_CLK_SEL_S 24
#define EMAC_EX_OSC_H_DIV_NUM_100M 0x0000003F
#define EMAC_EX_OSC_H_DIV_NUM_100M_M (EMAC_EX_OSC_H_DIV_NUM_100M_V << EMAC_EX_OSC_H_DIV_NUM_100M_S)
#define EMAC_EX_OSC_H_DIV_NUM_100M_V 0x0000003F
#define EMAC_EX_OSC_H_DIV_NUM_100M_S 18
#define EMAC_EX_OSC_DIV_NUM_100M 0x0000003F
#define EMAC_EX_OSC_DIV_NUM_100M_M (EMAC_EX_OSC_DIV_NUM_100M_V << EMAC_EX_OSC_DIV_NUM_100M_S)
#define EMAC_EX_OSC_DIV_NUM_100M_V 0x0000003F
#define EMAC_EX_OSC_DIV_NUM_100M_S 12
#define EMAC_EX_OSC_H_DIV_NUM_10M 0x0000003F
#define EMAC_EX_OSC_H_DIV_NUM_10M_M (EMAC_EX_OSC_H_DIV_NUM_10M_V << EMAC_EX_OSC_H_DIV_NUM_10M_S)
#define EMAC_EX_OSC_H_DIV_NUM_10M_V 0x0000003F
#define EMAC_EX_OSC_H_DIV_NUM_10M_S 6
#define EMAC_EX_OSC_DIV_NUM_10M 0x0000003F
#define EMAC_EX_OSC_DIV_NUM_10M_M (EMAC_EX_OSC_DIV_NUM_10M_V << EMAC_EX_OSC_DIV_NUM_10M_S)
#define EMAC_EX_OSC_DIV_NUM_10M_V 0x0000003F
#define EMAC_EX_OSC_DIV_NUM_10M_S 0
#define EMAC_EX_CLK_CTRL_REG (REG_EMAC_EX_BASE + 0x0008)
#define EMAC_EX_CLK_EN (BIT(5))
#define EMAC_EX_CLK_EN_M (BIT(5))
#define EMAC_EX_CLK_EN_V 1
#define EMAC_EX_CLK_EN_S 5
#define EMAC_EX_MII_CLK_RX_EN (BIT(4))
#define EMAC_EX_MII_CLK_RX_EN_M (BIT(4))
#define EMAC_EX_MII_CLK_RX_EN_V 1
#define EMAC_EX_MII_CLK_RX_EN_S 4
#define EMAC_EX_MII_CLK_TX_EN (BIT(3))
#define EMAC_EX_MII_CLK_TX_EN_M (BIT(3))
#define EMAC_EX_MII_CLK_TX_EN_V 1
#define EMAC_EX_MII_CLK_TX_EN_S 3
#define EMAC_EX_RX_125_CLK_EN (BIT(2))
#define EMAC_EX_RX_125_CLK_EN_M (BIT(2))
#define EMAC_EX_RX_125_CLK_EN_V 1
#define EMAC_EX_RX_125_CLK_EN_S 2
#define EMAC_EX_INT_OSC_EN (BIT(1))
#define EMAC_EX_INT_OSC_EN_M (BIT(1))
#define EMAC_EX_INT_OSC_EN_V 1
#define EMAC_EX_INT_OSC_EN_S 1
#define EMAC_EX_EXT_OSC_EN (BIT(0))
#define EMAC_EX_EXT_OSC_EN_M (BIT(0))
#define EMAC_EX_EXT_OSC_EN_V 1
#define EMAC_EX_EXT_OSC_EN_S 0
#define EMAC_EX_PHYINF_CONF_REG (REG_EMAC_EX_BASE + 0x000c)
#define EMAC_EX_TX_ERR_OUT_EN (BIT(20))
#define EMAC_EX_TX_ERR_OUT_EN_M (BIT(20))
#define EMAC_EX_TX_ERR_OUT_EN_V 1
#define EMAC_EX_TX_ERR_OUT_EN_S 20
#define EMAC_EX_SCR_SMI_DLY_RX_SYNC (BIT(19))
#define EMAC_EX_SCR_SMI_DLY_RX_SYNC_M (BIT(19))
#define EMAC_EX_SCR_SMI_DLY_RX_SYNC_V 1
#define EMAC_EX_SCR_SMI_DLY_RX_SYNC_S 19
#define EMAC_EX_PMT_CTRL_EN (BIT(18))
#define EMAC_EX_PMT_CTRL_EN_M (BIT(18))
#define EMAC_EX_PMT_CTRL_EN_V 1
#define EMAC_EX_PMT_CTRL_EN_S 18
#define EMAC_EX_SBD_CLK_GATING_EN (BIT(17))
#define EMAC_EX_SBD_CLK_GATING_EN_M (BIT(17))
#define EMAC_EX_SBD_CLK_GATING_EN_V 1
#define EMAC_EX_SBD_CLK_GATING_EN_S 17
#define EMAC_EX_SS_MODE (BIT(16))
#define EMAC_EX_SS_MODE_M (BIT(16))
#define EMAC_EX_SS_MODE_V 1
#define EMAC_EX_SS_MODE_S 16
#define EMAC_EX_PHY_INTF_SEL 0x00000007
#define EMAC_EX_PHY_INTF_SEL_M (EMAC_EX_PHY_INTF_SEL_V << EMAC_EX_PHY_INTF_SEL_S)
#define EMAC_EX_PHY_INTF_SEL_V 0x00000007
#define EMAC_EX_PHY_INTF_SEL_S 13
#define EMAC_EX_REVMII_PHY_ADDR 0x0000001F
#define EMAC_EX_REVMII_PHY_ADDR_M (EMAC_EX_REVMII_PHY_ADDR_V << EMAC_EX_REVMII_PHY_ADDR_S)
#define EMAC_EX_REVMII_PHY_ADDR_V 0x0000001F
#define EMAC_EX_REVMII_PHY_ADDR_S 8
#define EMAC_EX_CORE_PHY_ADDR 0x0000001F
#define EMAC_EX_CORE_PHY_ADDR_M (EMAC_EX_CORE_PHY_ADDR_V << EMAC_EX_CORE_PHY_ADDR_S)
#define EMAC_EX_CORE_PHY_ADDR_V 0x0000001F
#define EMAC_EX_CORE_PHY_ADDR_S 3
#define EMAC_EX_SBD_FLOWCTRL (BIT(2))
#define EMAC_EX_SBD_FLOWCTRL_M (BIT(2))
#define EMAC_EX_SBD_FLOWCTRL_V 1
#define EMAC_EX_SBD_FLOWCTRL_S 2
#define EMAC_EX_EXT_REVMII_RX_CLK_SEL (BIT(1))
#define EMAC_EX_EXT_REVMII_RX_CLK_SEL_M (BIT(1))
#define EMAC_EX_EXT_REVMII_RX_CLK_SEL_V 1
#define EMAC_EX_EXT_REVMII_RX_CLK_SEL_S 1
#define EMAC_EX_INT_REVMII_RX_CLK_SEL (BIT(0))
#define EMAC_EX_INT_REVMII_RX_CLK_SEL_M (BIT(0))
#define EMAC_EX_INT_REVMII_RX_CLK_SEL_V 1
#define EMAC_EX_INT_REVMII_RX_CLK_SEL_S 0
#define EMAC_EX_PHY_INTF_RMII 4
#define EMAC_EX_EMAC_PD_SEL_REG (REG_EMAC_EX_BASE + 0x0010)
#define EMAC_EX_RAM_PD_EN 0x00000003
#define EMAC_EX_RAM_PD_EN_M (EMAC_EX_RAM_PD_EN_V << EMAC_EX_RAM_PD_EN_S)
#define EMAC_EX_RAM_PD_EN_V 0x00000003
#define EMAC_EX_RAM_PD_EN_S 0
#define EMAC_EX_DATE_REG (REG_EMAC_EX_BASE + 0x00fc)
#define EMAC_EX_DATE 0xFFFFFFFF
#define EMAC_EX_DATE_M (EMAC_EX_DATE_V << EMAC_EX_DATE_S)
#define EMAC_EX_DATE_V 0xFFFFFFFF
#define EMAC_EX_DATE_S 0
#define EMAC_EX_DATE_VERSION 0x16042200
#define EMAC_EX_DATE_VERSION_M (EMAC_EX_DATE_VERSION_V << EMAC_EX_DATE_VERSION_S)
#define EMAC_EX_DATE_VERSION_V 0x16042200
#define EMAC_CLK_EN_REG 0x3ff000cc
#define EMAC_CLK_EN_REG_M (EMAC_CLK_EN_REG_V << EMAC_CLK_EN_REG_S)
#define EMAC_CLK_EN_REG_V 0x3ff000cc
#define EMAC_CLK_EN (BIT(14))
#define EMAC_CLK_EN_M (BIT(14))
#define EMAC_CLK_EN_V 1
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,74 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef volatile struct {
union {
struct {
uint32_t div_num : 4;
uint32_t h_div_num : 4;
uint32_t reserved8 : 24;
};
uint32_t val;
} ex_clkout_conf;
union {
struct {
uint32_t div_num_10m : 6;
uint32_t h_div_num_10m : 6;
uint32_t div_num_100m : 6;
uint32_t h_div_num_100m : 6;
uint32_t clk_sel : 1;
uint32_t reserved25 : 7;
};
uint32_t val;
} ex_oscclk_conf;
union {
struct {
uint32_t ext_en : 1;
uint32_t int_en : 1;
uint32_t reserved2 : 1;
uint32_t mii_clk_tx_en : 1;
uint32_t mii_clk_rx_en : 1;
uint32_t reserved5 : 27;
};
uint32_t val;
} ex_clk_ctrl;
union {
struct {
uint32_t reserved0 : 13;
uint32_t phy_intf_sel : 3;
uint32_t reserved16 : 16;
};
uint32_t val;
} ex_phyinf_conf;
union {
struct {
uint32_t ram_pd_en : 2;
uint32_t reserved2 : 30;
};
uint32_t val;
} pd_sel;
} emac_ext_dev_t;
extern emac_ext_dev_t EMAC_EXT;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,345 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef volatile struct {
union {
struct {
uint32_t pltf : 2; /*These bits control the number of preamble bytes that are added to the beginning of every Transmit frame. The preamble reduction occurs only when the MAC is operating in the full-duplex mode.2'b00: 7 bytes of preamble. 2'b01: 5 bytes of preamble. 2'b10: 3 bytes of preamble.*/
uint32_t rx : 1; /*When this bit is set the receiver state machine of the MAC is enabled for receiving frames from the MII. When this bit is reset the MAC receive state machine is disabled after the completion of the reception of the current frame and does not receive any further frames from the MII.*/
uint32_t tx : 1; /*When this bit is set the transmit state machine of the MAC is enabled for transmission on the MII. When this bit is reset the MAC transmit state machine is disabled after the completion of the transmission of the current frame and does not transmit any further frames.*/
uint32_t deferralcheck : 1; /*Deferral Check.*/
uint32_t backofflimit : 2; /*The Back-Off limit determines the random integer number (r) of slot time delays (512 bit times for 10/100 Mbps) for which the MAC waits before rescheduling a transmission attempt during retries after a collision. This bit is applicable only in the half-duplex mode. 00: k= min (n 10). 01: k = min (n 8). 10: k = min (n 4). 11: k = min (n 1) n = retransmission attempt. The random integer r takes the value in the Range 0 ~ 2000.*/
uint32_t padcrcstrip : 1; /*When this bit is set the MAC strips the Pad or FCS field on the incoming frames only if the value of the length field is less than 1 536 bytes. All received frames with length field greater than or equal to 1 536 bytes are passed to the application without stripping the Pad or FCS field. When this bit is reset the MAC passes all incoming frames without modifying them to the Host.*/
uint32_t reserved8 : 1;
uint32_t retry : 1; /*When this bit is set the MAC attempts only one transmission. When a collision occurs on the MII interface the MAC ignores the current frame transmission and reports a Frame Abort with excessive collision error in the transmit frame status. When this bit is reset the MAC attempts retries based on the settings of the BL field (Bits [6:5]). This bit is applicable only in the half-duplex Mode.*/
uint32_t rxipcoffload : 1; /*When this bit is set the MAC calculates the 16-bit one's complement of the one's complement sum of all received Ethernet frame payloads. It also checks whether the IPv4 Header checksum (assumed to be bytes 25/26 or 29/30 (VLAN-tagged) of the received Ethernet frame) is correct for the received frame and gives the status in the receive status word. The MAC also appends the 16-bit checksum calculated for the IP header datagram payload (bytes after the IPv4 header) and appends it to the Ethernet frame transferred to the application (when Type 2 COE is deselected). When this bit is reset this function is disabled.*/
uint32_t duplex : 1; /*When this bit is set the MAC operates in the full-duplex mode where it can transmit and receive simultaneously. This bit is read only with default value of 1'b1 in the full-duplex-mode.*/
uint32_t loopback : 1; /*When this bit is set the MAC operates in the loopback mode MII. The MII Receive clock input (CLK_RX) is required for the loopback to work properly because the transmit clock is not looped-back internally.*/
uint32_t rxown : 1; /*When this bit is set the MAC disables the reception of frames when the TX_EN is asserted in the half-duplex mode. When this bit is reset the MAC receives all packets that are given by the PHY while transmitting. This bit is not applicable if the MAC is operating in the full duplex mode.*/
uint32_t fespeed : 1; /*This bit selects the speed in the MII RMII interface. 0: 10 Mbps. 1: 100 Mbps.*/
uint32_t mii : 1; /*This bit selects the Ethernet line speed. It should be set to 1 for 10 or 100 Mbps operations.In 10 or 100 Mbps operations this bit along with FES(EMACFESPEED) bit it selects the exact linespeed. In the 10/100 Mbps-only operations the bit is always 1.*/
uint32_t disablecrs : 1; /*When set high this bit makes the MAC transmitter ignore the MII CRS signal during frame transmission in the half-duplex mode. This request results in no errors generated because of Loss of Carrier or No Carrier during such transmission. When this bit is low the MAC transmitter generates such errors because of Carrier Sense and can even abort the transmissions.*/
uint32_t interframegap : 3; /*These bits control the minimum IFG between frames during transmission. 3'b000: 96 bit times. 3'b001: 88 bit times. 3'b010: 80 bit times. 3'b111: 40 bit times. In the half-duplex mode the minimum IFG can be configured only for 64 bit times (IFG = 100). Lower values are not considered.*/
uint32_t jumboframe : 1; /*When this bit is set the MAC allows Jumbo frames of 9 018 bytes (9 022 bytes for VLAN tagged frames) without reporting a giant frame error in the receive frame status.*/
uint32_t reserved21 : 1;
uint32_t jabber : 1; /*When this bit is set the MAC disables the jabber timer on the transmitter. The MAC can transfer frames of up to 16 383 bytes. When this bit is reset the MAC cuts off the transmitter if the application sends out more than 2 048 bytes of data (10 240 if JE is set high) during Transmission.*/
uint32_t watchdog : 1; /*When this bit is set the MAC disables the watchdog timer on the receiver. The MAC can receive frames of up to 16 383 bytes. When this bit is reset the MAC does not allow a receive frame which more than 2 048 bytes (10 240 if JE is set high) or the value programmed in Register (Watchdog Timeout Register). The MAC cuts off any bytes received after the watchdog limit number of bytes.*/
uint32_t reserved24 : 1;
uint32_t reserved25 : 1;
uint32_t reserved26 : 1;
uint32_t ass2kp : 1; /*When set the MAC considers all frames with up to 2 000 bytes length as normal packets.When Bit[20] (JE) is not set the MAC considers all received frames of size more than 2K bytes as Giant frames. When this bit is reset and Bit[20] (JE) is not set the MAC considers all received frames of size more than 1 518 bytes (1 522 bytes for tagged) as Giant frames. When Bit[20] is set setting this bit has no effect on Giant Frame status.*/
uint32_t sairc : 3; /*This field controls the source address insertion or replacement for all transmitted frames.Bit[30] specifies which MAC Address register (0 or 1) is used for source address insertion or replacement based on the values of Bits [29:28]: 2'b0x: The input signals mti_sa_ctrl_i and ati_sa_ctrl_i control the SA field generation. 2'b10: If Bit[30] is set to 0 the MAC inserts the content of the MAC Address 0 registers in the SA field of all transmitted frames. If Bit[30] is set to 1 the MAC inserts the content of the MAC Address 1 registers in the SA field of all transmitted frames. 2'b11: If Bit[30] is set to 0 the MAC replaces the content of the MAC Address 0 registers in the SA field of all transmitted frames. If Bit[30] is set to 1 the MAC replaces the content of the MAC Address 1 registers in the SA field of all transmitted frames.*/
uint32_t reserved31 : 1;
};
uint32_t val;
} gmacconfig;
union {
struct {
uint32_t pmode : 1; /*When this bit is set the Address Filter module passes all incoming frames irrespective of the destination or source address. The SA or DA Filter Fails status bits of the Receive Status Word are always cleared when PR(PRI_RATIO) is set.*/
uint32_t reserved1 : 1;
uint32_t reserved2 : 1;
uint32_t daif : 1; /*When this bit is set the Address Check block operates in inverse filtering mode for the DA address comparison for both unicast and multicast frames. When reset normal filtering of frames is performed.*/
uint32_t pam : 1; /*When set this bit indicates that all received frames with a multicast destination address (first bit in the destination address field is '1') are passed.*/
uint32_t dbf : 1; /*When this bit is set the AFM(Address Filtering Module) module blocks all incoming broadcast frames. In addition it overrides all other filter settings. When this bit is reset the AFM module passes all received broadcast Frames.*/
uint32_t pcf : 2; /*These bits control the forwarding of all control frames (including unicast and multicast Pause frames). 2'b00: MAC filters all control frames from reaching the application. 2'b01: MAC forwards all control frames except Pause frames to application even if they fail the Address filter. 2'b10: MAC forwards all control frames to application even if they fail the Address Filter. 2'b11: MAC forwards control frames that pass the Address Filter.The following conditions should be true for the Pause frames processing: Condition 1: The MAC is in the full-duplex mode and flow control is enabled by setting Bit 2 (RFE) of Register (Flow Control Register) to 1. Condition 2: The destination address (DA) of the received frame matches the special multicast address or the MAC Address 0 when Bit 3 (UP) of the Register(Flow Control Register) is set. Condition 3: The Type field of the received frame is 0x8808 and the OPCODE field is 0x0001.*/
uint32_t saif : 1; /*When this bit is set the Address Check block operates in inverse filtering mode for the SA address comparison. The frames whose SA matches the SA registers are marked as failing the SA Address filter. When this bit is reset frames whose SA does not match the SA registers are marked as failing the SA Address filter.*/
uint32_t safe : 1; /*When this bit is set the MAC compares the SA field of the received frames with the values programmed in the enabled SA registers. If the comparison fails the MAC drops the frame. When this bit is reset the MAC forwards the received frame to the application with updated SAF bit of the Rx Status depending on the SA address comparison.*/
uint32_t reserved10 : 1;
uint32_t reserved11 : 5;
uint32_t reserved16 : 1;
uint32_t reserved17 : 3;
uint32_t reserved20 : 1;
uint32_t reserved21 : 1;
uint32_t reserved22 : 9;
uint32_t receive_all : 1; /*When this bit is set the MAC Receiver module passes all received frames irrespective of whether they pass the address filter or not to the Application. The result of the SA or DA filtering is updated (pass or fail) in the corresponding bits in the Receive Status Word. When this bit is reset the Receiver module passes only those frames to the Application that pass the SA or DA address Filter.*/
};
uint32_t val;
} gmacff;
uint32_t reserved_1008;
uint32_t reserved_100c;
union {
struct {
uint32_t miibusy : 1; /*This bit should read logic 0 before writing to PHY Addr Register and PHY data Register.During a PHY register access the software sets this bit to 1'b1 to indicate that a Read or Write access is in progress. PHY data Register is invalid until this bit is cleared by the MAC. Therefore PHY data Register (MII Data) should be kept valid until the MAC clears this bit during a PHY Write operation. Similarly for a read operation the contents of Register 5 are not valid until this bit is cleared. The subsequent read or write operation should happen only after the previous operation is complete. Because there is no acknowledgment from the PHY to MAC after a read or write operation is completed there is no change in the functionality of this bit even when the PHY is not Present.*/
uint32_t miiwrite : 1; /*When set this bit indicates to the PHY that this is a Write operation using the MII Data register. If this bit is not set it indicates that this is a Read operation that is placing the data in the MII Data register.*/
uint32_t miicsrclk : 4; /*CSR clock range: 1.0 MHz ~ 2.5 MHz. 4'b0000: When the APB clock frequency is 80 MHz the MDC clock frequency is APB CLK/42 4'b0000: When the APB clock frequency is 40 MHz the MDC clock frequency is APB CLK/26.*/
uint32_t miireg : 5; /*These bits select the desired MII register in the selected PHY device.*/
uint32_t miidev : 5; /*This field indicates which of the 32 possible PHY devices are being accessed.*/
uint32_t reserved16 : 16;
};
uint32_t val;
} emacgmiiaddr;
union {
struct {
uint32_t mii_data : 16; /*This field contains the 16-bit data value read from the PHY after a Management Read operation or the 16-bit data value to be written to the PHY before a Management Write operation.*/
uint32_t reserved16 : 16;
};
uint32_t val;
} emacmiidata;
union {
struct {
uint32_t fcbba : 1; /*This bit initiates a Pause frame in the full-duplex mode and activates the backpressure function in the half-duplex mode if the TFCE bit is set. In the full-duplex mode this bit should be read as 1'b0 before writing to the Flow Control register. To initiate a Pause frame the Application must set this bit to 1'b1. During a transfer of the Control Frame this bit continues to be set to signify that a frame transmission is in progress. After the completion of Pause frame transmission the MAC resets this bit to 1'b0. The Flow Control register should not be written to until this bit is cleared. In the half-duplex mode when this bit is set (and TFCE is set) then backpressure is asserted by the MAC. During backpressure when the MAC receives a new frame the transmitter starts sending a JAM pattern resulting in a collision. When the MAC is configured for the full-duplex mode the BPA(backpressure activate) is automatically disabled.*/
uint32_t tfce : 1; /*In the full-duplex mode when this bit is set the MAC enables the flow control operation to transmit Pause frames. When this bit is reset the flow control operation in the MAC is disabled and the MAC does not transmit any Pause frames. In the half-duplex mode when this bit is set the MAC enables the backpressure operation. When this bit is reset the backpressure feature is Disabled.*/
uint32_t rfce : 1; /*When this bit is set the MAC decodes the received Pause frame and disables its transmitter for a specified (Pause) time. When this bit is reset the decode function of the Pause frame is disabled.*/
uint32_t upfd : 1; /*A pause frame is processed when it has the unique multicast address specified in the IEEE Std 802.3. When this bit is set the MAC can also detect Pause frames with unicast address of the station. This unicast address should be as specified in the EMACADDR0 High Register and EMACADDR0 Low Register. When this bit is reset the MAC only detects Pause frames with unique multicast address.*/
uint32_t plt : 2; /*This field configures the threshold of the Pause timer automatic retransmission of the Pause frame.The threshold values should be always less than the Pause Time configured in Bits[31:16]. For example if PT = 100H (256 slot-times) and PLT = 01 then a second Pause frame is automatically transmitted at 228 (256-28) slot times after the first Pause frame is transmitted. The following list provides the threshold values for different values: 2'b00: The threshold is Pause time minus 4 slot times (PT-4 slot times). 2'b01: The threshold is Pause time minus 28 slot times (PT-28 slot times). 2'b10: The threshold is Pause time minus 144 slot times (PT-144 slot times). 2'b11: The threshold is Pause time minus 256 slot times (PT-256 slot times). The slot time is defined as the time taken to transmit 512 bits (64 bytes) on the MII interface.*/
uint32_t reserved6 : 1;
uint32_t dzpq : 1; /*When this bit is set it disables the automatic generation of the Zero-Quanta Pause frames on the de-assertion of the flow-control signal from the FIFO layer. When this bit is reset normal operation with automatic Zero-Quanta Pause frame generation is enabled.*/
uint32_t reserved8 : 8;
uint32_t pause_time : 16; /*This field holds the value to be used in the Pause Time field in the transmit control frame. If the Pause Time bits is configured to be double-synchronized to the MII clock domain then consecutive writes to this register should be performed only after at least four clock cycles in the destination clock domain.*/
};
uint32_t val;
} gmacfc;
uint32_t reserved_101c;
uint32_t reserved_1020;
union {
struct {
uint32_t macrpes : 1; /*When high this bit indicates that the MAC MII receive protocol engine is actively receiving data and not in IDLE state.*/
uint32_t macrffcs : 2; /*When high this field indicates the active state of the FIFO Read and Write controllers of the MAC Receive Frame Controller Module. MACRFFCS[1] represents the status of FIFO Read controller. MACRFFCS[0] represents the status of small FIFO Write controller.*/
uint32_t reserved3 : 1;
uint32_t mtlrfwcas : 1; /*When high this bit indicates that the MTL Rx FIFO Write Controller is active and is transferring a received frame to the FIFO.*/
uint32_t mtlrfrcs : 2; /*This field gives the state of the Rx FIFO read Controller: 2'b00: IDLE state.2'b01: Reading frame data.2'b10: Reading frame status (or timestamp).2'b11: Flushing the frame data and status.*/
uint32_t reserved7 : 1;
uint32_t mtlrffls : 2; /*This field gives the status of the fill-level of the Rx FIFO: 2'b00: Rx FIFO Empty. 2'b01: Rx FIFO fill-level below flow-control deactivate threshold. 2'b10: Rx FIFO fill-level above flow-control activate threshold. 2'b11: Rx FIFO Full.*/
uint32_t reserved10 : 6;
uint32_t mactpes : 1; /*When high this bit indicates that the MAC MII transmit protocol engine is actively transmitting data and is not in the IDLE state.*/
uint32_t mactfcs : 2; /*This field indicates the state of the MAC Transmit Frame Controller module: 2'b00: IDLE state. 2'b01: Waiting for status of previous frame or IFG or backoff period to be over. 2'b10: Generating and transmitting a Pause frame (in the full-duplex mode). 2'b11: Transferring input frame for transmission.*/
uint32_t mactp : 1; /*When high this bit indicates that the MAC transmitter is in the Pause condition (in the full-duplex-mode) and hence does not schedule any frame for transmission.*/
uint32_t mtltfrcs : 2; /*This field indicates the state of the Tx FIFO Read Controller: 2'b00: IDLE state. 2'b01: READ state (transferring data to the MAC transmitter). 2'b10: Waiting for TxStatus from the MAC transmitter. 2'b11: Writing the received TxStatus or flushing the Tx FIFO.*/
uint32_t mtltfwcs : 1; /*When high this bit indicates that the MTL Tx FIFO Write Controller is active and is transferring data to the Tx FIFO.*/
uint32_t reserved23 : 1;
uint32_t mtltfnes : 1; /*When high this bit indicates that the MTL Tx FIFO is not empty and some data is left for Transmission.*/
uint32_t mtltsffs : 1; /*When high this bit indicates that the MTL TxStatus FIFO is full. Therefore the MTL cannot accept any more frames for transmission.*/
uint32_t reserved26 : 6;
};
uint32_t val;
} emacdebug;
uint32_t pmt_rwuffr; /*The MSB (31st bit) must be zero.Bit j[30:0] is the byte mask. If Bit 1/2/3/4 (byte number) of the byte mask is set the CRC block processes the Filter 1/2/3/4 Offset + j of the incoming packet(PWKPTR is 0/1/2/3).RWKPTR is 0:Filter 0 Byte Mask .RWKPTR is 1:Filter 1 Byte Mask RWKPTR is 2:Filter 2 Byte Mask RWKPTR is 3:Filter 3 Byte Mask RWKPTR is 4:Bit 3/11/19/27 specifies the address type defining the destination address type of the pattern.When the bit is set the pattern applies to only multicast packets*/
union {
struct {
uint32_t pwrdwn : 1; /*When set the MAC receiver drops all received frames until it receives the expected magic packet or remote wake-up frame.This bit must only be set when MGKPKTEN GLBLUCAST or RWKPKTEN bit is set high.*/
uint32_t mgkpkten : 1; /*When set enables generation of a power management event because of magic packet reception.*/
uint32_t rwkpkten : 1; /*When set enables generation of a power management event because of remote wake-up frame reception*/
uint32_t reserved3 : 2;
uint32_t mgkprcvd : 1; /*When set this bit indicates that the power management event is generated because of the reception of a magic packet. This bit is cleared by a Read into this register.*/
uint32_t rwkprcvd : 1; /*When set this bit indicates the power management event is generated because of the reception of a remote wake-up frame. This bit is cleared by a Read into this register.*/
uint32_t reserved7 : 2;
uint32_t glblucast : 1; /*When set enables any unicast packet filtered by the MAC (DAFilter) address recognition to be a remote wake-up frame.*/
uint32_t reserved10 : 14;
uint32_t rwkptr : 5; /*The maximum value of the pointer is 7 the detail information please refer to PMT_RWUFFR.*/
uint32_t reserved29 : 2;
uint32_t rwkfiltrst : 1; /*When this bit is set it resets the RWKPTR register to 3b000.*/
};
uint32_t val;
} pmt_csr;
union {
struct {
uint32_t tlpien : 1; /*When set this bit indicates that the MAC Transmitter has entered the LPI state because of the setting of the LPIEN bit. This bit is cleared by a read into this register.*/
uint32_t tlpiex : 1; /*When set this bit indicates that the MAC transmitter has exited the LPI state after the user has cleared the LPIEN bit and the LPI_TW_Timer has expired.This bit is cleared by a read into this register.*/
uint32_t rlpien : 1; /*When set this bit indicates that the MAC Receiver has received an LPI pattern and entered the LPI state. This bit is cleared by a read into this register.*/
uint32_t rlpiex : 1; /*When set this bit indicates that the MAC Receiver has stopped receiving the LPI pattern on the MII interface exited the LPI state and resumed the normal reception. This bit is cleared by a read into this register.*/
uint32_t reserved4 : 4;
uint32_t tlpist : 1; /*When set this bit indicates that the MAC is transmitting the LPI pattern on the MII interface.*/
uint32_t rlpist : 1; /*When set this bit indicates that the MAC is receiving the LPI pattern on the MII interface.*/
uint32_t reserved10 : 6;
uint32_t lpien : 1; /*When set this bit instructs the MAC Transmitter to enter the LPI state. When reset this bit instructs the MAC to exit the LPI state and resume normal transmission.This bit is cleared when the LPITXA bit is set and the MAC exits the LPI state because of the arrival of a new packet for transmission.*/
uint32_t pls : 1; /*This bit indicates the link status of the PHY.When set the link is considered to be okay (up) and when reset the link is considered to be down.*/
uint32_t reserved18 : 1;
uint32_t lpitxa : 1; /*This bit controls the behavior of the MAC when it is entering or coming out of the LPI mode on the transmit side.If the LPITXA and LPIEN bits are set to 1 the MAC enters the LPI mode only after all outstanding frames and pending frames have been transmitted. The MAC comes out of the LPI mode when the application sends any frame.When this bit is 0 the LPIEN bit directly controls behavior of the MAC when it is entering or coming out of the LPI mode.*/
uint32_t reserved20 : 12;
};
uint32_t val;
} gmaclpi_crs;
union {
struct {
uint32_t lpi_tw_timer : 16; /*This field specifies the minimum time (in microseconds) for which the MAC waits after it stops transmitting the LPI pattern to the PHY and before it resumes the normal transmission. The TLPIEX status bit is set after the expiry of this timer.*/
uint32_t lpi_ls_timer : 10; /*This field specifies the minimum time (in milliseconds) for which the link status from the PHY should be up (OKAY) before the LPI pattern can be transmitted to the PHY. The MAC does not transmit the LPI pattern even when the LPIEN bit is set unless the LPI_LS_Timer reaches the programmed terminal count. The default value of the LPI_LS_Timer is 1000 (1 sec) as defined in the IEEE standard.*/
uint32_t reserved26 : 6;
};
uint32_t val;
} gmaclpitimerscontrol;
union {
struct {
uint32_t reserved0 : 1;
uint32_t reserved1 : 1;
uint32_t reserved2 : 1;
uint32_t pmtints : 1; /*This bit is set when a magic packet or remote wake-up frame is received in the power-down mode (see Bit[5] and Bit[6] in the PMT Control and Status Register). This bit is cleared when both Bits[6:5] are cleared because of a read operation to the PMT Control and Status register. This bit is valid only when you select the optional PMT module during core configuration.*/
uint32_t reserved4 : 1;
uint32_t reserved5 : 1;
uint32_t reserved6 : 1;
uint32_t reserved7 : 1;
uint32_t reserved8 : 1;
uint32_t reserved9 : 1;
uint32_t lpiis : 1; /*When the Energy Efficient Ethernet feature is enabled this bit is set for any LPI state entry or exit in the MAC Transmitter or Receiver. This bit is cleared on reading Bit[0] of Register (LPI Control and Status Register).*/
uint32_t reserved11 : 1;
uint32_t reserved12 : 20;
};
uint32_t val;
} emacints;
union {
struct {
uint32_t reserved0 : 1;
uint32_t reserved1 : 1;
uint32_t reserved2 : 1;
uint32_t pmtintmask : 1; /*When set this bit disables the assertion of the interrupt signal because of the setting of PMT Interrupt Status bit in Register (Interrupt Status Register).*/
uint32_t reserved4 : 5;
uint32_t reserved9 : 1;
uint32_t lpiintmask : 1; /*When set this bit disables the assertion of the interrupt signal because of the setting of the LPI Interrupt Status bit in Register (Interrupt Status Register).*/
uint32_t reserved11 : 21;
};
uint32_t val;
} emacintmask;
union {
struct {
uint32_t address0_hi : 16; /*This field contains the upper 16 bits (47:32) of the first 6-byte MAC address.The MAC uses this field for filtering the received frames and inserting the MAC address in the Transmit Flow Control (Pause) Frames.*/
uint32_t reserved16 : 15;
uint32_t address_enable0 : 1; /*This bit is always set to 1.*/
};
uint32_t val;
} emacaddr0high;
uint32_t emacaddr0low; /*This field contains the lower 32 bits of the first 6-byte MAC address. This is used by the MAC for filtering the received frames and inserting the MAC address in the Transmit Flow Control (Pause) Frames.*/
union {
struct {
uint32_t mac_address1_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the second 6-byte MAC Address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control : 6; /*These bits are mask control bits for comparison of each of the EMACADDR1 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR1 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR1 High [15:8]. Bit[28]: EMACADDR1 High [7:0]. Bit[27]: EMACADDR1 Low [31:24]. Bit[24]: EMACADDR1 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address : 1; /*When this bit is set the EMACADDR1[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR1[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable1 : 1; /*When this bit is set the address filter module uses the second MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr1high;
uint32_t emacaddr1low; /*This field contains the lower 32 bits of the second 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/
union {
struct {
uint32_t mac_address2_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the third 6-byte MAC address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control2 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR2 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR2 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR2 High [15:8]. Bit[28]: EMACADDR2 High [7:0]. Bit[27]: EMACADDR2 Low [31:24]. Bit[24]: EMACADDR2 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address2 : 1; /*When this bit is set the EMACADDR2[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR2[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable2 : 1; /*When this bit is set the address filter module uses the third MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr2high;
uint32_t emacaddr2low; /*This field contains the lower 32 bits of the third 6-byte MAC address. The content of this field is undefined so the register needs to be configured after the initialization process.*/
union {
struct {
uint32_t mac_address3_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the fourth 6-byte MAC address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control3 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR3 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR3 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR3 High [15:8]. Bit[28]: EMACADDR3 High [7:0]. Bit[27]: EMACADDR3 Low [31:24]. Bit[24]: EMACADDR3 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address3 : 1; /*When this bit is set the EMACADDR3[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR3[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable3 : 1; /*When this bit is set the address filter module uses the fourth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr3high;
uint32_t emacaddr3low; /*This field contains the lower 32 bits of the fourth 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/
union {
struct {
uint32_t mac_address4_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the fifth 6-byte MAC address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control4 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR4 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR4 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR4 High [15:8]. Bit[28]: EMACADDR4 High [7:0]. Bit[27]: EMACADDR4 Low [31:24]. Bit[24]: EMACADDR4 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address4 : 1; /*When this bit is set the EMACADDR4[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR4[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable4 : 1; /*When this bit is set the address filter module uses the fifth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr4high;
uint32_t emacaddr4low; /*This field contains the lower 32 bits of the fifth 6-byte MAC address. The content of this field is undefined so the register needs to be configured after the initialization process.*/
union {
struct {
uint32_t mac_address5_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the sixth 6-byte MAC address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control5 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR5 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR5 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR5 High [15:8]. Bit[28]: EMACADDR5 High [7:0]. Bit[27]: EMACADDR5 Low [31:24]. Bit[24]: EMACADDR5 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address5 : 1; /*When this bit is set the EMACADDR5[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR5[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable5 : 1; /*When this bit is set the address filter module uses the sixth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr5high;
uint32_t emacaddr5low; /*This field contains the lower 32 bits of the sixth 6-byte MAC address. The content of this field is undefined so the register needs to be configured after the initialization process.*/
union {
struct {
uint32_t mac_address6_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the seventh 6-byte MAC Address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control6 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR6 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR6 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR6 High [15:8]. Bit[28]: EMACADDR6 High [7:0]. Bit[27]: EMACADDR6 Low [31:24]. Bit[24]: EMACADDR6 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address6 : 1; /*When this bit is set the EMACADDR6[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR6[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable6 : 1; /*When this bit is set the address filter module uses the seventh MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr6high;
uint32_t emacaddr6low; /*This field contains the lower 32 bits of the seventh 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/
union {
struct {
uint32_t mac_address7_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the eighth 6-byte MAC Address.*/
uint32_t reserved16 : 8;
uint32_t mask_byte_control7 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR7 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR7 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR7 High [15:8]. Bit[28]: EMACADDR7 High [7:0]. Bit[27]: EMACADDR7 Low [31:24]. Bit[24]: EMACADDR7 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/
uint32_t source_address7 : 1; /*When this bit is set the EMACADDR7[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR7[47:0] is used to compare with the DA fields of the received frame.*/
uint32_t address_enable7 : 1; /*When this bit is set the address filter module uses the eighth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/
};
uint32_t val;
} emacaddr7high;
uint32_t emacaddr7low; /*This field contains the lower 32 bits of the eighth 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/
uint32_t reserved_1080;
uint32_t reserved_1084;
uint32_t reserved_1088;
uint32_t reserved_108c;
uint32_t reserved_1090;
uint32_t reserved_1094;
uint32_t reserved_1098;
uint32_t reserved_109c;
uint32_t reserved_10a0;
uint32_t reserved_10a4;
uint32_t reserved_10a8;
uint32_t reserved_10ac;
uint32_t reserved_10b0;
uint32_t reserved_10b4;
uint32_t reserved_10b8;
uint32_t reserved_10bc;
uint32_t reserved_10c0;
uint32_t reserved_10c4;
uint32_t reserved_10c8;
uint32_t reserved_10cc;
uint32_t reserved_10d0;
uint32_t reserved_10d4;
union {
struct {
uint32_t link_mode : 1; /*This bit indicates the current mode of operation of the link: 1'b0: Half-duplex mode. 1'b1: Full-duplex mode.*/
uint32_t link_speed : 2; /*This bit indicates the current speed of the link: 2'b00: 2.5 MHz. 2'b01: 25 MHz. 2'b10: 125 MHz.*/
uint32_t reserved3 : 1;
uint32_t jabber_timeout : 1; /*This bit indicates whether there is jabber timeout error (1'b1) in the received Frame.*/
uint32_t reserved5 : 1;
uint32_t reserved6 : 10;
uint32_t reserved16 : 1;
uint32_t reserved17 : 15;
};
uint32_t val;
} emaccstatus;
union {
struct {
uint32_t wdogto : 14; /*When Bit[16] (PWE) is set and Bit[23] (WD) of EMACCONFIG_REG is reset this field is used as watchdog timeout for a received frame. If the length of a received frame exceeds the value of this field such frame is terminated and declared as an error frame.*/
uint32_t reserved14 : 2;
uint32_t pwdogen : 1; /*When this bit is set and Bit[23] (WD) of EMACCONFIG_REG is reset the WTO field (Bits[13:0]) is used as watchdog timeout for a received frame. When this bit is cleared the watchdog timeout for a received frame is controlled by the setting of Bit[23] (WD) and Bit[20] (JE) in EMACCONFIG_REG.*/
uint32_t reserved17 : 15;
};
uint32_t val;
} emacwdogto;
} emac_mac_dev_t;
extern emac_mac_dev_t EMAC_MAC;
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,10 @@ set(SOC_SRCS "cpu_util.c"
"soc_memory_layout.c"
"spi_periph.c")
if(NOT BOOTLOADER_BUILD)
list(APPEND SOC_SRCS "emac_hal.c")
endif()
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
set_source_files_properties("esp32/rtc_clk.c" PROPERTIES
COMPILE_FLAGS "-fno-jump-tables -fno-tree-switch-conversion")

View file

@ -14,4 +14,9 @@ entries:
spi_slave_hal_iram (noflash_text)
spi_flash_hal_iram (noflash)
lldesc (noflash_text)
emac_hal:emac_hal_isr (noflash_text)
emac_hal:emac_hal_tx_complete_cb (noflash_text)
emac_hal:emac_hal_tx_unavail_cb (noflash_text)
emac_hal:emac_hal_rx_complete_cb (noflash_text)
emac_hal:emac_hal_rx_early_cb (noflash_text)
emac_hal:emac_hal_rx_unavail_cb (noflash_text)

View file

@ -1,3 +1,3 @@
idf_component_register(SRCS "event_handlers.c" "tcpip_adapter_lwip.c"
INCLUDE_DIRS include
REQUIRES lwip ethernet)
REQUIRES lwip esp_eth)

View file

@ -52,10 +52,10 @@ static void handle_eth_start(void *arg, esp_event_base_t base, int32_t event_id,
{
tcpip_adapter_ip_info_t eth_ip;
uint8_t eth_mac[6];
esp_eth_get_mac(eth_mac);
esp_eth_handle_t eth_handle = *(esp_eth_handle_t*)data;
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, eth_mac);
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &eth_ip);
tcpip_adapter_eth_start(eth_mac, &eth_ip);
tcpip_adapter_eth_start(eth_mac, &eth_ip, eth_handle);
}
static void handle_eth_stop(void *arg, esp_event_base_t base, int32_t event_id, void *data)

View file

@ -189,13 +189,14 @@ void tcpip_adapter_init(void);
*
* @param[in] mac Set MAC address of this interface
* @param[in] ip_info Set IP address of this interface
* @param[in] args extra args passed to tcpip_adapter
*
* @return
* - ESP_OK
* - ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS
* - ESP_ERR_NO_MEM
*/
esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info);
esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args);
/**
* @brief Cause the TCP/IP stack to start the Wi-Fi station interface with specified MAC and IP

View file

@ -49,19 +49,19 @@ static tcpip_adapter_ip_lost_timer_t esp_ip_lost_timer[TCPIP_ADAPTER_IF_MAX];
static tcpip_adapter_dhcp_status_t dhcps_status = TCPIP_ADAPTER_DHCP_INIT;
static tcpip_adapter_dhcp_status_t dhcpc_status[TCPIP_ADAPTER_IF_MAX] = {TCPIP_ADAPTER_DHCP_INIT};
static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t *msg);
static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if);
static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if);
static void tcpip_adapter_ip_lost_timer(void *arg);
@ -69,13 +69,13 @@ static sys_sem_t api_sync_sem = NULL;
static bool tcpip_inited = false;
static sys_sem_t api_lock_sem = NULL;
extern sys_thread_t g_lwip_task;
static const char* TAG = "tcpip_adapter";
static const char *TAG = "tcpip_adapter";
ESP_EVENT_DEFINE_BASE(IP_EVENT);
static void tcpip_adapter_api_cb(void* api_msg)
static void tcpip_adapter_api_cb(void *api_msg)
{
tcpip_adapter_api_msg_t *msg = (tcpip_adapter_api_msg_t*)api_msg;
tcpip_adapter_api_msg_t *msg = (tcpip_adapter_api_msg_t *)api_msg;
if (!msg || !msg->api_fn) {
ESP_LOGD(TAG, "null msg/api_fn");
@ -91,8 +91,8 @@ static void tcpip_adapter_api_cb(void* api_msg)
static void tcpip_adapter_dhcps_cb(u8_t client_ip[4])
{
ESP_LOGI(TAG,"softAP assign IP to station,IP is: %d.%d.%d.%d",
client_ip[0],client_ip[1],client_ip[2],client_ip[3]);
ESP_LOGI(TAG, "softAP assign IP to station,IP is: %d.%d.%d.%d",
client_ip[0], client_ip[1], client_ip[2], client_ip[3]);
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
evt.event_id = SYSTEM_EVENT_AP_STAIPASSIGNED;
@ -129,10 +129,11 @@ void tcpip_adapter_init(void)
static inline netif_init_fn tcpip_if_to_netif_init_fn(tcpip_adapter_if_t tcpip_if)
{
if (tcpip_if < TCPIP_ADAPTER_IF_MAX)
return esp_netif_init_fn[tcpip_if];
else
return NULL;
if (tcpip_if < TCPIP_ADAPTER_IF_MAX) {
return esp_netif_init_fn[tcpip_if];
} else {
return NULL;
}
}
static int tcpip_adapter_ipc_check(tcpip_adapter_api_msg_t *msg)
@ -169,11 +170,11 @@ static esp_err_t tcpip_adapter_update_default_netif(void)
return ESP_OK;
}
static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args)
{
netif_init_fn netif_init;
TCPIP_ADAPTER_IPC_CALL(tcpip_if, mac, ip_info, 0, tcpip_adapter_start_api);
TCPIP_ADAPTER_IPC_CALL(tcpip_if, mac, ip_info, args, tcpip_adapter_start_api);
if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || mac == NULL || ip_info == NULL) {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
@ -191,7 +192,7 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac,
netif_init = tcpip_if_to_netif_init_fn(tcpip_if);
assert(netif_init != NULL);
netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, NULL, netif_init, tcpip_input);
netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, args, netif_init, tcpip_input);
#if ESP_GRATUITOUS_ARP
if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
netif_set_garp_flag(esp_netif[tcpip_if]);
@ -205,11 +206,11 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac,
if (dhcps_status == TCPIP_ADAPTER_DHCP_INIT) {
dhcps_set_new_lease_cb(tcpip_adapter_dhcps_cb);
dhcps_start(esp_netif[tcpip_if], ip_info->ip);
ESP_LOGD(TAG, "dhcp server start:(ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR ")",
IP2STR(&ip_info->ip), IP2STR(&ip_info->netmask), IP2STR(&ip_info->gw));
IP2STR(&ip_info->ip), IP2STR(&ip_info->netmask), IP2STR(&ip_info->gw));
dhcps_status = TCPIP_ADAPTER_DHCP_STARTED;
}
@ -222,34 +223,34 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac,
return ESP_OK;
}
esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args)
{
esp_netif_init_fn[TCPIP_ADAPTER_IF_ETH] = ethernetif_init;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_ETH, mac, ip_info);
esp_netif_init_fn[TCPIP_ADAPTER_IF_ETH] = ethernetif_init;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_ETH, mac, ip_info, args);
}
esp_err_t tcpip_adapter_sta_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
{
esp_netif_init_fn[TCPIP_ADAPTER_IF_STA] = wlanif_init_sta;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_STA, mac, ip_info);
esp_netif_init_fn[TCPIP_ADAPTER_IF_STA] = wlanif_init_sta;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_STA, mac, ip_info, NULL);
}
esp_err_t tcpip_adapter_test_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
{
esp_netif_init_fn[TCPIP_ADAPTER_IF_TEST] = nettestif_init;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_TEST, mac, ip_info);
esp_netif_init_fn[TCPIP_ADAPTER_IF_TEST] = nettestif_init;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_TEST, mac, ip_info, NULL);
}
esp_err_t tcpip_adapter_ap_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
{
esp_netif_init_fn[TCPIP_ADAPTER_IF_AP] = wlanif_init_ap;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_AP, mac, ip_info);
esp_netif_init_fn[TCPIP_ADAPTER_IF_AP] = wlanif_init_ap;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_AP, mac, ip_info, NULL);
}
static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_start(msg->tcpip_if, msg->mac, msg->ip_info);
return tcpip_adapter_start(msg->tcpip_if, msg->mac, msg->ip_info, msg->data);
}
esp_err_t tcpip_adapter_stop(tcpip_adapter_if_t tcpip_if)
@ -291,7 +292,7 @@ esp_err_t tcpip_adapter_stop(tcpip_adapter_if_t tcpip_if)
return ESP_OK;
}
static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t *msg)
{
msg->ret = tcpip_adapter_stop(msg->tcpip_if);
return msg->ret;
@ -316,7 +317,7 @@ esp_err_t tcpip_adapter_up(tcpip_adapter_if_t tcpip_if)
return ESP_OK;
}
static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t *msg)
{
msg->ret = tcpip_adapter_up(msg->tcpip_if);
return msg->ret;
@ -349,12 +350,12 @@ esp_err_t tcpip_adapter_down(tcpip_adapter_if_t tcpip_if)
return ESP_OK;
}
static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_down(msg->tcpip_if);
}
esp_err_t tcpip_adapter_set_old_ip_info_api(tcpip_adapter_api_msg_t * msg)
esp_err_t tcpip_adapter_set_old_ip_info_api(tcpip_adapter_api_msg_t *msg)
{
memcpy(&esp_ip_old[msg->tcpip_if], msg->ip_info, sizeof(tcpip_adapter_ip_info_t));
return ESP_OK;
@ -468,7 +469,7 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, const tcpip_ada
return ESP_OK;
}
static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_set_ip_info(msg->tcpip_if, msg->ip_info);
}
@ -528,7 +529,7 @@ esp_err_t tcpip_adapter_create_ip6_linklocal(tcpip_adapter_if_t tcpip_if)
}
}
static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_create_ip6_linklocal(msg->tcpip_if);
}
@ -683,7 +684,7 @@ esp_err_t tcpip_adapter_dhcps_option(tcpip_adapter_dhcp_option_mode_t opt_op, tc
if (*(uint8_t *)opt_val) {
*(uint8_t *)opt_info |= OFFER_ROUTER;
} else {
*(uint8_t *)opt_info &= ((~OFFER_ROUTER)&0xFF);
*(uint8_t *)opt_info &= ((~OFFER_ROUTER) & 0xFF);
}
break;
}
@ -691,15 +692,15 @@ esp_err_t tcpip_adapter_dhcps_option(tcpip_adapter_dhcp_option_mode_t opt_op, tc
if (*(uint8_t *)opt_val) {
*(uint8_t *)opt_info |= OFFER_DNS;
} else {
*(uint8_t *)opt_info &= ((~OFFER_DNS)&0xFF);
*(uint8_t *)opt_info &= ((~OFFER_DNS) & 0xFF);
}
break;
}
default:
break;
}
dhcps_set_option_info(opt_id, opt_info,opt_len);
dhcps_set_option_info(opt_id, opt_info, opt_len);
} else {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
@ -720,7 +721,7 @@ esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_
ESP_LOGD(TAG, "set dns invalid if=%d", tcpip_if);
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
if (!dns) {
ESP_LOGD(TAG, "set dns null dns");
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
@ -730,7 +731,7 @@ esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_
ESP_LOGD(TAG, "set dns invalid type=%d", type);
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
if (ip4_addr_isany_val(dns->ip.u_addr.ip4)) {
ESP_LOGD(TAG, "set dns invalid dns");
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
@ -753,20 +754,20 @@ esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_
return ESP_OK;
}
static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t *msg)
{
tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t*)msg->data;
tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t *)msg->data;
return tcpip_adapter_set_dns_info(msg->tcpip_if, dns_param->dns_type, dns_param->dns_info);
}
esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t *dns)
{
{
tcpip_adapter_dns_param_t dns_param;
dns_param.dns_type = type;
dns_param.dns_info = dns;
TCPIP_ADAPTER_IPC_CALL(tcpip_if, type, 0, &dns_param, tcpip_adapter_get_dns_info_api);
if (!dns) {
ESP_LOGD(TAG, "get dns null dns");
@ -777,9 +778,9 @@ esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_
ESP_LOGD(TAG, "get dns invalid type=%d", type);
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) {
ESP_LOGD(TAG, "get dns invalid tcpip_if=%d",tcpip_if);
ESP_LOGD(TAG, "get dns invalid tcpip_if=%d", tcpip_if);
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
@ -792,9 +793,9 @@ esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_
return ESP_OK;
}
static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t *msg)
{
tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t*)msg->data;
tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t *)msg->data;
return tcpip_adapter_get_dns_info(msg->tcpip_if, dns_param->dns_type, dns_param->dns_info);
}
@ -837,7 +838,7 @@ esp_err_t tcpip_adapter_dhcps_start(tcpip_adapter_if_t tcpip_if)
return ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED;
}
static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_dhcps_start(msg->tcpip_if);
}
@ -872,7 +873,7 @@ esp_err_t tcpip_adapter_dhcps_stop(tcpip_adapter_if_t tcpip_if)
return ESP_OK;
}
static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_dhcps_stop(msg->tcpip_if);
}
@ -894,11 +895,11 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif)
return;
}
if( netif == esp_netif[TCPIP_ADAPTER_IF_STA] ) {
if ( netif == esp_netif[TCPIP_ADAPTER_IF_STA] ) {
tcpip_if = TCPIP_ADAPTER_IF_STA;
} else if(netif == esp_netif[TCPIP_ADAPTER_IF_ETH] ) {
} else if (netif == esp_netif[TCPIP_ADAPTER_IF_ETH] ) {
tcpip_if = TCPIP_ADAPTER_IF_ETH;
} else {
} else {
ESP_LOGD(TAG, "err netif=%p", netif);
return;
}
@ -908,7 +909,7 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif)
ip_info_old = &esp_ip_old[tcpip_if];
if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4) ) {
//check whether IP is changed
if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), (&ip_info->ip)) ||
!ip4_addr_cmp(ip_2_ip4(&netif->netmask), (&ip_info->netmask)) ||
@ -967,13 +968,13 @@ static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if)
if ( netif && (CONFIG_NETIF_IP_LOST_TIMER_INTERVAL > 0) && !ip4_addr_isany_val(ip_info_old->ip)) {
esp_ip_lost_timer[tcpip_if].timer_running = true;
sys_timeout(CONFIG_NETIF_IP_LOST_TIMER_INTERVAL*1000, tcpip_adapter_ip_lost_timer, (void*)tcpip_if);
sys_timeout(CONFIG_NETIF_IP_LOST_TIMER_INTERVAL * 1000, tcpip_adapter_ip_lost_timer, (void *)tcpip_if);
ESP_LOGD(TAG, "if%d start ip lost tmr: interval=%d", tcpip_if, CONFIG_NETIF_IP_LOST_TIMER_INTERVAL);
return ESP_OK;
}
ESP_LOGD(TAG, "if%d start ip lost tmr: no need start because netif=%p interval=%d ip=%x",
tcpip_if, netif, CONFIG_NETIF_IP_LOST_TIMER_INTERVAL, ip_info_old->ip.addr);
ESP_LOGD(TAG, "if%d start ip lost tmr: no need start because netif=%p interval=%d ip=%x",
tcpip_if, netif, CONFIG_NETIF_IP_LOST_TIMER_INTERVAL, ip_info_old->ip.addr);
return ESP_OK;
}
@ -988,7 +989,7 @@ static void tcpip_adapter_ip_lost_timer(void *arg)
if (tcpip_if == TCPIP_ADAPTER_IF_STA) {
struct netif *netif = esp_netif[tcpip_if];
if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))){
if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))) {
system_event_t evt;
memset(&evt, 0, sizeof(system_event_t));
@ -1062,7 +1063,7 @@ esp_err_t tcpip_adapter_dhcpc_start(tcpip_adapter_if_t tcpip_if)
return ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED;
}
static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_dhcpc_start(msg->tcpip_if);
}
@ -1096,11 +1097,11 @@ esp_err_t tcpip_adapter_dhcpc_stop(tcpip_adapter_if_t tcpip_if)
dhcpc_status[tcpip_if] = TCPIP_ADAPTER_DHCP_STOPPED;
LWIP_DHCP_IP_ADDR_ERASE();
return ESP_OK;
}
static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t *msg)
{
return tcpip_adapter_dhcpc_stop(msg->tcpip_if);
}
@ -1193,9 +1194,9 @@ esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *ho
#endif
}
static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t * msg)
static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t *msg)
{
const char *hostname = (char*) msg->data;
const char *hostname = (char *) msg->data;
return tcpip_adapter_set_hostname(msg->tcpip_if, hostname);
}
@ -1228,7 +1229,7 @@ static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if)
return ESP_OK;
}
esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif)
esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void **netif)
{
if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) {
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;

View file

@ -62,11 +62,10 @@ INPUT = \
##
## Ethernet - API Reference
##
../../components/ethernet/include/esp_eth.h \
../../components/ethernet/include/eth_phy/phy.h \
../../components/ethernet/include/eth_phy/phy_tlk110.h \
../../components/ethernet/include/eth_phy/phy_lan8720.h \
../../components/ethernet/include/eth_phy/phy_ip101.h \
../../components/esp_eth/include/esp_eth.h \
../../components/esp_eth/include/esp_eth_com.h \
../../components/esp_eth/include/esp_eth_mac.h \
../../components/esp_eth/include/esp_eth_phy.h \
##
## Peripherals - API Reference
##

View file

@ -7,48 +7,47 @@ Application Example
- Ethernet basic example: :example:`ethernet/ethernet`.
- Ethernet iperf example: :example:`ethernet/iperf`.
PHY Interfaces
--------------
Ethernet Driver Model
---------------------
The configured PHY model(s) are set in software by configuring the eth_config_t structure for the given PHY.
* :component_file:`esp_eth/include/esp_eth.h`
Headers include a default configuration structure. These default configurations will need some members overriden or re-set before they can be used for a particular PHY hardware configuration. Consult the Ethernet example to see how this is done.
Ethernet Common Interface
-------------------------
* :component_file:`ethernet/include/eth_phy/phy.h` (common)
* :component_file:`ethernet/include/eth_phy/phy_tlk110.h`
* :component_file:`ethernet/include/eth_phy/phy_lan8720.h`
* :component_file:`ethernet/include/eth_phy/phy_ip101.h`
* :component_file:`esp_eth/include/esp_eth_com.h`
PHY Configuration Constants
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ethernet MAC Interface
----------------------
.. doxygenvariable:: phy_tlk110_default_ethernet_config
.. doxygenvariable:: phy_lan8720_default_ethernet_config
.. doxygenvariable:: phy_ip101_default_ethernet_config
* :component_file:`esp_eth/include/esp_eth_mac.h`
Ethernet PHY Interface
----------------------
API Reference - Ethernet
------------------------
* :component_file:`esp_eth/include/esp_eth_phy.h`
Ethernet PHY Common Registers
-----------------------------
* :component_file:`esp_eth/include/eth_phy_regs_struct.h`
API Reference - Driver Model
----------------------------
.. include:: /_build/inc/esp_eth.inc
API Reference - PHY Common
--------------------------
API Reference - Common Interface
--------------------------------
.. include:: /_build/inc/phy.inc
.. include:: /_build/inc/esp_eth_com.inc
API Reference - PHY TLK110
--------------------------
API Reference - MAC Interface
-----------------------------
.. include:: /_build/inc/phy_tlk110.inc
.. include:: /_build/inc/esp_eth_mac.inc
API Reference - PHY LAN8720
---------------------------
.. include:: /_build/inc/phy_lan8720.inc
API Reference - PHY IP101
-------------------------
.. include:: /_build/inc/phy_ip101.inc
API Reference - PHY Interface
-----------------------------
.. include:: /_build/inc/esp_eth_phy.inc

View file

@ -30,119 +30,39 @@ menu "Example Connection Configuration"
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
choice EXAMPLE_PHY_MODEL
prompt "Ethernet PHY"
choice EXAMPLE_ETH_PHY_MODEL
depends on EXAMPLE_CONNECT_ETHERNET
default EXAMPLE_PHY_TLK110
prompt "Ethernet PHY Device"
default EXAMPLE_ETH_PHY_IP101
help
Select the PHY driver to use for the example.
config EXAMPLE_PHY_IP101
config EXAMPLE_ETH_PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config EXAMPLE_PHY_TLK110
bool "TI TLK110 PHY"
config EXAMPLE_ETH_PHY_RTL8201
bool "RTL8201/SR8201"
help
Select this to use the TI TLK110 PHY
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
config EXAMPLE_PHY_LAN8720
bool "Microchip LAN8720 PHY"
config EXAMPLE_ETH_PHY_LAN8720
bool "LAN8720"
help
Select this to use the Microchip LAN8720 PHY
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
config EXAMPLE_ETH_PHY_DP83848
bool "DP83848"
help
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
endchoice
config EXAMPLE_PHY_ADDRESS
int "PHY Address (0-31)"
depends on EXAMPLE_CONNECT_ETHERNET
default 31
range 0 31
help
Select the PHY Address (0-31) for the hardware configuration and PHY model.
TLK110 default 31
LAN8720 default 1 or 0
choice EXAMPLE_PHY_CLOCK_MODE
prompt "EMAC clock mode"
depends on EXAMPLE_CONNECT_ETHERNET
default EXAMPLE_PHY_CLOCK_GPIO0_IN
help
Select external (input on GPIO0) or internal (output on GPIO16 or GPIO17) clock
config EXAMPLE_PHY_CLOCK_GPIO0_IN
bool "GPIO0 input"
depends on EXAMPLE_CONNECT_ETHERNET
help
Input of 50MHz PHY clock on GPIO0.
config EXAMPLE_PHY_CLOCK_GPIO0_OUT
bool "GPIO0 Output"
help
Output the internal 50MHz RMII clock on GPIO0.
config EXAMPLE_PHY_CLOCK_GPIO16_OUT
bool "GPIO16 output"
depends on EXAMPLE_CONNECT_ETHERNET
help
Output the internal 50MHz APLL clock on GPIO16.
config EXAMPLE_PHY_CLOCK_GPIO17_OUT
bool "GPIO17 output (inverted)"
depends on EXAMPLE_CONNECT_ETHERNET
help
Output the internal 50MHz APLL clock on GPIO17 (inverted signal).
endchoice
config EXAMPLE_PHY_CLOCK_MODE
int
depends on EXAMPLE_CONNECT_ETHERNET
default 0 if EXAMPLE_PHY_CLOCK_GPIO0_IN
default 1 if EXAMPLE_PHY_CLOCK_GPIO0_OUT
default 2 if EXAMPLE_PHY_CLOCK_GPIO16_OUT
default 3 if EXAMPLE_PHY_CLOCK_GPIO17_OUT
config EXAMPLE_PHY_USE_POWER_PIN
bool "Use PHY Power (enable/disable) pin"
depends on EXAMPLE_CONNECT_ETHERNET
default y
help
Use a GPIO "power pin" to power the PHY on/off during operation.
Consult the example README for more details
config EXAMPLE_PHY_POWER_PIN
int "PHY Power GPIO"
depends on EXAMPLE_CONNECT_ETHERNET
default 17
range 0 33
depends on EXAMPLE_PHY_USE_POWER_PIN
help
GPIO number to use for powering on/off the PHY.
config EXAMPLE_PHY_SMI_MDC_PIN
int "SMI MDC Pin"
depends on EXAMPLE_CONNECT_ETHERNET
default 23
range 0 33
help
GPIO number to use for SMI clock output MDC to PHY.
config EXAMPLE_PHY_SMI_MDIO_PIN
int "SMI MDIO Pin"
depends on EXAMPLE_CONNECT_ETHERNET
default 18
range 0 33
help
GPIO number to use for SMI data pin MDIO to/from PHY.
config EXAMPLE_CONNECT_IPV6
bool "Obtain IPv6 link-local address"
default y

View file

@ -21,24 +21,23 @@
#include "lwip/err.h"
#include "lwip/sys.h"
#define GOT_IPV4_BIT BIT(0)
#define GOT_IPV6_BIT BIT(1)
#define GOT_IPV4_BIT BIT(0)
#define GOT_IPV6_BIT BIT(1)
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
#define CONNECTED_BITS (GOT_IPV4_BIT | GOT_IPV6_BIT)
#define CONNECTED_BITS (GOT_IPV4_BIT | GOT_IPV6_BIT)
#else
#define CONNECTED_BITS (GOT_IPV4_BIT)
#define CONNECTED_BITS (GOT_IPV4_BIT)
#endif
static EventGroupHandle_t s_connect_event_group;
static ip4_addr_t s_ip_addr;
static const char* s_connection_name;
static const char *s_connection_name;
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
static ip6_addr_t s_ipv6_addr;
#endif
static const char *TAG = "example_connect";
/* set up connection, Wi-Fi or Ethernet */
@ -47,20 +46,20 @@ static void start();
/* tear down connection, release resources */
static void stop();
static void on_got_ip(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void on_got_ip(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;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr));
xEventGroupSetBits(s_connect_event_group, GOT_IPV4_BIT);
}
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
static void on_got_ipv6(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void on_got_ipv6(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip6_t* event = (ip_event_got_ip6_t*) event_data;
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
memcpy(&s_ipv6_addr, &event->ip6_info.ip, sizeof(s_ipv6_addr));
xEventGroupSetBits(s_connect_event_group, GOT_IPV6_BIT);
}
@ -98,17 +97,17 @@ esp_err_t example_disconnect()
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
static void on_wifi_disconnect(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void on_wifi_disconnect(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect...");
ESP_ERROR_CHECK( esp_wifi_connect() );
ESP_ERROR_CHECK(esp_wifi_connect());
}
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
static void on_wifi_connect(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void on_wifi_connect(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
}
@ -155,87 +154,13 @@ static void stop()
}
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
#include "driver/gpio.h"
#ifdef CONFIG_EXAMPLE_PHY_LAN8720
#include "eth_phy/phy_lan8720.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
#endif
#ifdef CONFIG_EXAMPLE_PHY_TLK110
#include "eth_phy/phy_tlk110.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
#elif CONFIG_EXAMPLE_PHY_IP101
#include "eth_phy/phy_ip101.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_ip101_default_ethernet_config
#endif
#define PIN_PHY_POWER CONFIG_EXAMPLE_PHY_POWER_PIN
#define PIN_SMI_MDC CONFIG_EXAMPLE_PHY_SMI_MDC_PIN
#define PIN_SMI_MDIO CONFIG_EXAMPLE_PHY_SMI_MDIO_PIN
#ifdef CONFIG_EXAMPLE_PHY_USE_POWER_PIN
/**
* @brief re-define power enable func for phy
*
* @param enable true to enable, false to disable
*
* @note This function replaces the default PHY power on/off function.
* If this GPIO is not connected on your device (and PHY is always powered),
* you can use the default PHY-specific power on/off function.
*/
static void phy_device_power_enable_via_gpio(bool enable)
{
assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
if (!enable) {
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(PIN_PHY_POWER);
gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
if (enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
ESP_LOGI(TAG, "Power On Ethernet PHY");
} else {
gpio_set_level(PIN_PHY_POWER, 0);
ESP_LOGI(TAG, "Power Off Ethernet PHY");
}
vTaskDelay(1); // Allow the power up/down to take effect, min 300us
if (enable) {
/* call the default PHY-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
#endif
/**
* @brief gpio specific init
*
* @note RMII data pins are fixed in esp32:
* TXD0 <=> GPIO19
* TXD1 <=> GPIO22
* TX_EN <=> GPIO21
* RXD0 <=> GPIO25
* RXD1 <=> GPIO26
* CLK <=> GPIO0
*
*/
static void eth_gpio_config_rmii(void)
{
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
/** Event handler for Ethernet events */
static void on_eth_event(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void on_eth_event(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
@ -249,30 +174,33 @@ static void on_eth_event(void* arg, esp_event_base_t event_base,
#endif // CONFIG_EXAMPLE_CONNECT_IPV6
static esp_eth_handle_t s_eth_handle = NULL;
static esp_eth_mac_t *s_mac = NULL;
static esp_eth_phy_t *s_phy = NULL;
static void start()
{
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_EXAMPLE_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.clock_mode = CONFIG_EXAMPLE_PHY_CLOCK_MODE;
#ifdef CONFIG_EXAMPLE_PHY_USE_POWER_PIN
/* Replace the default 'power enable' function with an example-specific one
that toggles a power GPIO. */
config.phy_power_enable = phy_device_power_enable_via_gpio;
#endif
ESP_ERROR_CHECK(esp_eth_init(&config));
ESP_ERROR_CHECK(tcpip_adapter_set_default_eth_handlers());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL));
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL));
#endif
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
s_mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
#if CONFIG_EXAMPLE_ETH_PHY_IP101
s_phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
s_phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN8720
s_phy = esp_eth_phy_new_lan8720(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
s_phy = esp_eth_phy_new_dp83848(&phy_config);
#endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
ESP_ERROR_CHECK(esp_eth_enable());
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
s_connection_name = "Ethernet";
}
@ -283,9 +211,9 @@ static void stop()
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6));
ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event));
#endif
ESP_ERROR_CHECK(esp_eth_disable());
ESP_ERROR_CHECK(esp_eth_deinit());
ESP_ERROR_CHECK(esp_eth_driver_uninstall(s_eth_handle));
ESP_ERROR_CHECK(s_phy->del(s_phy));
ESP_ERROR_CHECK(s_mac->del(s_mac));
}
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET

View file

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ethernet_demo)
project(ethernet_basic)

View file

@ -3,7 +3,7 @@
# project subdirectory.
#
PROJECT_NAME := ethernet_demo
PROJECT_NAME := ethernet_basic
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,91 @@
# Ethernet Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates basic usage of `Ethernet driver` together with `tcpip_adapter`. The work flow of the example could be as follows:
1. Install Ethernet driver
2. Send DHCP requests and wait for a DHCP lease
3. If get IP address successfully, then you will be able to ping the device
If you have a new Ethernet application to go (for example, connect to IoT cloud via Ethernet), try this as a basic template, then add your own code.
## How to use example
### Hardware Required
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
### Project configuration in menuconfig
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system.
1. In the `Example Configuration` menu:
* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
2. In the `Component config > Ethernet` menu:
* Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
| Default Example GPIO | RMII Signal | Notes |
| -------------------- | ----------- | ------------- |
| GPIO23 | MDC | Output to PHY |
| GPIO18 | MDIO | Bidirectional |
* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
### Extra configuration in the code (Optional)
* By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.
### Build and Flash
Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```bash
I (336) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (382) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (392) eth_example: Ethernet Started
I (3922) eth_example: Ethernet Link Up
I (5862) tcpip_adapter: eth ip: 192.168.2.151, mask: 255.255.255.0, gw: 192.168.2.2
I (5862) eth_example: Ethernet Got IP Address
I (5862) eth_example: ~~~~~~~~~~~
I (5862) eth_example: ETHIP:192.168.2.151
I (5872) eth_example: ETHMASK:255.255.255.0
I (5872) eth_example: ETHGW:192.168.2.2
I (5882) eth_example: ~~~~~~~~~~~
```
## Troubleshooting
* RMII Clock
* ESP32's MAC and the external PHY device need a common 50MHz reference clock (aka RMII clock). This clock can either be provided by an externally oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce possible ringing.
* ESP32 can generate a 50MHz clock using internal APLL. But if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock.
* GPIO connections
* RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. They're described as below:
| GPIO | RMII Signal | ESP32 EMAC Function |
| ------ | ----------- | ------------------- |
| GPIO21 | TX_EN | EMAC_TX_EN |
| GPIO19 | TX0 | EMAC_TXD0 |
| GPIO22 | TX1 | EMAC_TXD1 |
| GPIO25 | RX0 | EMAC_RXD0 |
| GPIO26 | RX1 | EMAC_RXD1 |
| GPIO27 | CRS_DV | EMAC_RX_DRV |
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View file

@ -1,2 +1,3 @@
idf_component_register(SRCS "ethernet_example_main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS ".")

View file

@ -0,0 +1,34 @@
menu "Example Configuration"
choice EXAMPLE_ETH_PHY_MODEL
prompt "Ethernet PHY Device"
default EXAMPLE_ETH_PHY_IP101
help
Select the Ethernet PHY device to use in the example.
config EXAMPLE_ETH_PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config EXAMPLE_ETH_PHY_RTL8201
bool "RTL8201/SR8201"
help
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
config EXAMPLE_ETH_PHY_LAN8720
bool "LAN8720"
help
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
config EXAMPLE_ETH_PHY_DP83848
bool "DP83848"
help
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
endchoice
endmenu

View file

@ -0,0 +1,82 @@
/* Ethernet Basic Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tcpip_adapter.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
static const char *TAG = "eth_example";
static esp_eth_handle_t s_eth_handle = NULL;
/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
ESP_LOGI(TAG, "Ethernet Link Up");
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;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
const tcpip_adapter_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, "~~~~~~~~~~~");
}
void app_main()
{
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(tcpip_adapter_set_default_eth_handlers());
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
#if CONFIG_EXAMPLE_ETH_PHY_IP101
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN8720
esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
}

View file

@ -12,36 +12,38 @@ The similarities on MAC layer between Ethernet and Wi-Fi make it easy to forward
### Hardware Required
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports three Ethernet PHY: `TLK110`, `LAN8720` and `IP101`, additional PHY drivers should be implemented by users themselves.
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
### Configure the project
### Project configuration in menuconfig
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu.
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system.
1. In the `Example Configuration` menu:
* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
* Set PHY address under `Ethernet PHY address`, it should depend on the PHY configuration of your hardware. You'd better consult the schematic of the board. By default, the PHY address of **ESP32-Ethernet-Kit** is *1*.
* Check whether or not to control the power of PHY chip under `Use PHY Power (enable / disable) pin`, (if set true, you also need to give the GPIO number of that pin under `PHY Power GPIO`).
* Set SMI MDC/MDIO GPIO number according to board schematic, by default they are set as below:
* Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`.
* Set the maximum connection number under `Maximum STA connections`.
2. In the `Component config > Ethernet` menu:
* Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
| Default Example GPIO | RMII Signal | Notes |
| -------------------- | ----------- | ------------- |
| GPIO23 | MDC | Output to PHY |
| GPIO18 | MDIO | Bidirectional |
* Select one kind of RMII clock mode under `Ethernet RMII Clock Mode` option. Possible configurations of the clock are listed as below. By default, ESP32-Ethernet-Kit use the `GPIO0 input` mode, which gives a good performance when enabling Ethernet and Wi-Fi at the same time.
* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
| Mode | GPIO Pin | Signal name | Notes |
| -------- | -------- | ------------ | ------------------------------------------------------------ |
| external | GPIO0 | EMAC_TX_CLK | Input of 50MHz PHY clock |
| internal | GPIO0 | CLK_OUT1 | Output of 50MHz APLL clock |
| internal | GPIO16 | EMAC_CLK_OUT | Output of 50MHz APLL clock |
| internal | GPIO17 | EMAC_CLK_180 | Inverted output of 50MHz APLL clock (suitable for long clock trace) |
### Extra configuration in the code (Optional)
* External RMII clock must be connected to `GPIO0`.
* ESP32 can generate the RMII clock(50MHz) using its internal APLL. But if the APLL has already been used for other peripheral (e.g. I²S), you'd better choose the external clock.
* By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.peripheral (e.g. I²S), you'd better choose the external clock.
* Set the SSID and password for Wi-Fi ap interface under `Wi-Fi SSID` and `Wi-Fi Password`.
* Set the maximum connection number under `Maximum STA connections`.
### Build and Flash
@ -104,11 +106,29 @@ Now your mobile phone should get access to the Internet.
## Troubleshooting
* Got error message `emac: emac rx buf err` when running the example.
* This example just forwards the packets on the Layer2 between Wi-Fi and Ethernet, it won't do any Layer3 business. So make sure you have disabled the `CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE`. By default, this option is false in the `sdkconfig.defaults` file.
* RMII Clock
* ESP32's MAC and the external PHY device need a common 50MHz reference clock (aka RMII clock). This clock can either be provided by an externally oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce possible ringing.
* ESP32 can generate a 50MHz clock using internal APLL. But if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock.
* Got error message `example: WiFi send packet failed: -1` when running the example.
* GPIO connections
* RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. They're described as below:
| GPIO | RMII Signal | ESP32 EMAC Function |
| ------ | ----------- | ------------------- |
| GPIO21 | TX_EN | EMAC_TX_EN |
| GPIO19 | TX0 | EMAC_TXD0 |
| GPIO22 | TX1 | EMAC_TXD1 |
| GPIO25 | RX0 | EMAC_RXD0 |
| GPIO26 | RX1 | EMAC_RXD1 |
| GPIO27 | CRS_DV | EMAC_RX_DRV |
* Got error message `WiFi send packet failed` when running the example.
* Ethernet process packets faster than Wi-Fi on ESP32, so have a try to enlarge the value of `FLOW_CONTROL_WIFI_SEND_DELAY_MS`.
* Got error message `send flow control message failed or timeout` when running the example.
* Enlarge the length of `FLOW_CONTROL_QUEUE_LENGTH`.
* Wi-Fi station doesn't receive any IP via DHCP.
* All Layer 3 (TCP/IP functions) on the ESP32 are disabled, including the SoftAP DHCP server. This means that devices must be able to access another DHCP server (for example on a Wi-Fi router connected via ethernet) or should use statically assigned IP addresses.
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View file

@ -1,2 +1,2 @@
idf_component_register(SRCS "eth2ap_example_main.c"
INCLUDE_DIRS ".")
idf_component_register(SRCS "ethernet_example_main.c"
INCLUDE_DIRS ".")

View file

@ -1,95 +1,36 @@
menu "Example Configuration"
choice EXAMPLE_PHY_MODEL
choice EXAMPLE_ETH_PHY_MODEL
prompt "Ethernet PHY Device"
default EXAMPLE_PHY_IP101
default EXAMPLE_ETH_PHY_IP101
help
Select the PHY driver to use for the example.
config EXAMPLE_PHY_IP101
Select the Ethernet PHY device to use in the example.
config EXAMPLE_ETH_PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config EXAMPLE_PHY_TLK110
bool "TLK110"
config EXAMPLE_ETH_PHY_RTL8201
bool "RTL8201/SR8201"
help
TLK110 is an Industrial 10/100Mbps Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/TLK110 for information about it.
config EXAMPLE_PHY_LAN8720
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
config EXAMPLE_ETH_PHY_LAN8720
bool "LAN8720"
help
LAN8720 is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
config EXAMPLE_ETH_PHY_DP83848
bool "DP83848"
help
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
endchoice
config EXAMPLE_PHY_ADDRESS
int "Ethernet PHY Address"
default 1
range 0 31
help
PHY Address of your PHY device. It depends on your schematic design.
choice EXAMPLE_PHY_CLOCK_MODE
prompt "Ethernet RMII Clock Mode"
default EXAMPLE_PHY_CLOCK_GPIO0_IN
help
Select external (input on GPIO0) or internal (output on GPIO0, GPIO16 or GPIO17) RMII clock.
config EXAMPLE_PHY_CLOCK_GPIO0_IN
bool "GPIO0 Input"
help
Input of 50MHz RMII clock on GPIO0.
config EXAMPLE_PHY_CLOCK_GPIO0_OUT
bool "GPIO0 Output"
help
Output the internal 50MHz RMII clock on GPIO0.
config EXAMPLE_PHY_CLOCK_GPIO16_OUT
bool "GPIO16 Output"
help
Output the internal 50MHz RMII clock on GPIO16.
config EXAMPLE_PHY_CLOCK_GPIO17_OUT
bool "GPIO17 Output (inverted)"
help
Output the internal 50MHz RMII clock on GPIO17 (inverted signal).
endchoice
config EXAMPLE_PHY_CLOCK_MODE
int
default 0 if EXAMPLE_PHY_CLOCK_GPIO0_IN
default 1 if EXAMPLE_PHY_CLOCK_GPIO0_OUT
default 2 if EXAMPLE_PHY_CLOCK_GPIO16_OUT
default 3 if EXAMPLE_PHY_CLOCK_GPIO17_OUT
config EXAMPLE_PHY_USE_POWER_PIN
bool "Use PHY Power (enable / disable) pin"
default y
help
Use a GPIO "power pin" to power the PHY on/off during operation.
When using GPIO0 to input RMII clock, the reset process will be interfered by this clock.
So we need another GPIO to control the switch on / off of the RMII clock.
if EXAMPLE_PHY_USE_POWER_PIN
config EXAMPLE_PHY_POWER_PIN
int "PHY power pin"
default 5
range 0 33
help
Set the GPIO number used for powering on/off the PHY.
endif
config EXAMPLE_PHY_SMI_MDC_PIN
int "Ethernet SMI MDC gpio number"
default 23
range 0 33
help
GPIO number used for SMI clock signal.
config EXAMPLE_PHY_SMI_MDIO_PIN
int "Ethernet SMI MDIO gpio number"
default 18
range 0 33
help
GPIO number used for SMI data signal.
config EXAMPLE_WIFI_SSID
string "Wi-Fi SSID"
default "eth2ap"

View file

@ -21,92 +21,27 @@
#include "driver/gpio.h"
#include "sdkconfig.h"
// Choose the default phy config according to Kconfig
#if CONFIG_EXAMPLE_PHY_LAN8720
#include "eth_phy/phy_lan8720.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
#elif CONFIG_EXAMPLE_PHY_TLK110
#include "eth_phy/phy_tlk110.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
#elif CONFIG_EXAMPLE_PHY_IP101
#include "eth_phy/phy_ip101.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_ip101_default_ethernet_config
#endif
static const char *TAG = "eth_example";
static esp_eth_handle_t s_eth_handle = NULL;
static xQueueHandle flow_control_queue = NULL;
static bool s_sta_is_connected = false;
static bool s_ethernet_is_connected = false;
static uint8_t s_eth_mac[6];
#define FLOW_CONTROL_QUEUE_TIMEOUT_MS (100)
#define FLOW_CONTROL_QUEUE_LENGTH (10)
#define FLOW_CONTROL_QUEUE_LENGTH (40)
#define FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS (100)
static const char *TAG = "example";
typedef struct {
void *packet;
uint16_t length;
} flow_control_msg_t;
static xQueueHandle flow_control_queue = NULL;
static bool s_sta_is_connected = false;
static bool s_ethernet_is_connected = false;
static uint8_t s_eth_mac[6];
#ifdef CONFIG_EXAMPLE_PHY_USE_POWER_PIN
/**
* @brief power control function for phy
*
* @param enable: set true to enable PHY power, set false to disable PHY power
*
* @note This function replaces the default PHY power on/off function.
* If this GPIO is not connected on your device (and PHY is always powered),
* you can use the default PHY-specific power on/off function.
*/
static void phy_device_power_enable_via_gpio(bool enable)
{
assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
if (!enable) {
/* call the default PHY-specific power off function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(CONFIG_EXAMPLE_PHY_POWER_PIN);
gpio_set_direction(CONFIG_EXAMPLE_PHY_POWER_PIN, GPIO_MODE_OUTPUT);
if (enable) {
gpio_set_level(CONFIG_EXAMPLE_PHY_POWER_PIN, 1);
ESP_LOGI(TAG, "Power On Ethernet PHY");
} else {
gpio_set_level(CONFIG_EXAMPLE_PHY_POWER_PIN, 0);
ESP_LOGI(TAG, "Power Off Ethernet PHY");
}
vTaskDelay(1);
if (enable) {
/* call the default PHY-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
#endif
/**
* @brief gpio specific init
*
* @note RMII data pins are fixed in esp32 as follows:
* TXD0 <=> GPIO19
* TXD1 <=> GPIO22
* TX_EN <=> GPIO21
* RXD0 <=> GPIO25
* RXD1 <=> GPIO26
* CLK <=> GPIO0
*
*/
static void eth_gpio_config_rmii(void)
{
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(CONFIG_EXAMPLE_PHY_SMI_MDC_PIN, CONFIG_EXAMPLE_PHY_SMI_MDIO_PIN);
}
// Forward packets from Wi-Fi to Ethernet
static esp_err_t pkt_wifi2eth(void *buffer, uint16_t len, void *eb)
{
if (s_ethernet_is_connected) {
if (esp_eth_tx(buffer, len) != ESP_OK) {
if (esp_eth_transmit(s_eth_handle, buffer, len) != ESP_OK) {
ESP_LOGE(TAG, "Ethernet send packet failed");
}
}
@ -117,7 +52,7 @@ static esp_err_t pkt_wifi2eth(void *buffer, uint16_t len, void *eb)
// Forward packets from Ethernet to Wi-Fi
// Note that, Ethernet works faster than Wi-Fi on ESP32,
// so we need to add an extra queue to balance their speed difference.
static esp_err_t pkt_eth2wifi(void *buffer, uint16_t len, void *eb)
static esp_err_t pkt_eth2wifi(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
flow_control_msg_t msg = {
@ -126,6 +61,7 @@ static esp_err_t pkt_eth2wifi(void *buffer, uint16_t len, void *eb)
};
if (xQueueSend(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) != pdTRUE) {
ESP_LOGE(TAG, "send flow control message failed or timeout");
free(buffer);
ret = ESP_FAIL;
}
return ret;
@ -141,17 +77,17 @@ static void eth2wifi_flow_control_task(void *args)
while (1) {
if (xQueueReceive(flow_control_queue, &msg, pdMS_TO_TICKS(FLOW_CONTROL_QUEUE_TIMEOUT_MS)) == pdTRUE) {
timeout = 0;
if (s_sta_is_connected && msg.length > 4) {
if (s_sta_is_connected && msg.length) {
do {
vTaskDelay(pdMS_TO_TICKS(timeout));
timeout += 2;
res = esp_wifi_internal_tx(ESP_IF_WIFI_AP, msg.packet, msg.length - 4);
} while (res == -1 && timeout < FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS);
res = esp_wifi_internal_tx(ESP_IF_WIFI_AP, msg.packet, msg.length);
} while (res && timeout < FLOW_CONTROL_WIFI_SEND_TIMEOUT_MS);
if (res != ESP_OK) {
ESP_LOGE(TAG, "WiFi send packet failed: %d", res);
}
}
esp_eth_free_rx_buf(msg.packet);
free(msg.packet);
}
}
vTaskDelete(NULL);
@ -165,7 +101,7 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base,
case ETHERNET_EVENT_CONNECTED:
ESP_LOGI(TAG, "Ethernet Link Up");
s_ethernet_is_connected = true;
esp_eth_get_mac(s_eth_mac);
esp_eth_ioctl(s_eth_handle, ETH_CMD_G_MAC_ADDR, s_eth_mac);
esp_wifi_set_mac(WIFI_IF_AP, s_eth_mac);
ESP_ERROR_CHECK(esp_wifi_start());
break;
@ -207,25 +143,29 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base,
static void initialize_ethernet(void)
{
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_EXAMPLE_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.clock_mode = CONFIG_EXAMPLE_PHY_CLOCK_MODE;
config.tcpip_input = pkt_eth2wifi;
config.promiscuous_enable = true;
#ifdef CONFIG_EXAMPLE_PHY_USE_POWER_PIN
/* Replace the default 'power enable' function with an example-specific one that toggles a power GPIO. */
config.phy_power_enable = phy_device_power_enable_via_gpio;
#endif
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_eth_init_internal(&config));
ESP_ERROR_CHECK(esp_eth_enable());
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
#if CONFIG_EXAMPLE_ETH_PHY_IP101
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN8720
esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
config.stack_input = pkt_eth2wifi;
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
esp_eth_ioctl(s_eth_handle, ETH_CMD_S_PROMISCUOUS, (void *)true);
}
static void initialize_wifi(void)
{
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init_internal(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {

View file

@ -1 +0,0 @@
CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE=n

View file

@ -1,106 +0,0 @@
# Ethernet Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates basic usage of `Ethernet driver` together with `tcpip_adapter`. The work flow of the example could be as follows:
1. Initialize the Ethernet interface and enable it
2. Send DHCP requests and wait for a DHCP lease
3. If get IP address successfully, then you will be able to ping the device
If you have a new Ethernet application to go (for example, connect to IoT cloud via Ethernet), try this as a basic template, then add your own code.
## How to use example
### Hardware Required
To run this example, you should have one ESP32 dev board integrated with an Ethernet interface, or just connect your ESP32 core board to a breakout board which featured with RMII Ethernet PHY. **Currently ESP-IDF officially supports three Ethernet PHY: `TLK110`, `LAN8720` and `IP101`, additional PHY drivers can be implemented by users themselves.**
### Configure the project
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. Then go into `Example Configuration` menu.
* Choose PHY device under `Ethernet PHY Device` option
* Set PHY address under `Ethernet PHY address` option, this address depends on the hardware and the PHY configuration. Consult the documentation/datasheet for the PHY hardware you have.
* Address 1 for the common Waveshare LAN8720 PHY breakout and the official ESP32-Ethernet-Kit board
* Check whether or not to control PHY's power under `Use PHY Power (enable / disable) pin` option, (if set true, you also need to set PHY Power GPIO number under `PHY Power GPIO` option)
* Set SMI MDC/MDIO GPIO number according to board schematic, default these two GPIOs are set as below:
| Default Example GPIO | RMII Signal | Notes |
| -------------------- | ----------- | ------------- |
| GPIO23 | MDC | Output to PHY |
| GPIO18 | MDIO | Bidirectional |
* Select one kind of EMAC clock mode under `Ethernet PHY Clock Mode` option. Possible configurations of the clock are listed as below:
| Mode | GPIO Pin | Signal name | Notes |
| -------- | -------- | ------------ | ------------------------------------------------------------ |
| external | GPIO0 | EMAC_TX_CLK | Input of 50MHz PHY clock |
| internal | GPIO0 | CLK_OUT1 | Output of 50MHz APLL clock |
| internal | GPIO16 | EMAC_CLK_OUT | Output of 50MHz APLL clock |
| internal | GPIO17 | EMAC_CLK_180 | Inverted output of 50MHz APLL clock (suitable for long clock trace) |
* The external reference clock of 50MHz must be supplied on `GPIO0`.
* The ESP32 can generate a 50MHz clock using internal APLL. When the APLL is already used as clock source for other purposes (most likely I²S), you have no choice but choose external clock.
### Build and Flash
Enter `make -j4 flash monitor` if you are using GNU Make based build system or enter `idf.py build flash monitor` if you' are using CMake based build system.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```bash
I (0) cpu_start: App cpu up.
I (265) heap_init: Initializing. RAM available for dynamic allocation:
I (272) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (278) heap_init: At 3FFB3FF0 len 0002C010 (176 KiB): DRAM
I (284) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (291) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (297) heap_init: At 4008851C len 00017AE4 (94 KiB): IRAM
I (303) cpu_start: Pro cpu start user code
I (322) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (325) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (325) emac: emac reset done
I (335) eth_example: Ethernet Started
I (4335) eth_example: Ethernet Link Up
I (6325) tcpip_adapter: eth ip: 192.168.2.164, mask: 255.255.255.0, gw: 192.168.2.2
I (6325) eth_example: Ethernet Got IP Address
I (6325) eth_example: ~~~~~~~~~~~
I (6325) eth_example: ETHIP:192.168.2.164
I (6335) eth_example: ETHMASK:255.255.255.0
I (6335) eth_example: ETHGW:192.168.2.2
I (6345) eth_example: ~~~~~~~~~~~
```
## Troubleshooting
* If the PHY address is incorrect then the EMAC will still be initialized, but all attempts to read/write configuration registers in the PHY's register will fail, for example, waiting for auto-negotiation done.
* Check PHY Clock
> The ESP32's MAC and the External PHY device need a common 50MHz reference clock. This clock can either be provided externally by a crystal oscillator (e.g. crystal connected to the PHY or a separate crystal oscillator) or internally by generating from EPS32's APLL. The signal integrity of this clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce ringing.
* Check GPIO connections, the RMII PHY wiring is fixed which can not be changed through either IOMUX or GPIO Matrix. They're described as below:
| GPIO | RMII Signal | ESP32 EMAC Function |
| ------ | ----------- | ------------------- |
| GPIO21 | TX_EN | EMAC_TX_EN |
| GPIO19 | TX0 | EMAC_TXD0 |
| GPIO22 | TX1 | EMAC_TXD1 |
| GPIO25 | RX0 | EMAC_RXD0 |
| GPIO26 | RX1 | EMAC_RXD1 |
| GPIO27 | CRS_DV | EMAC_RX_DRV |
* Check GPIO0
> GPIO0 is a strapping pin for entering UART flashing mode on reset, care must be taken when using this pin as `EMAC_TX_CLK`. If the clock output from the PHY is oscillating during reset, the ESP32 may randomly enter UART flashing mode. One solution is to use an additional GPIO as a "power pin", which either powers the PHY on/off or enables/disables the PHY's own oscillator. This prevents the clock signal from being active during a system reset. For this configuration to work, `GPIO0` also needs a pullup resistor and the "power pin" GPIO will need a pullup/pulldown resistor - as appropriate in order to keep the PHY clock disabled when the ESP32 is in reset. See the example source code to see how the "power pin" GPIO can be managed in software.

View file

@ -1,94 +0,0 @@
menu "Example Configuration"
choice PHY_MODEL
prompt "Ethernet PHY Device"
default PHY_TLK110
help
Select the PHY driver to use for the example.
config PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config PHY_TLK110
bool "TLK110"
help
TLK110 is an Industrial 10/100Mbps Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/TLK110 for information about it.
config PHY_LAN8720
bool "LAN8720"
help
LAN8720 is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
endchoice
config PHY_ADDRESS
int "Ethernet PHY Address"
default 31
range 0 31
help
PHY Address of your PHY device. It dependens on your schematic design.
choice PHY_CLOCK_MODE
prompt "Ethernet PHY Clock Mode"
default PHY_CLOCK_GPIO0_IN
help
Select external (input on GPIO0) or internal (output on GPIO0, GPIO16 or GPIO17) RMII clock.
config PHY_CLOCK_GPIO0_IN
bool "GPIO0 Input"
help
Input of 50MHz RMII clock on GPIO0.
config PHY_CLOCK_GPIO0_OUT
bool "GPIO0 Output"
help
Output the internal 50MHz RMII clock on GPIO0.
config PHY_CLOCK_GPIO16_OUT
bool "GPIO16 Output"
help
Output the internal 50MHz RMII clock on GPIO16.
config PHY_CLOCK_GPIO17_OUT
bool "GPIO17 Output (inverted)"
help
Output the internal 50MHz RMII clock on GPIO17 (inverted signal).
endchoice
config PHY_CLOCK_MODE
int
default 0 if PHY_CLOCK_GPIO0_IN
default 1 if PHY_CLOCK_GPIO0_OUT
default 2 if PHY_CLOCK_GPIO16_OUT
default 3 if PHY_CLOCK_GPIO17_OUT
config PHY_USE_POWER_PIN
bool "Use PHY Power (enable / disable) pin"
default n
help
Use a GPIO "power pin" to power the PHY on/off during operation.
When using GPIO0 to input RMII clock, the reset process will be interfered by this clock.
So we need another GPIO to control the switch on / off of the RMII clock.
if PHY_USE_POWER_PIN
config PHY_POWER_PIN
int "PHY Power GPIO"
default 17
range 0 33
depends on PHY_USE_POWER_PIN
help
GPIO number to use for powering on/off the PHY.
endif
config PHY_SMI_MDC_PIN
int "SMI MDC Pin Number"
default 23
range 0 33
help
GPIO number used for SMI clock signal.
config PHY_SMI_MDIO_PIN
int "SMI MDIO Pin Number"
default 18
range 0 33
help
GPIO number used for SMI data signal.
endmenu

View file

@ -1,154 +0,0 @@
/* ethernet Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event_loop.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "esp32/rom/gpio.h"
#include "tcpip_adapter.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#if CONFIG_PHY_LAN8720
#include "eth_phy/phy_lan8720.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
#elif CONFIG_PHY_TLK110
#include "eth_phy/phy_tlk110.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
#elif CONFIG_PHY_IP101
#include "eth_phy/phy_ip101.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_ip101_default_ethernet_config
#endif
static const char *TAG = "eth_example";
#define PIN_PHY_POWER CONFIG_PHY_POWER_PIN
#define PIN_SMI_MDC CONFIG_PHY_SMI_MDC_PIN
#define PIN_SMI_MDIO CONFIG_PHY_SMI_MDIO_PIN
#ifdef CONFIG_PHY_USE_POWER_PIN
/**
* @brief re-define power enable func for phy
*
* @param enable true to enable, false to disable
*
* @note This function replaces the default PHY power on/off function.
* If this GPIO is not connected on your device (and PHY is always powered),
* you can use the default PHY-specific power on/off function.
*/
static void phy_device_power_enable_via_gpio(bool enable)
{
assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
if (!enable) {
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(PIN_PHY_POWER);
gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
if (enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
ESP_LOGI(TAG, "Power On Ethernet PHY");
} else {
gpio_set_level(PIN_PHY_POWER, 0);
ESP_LOGI(TAG, "Power Off Ethernet PHY");
}
vTaskDelay(1); // Allow the power up/down to take effect, min 300us
if (enable) {
/* call the default PHY-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
#endif
/**
* @brief gpio specific init
*
* @note RMII data pins are fixed in esp32:
* TXD0 <=> GPIO19
* TXD1 <=> GPIO22
* TX_EN <=> GPIO21
* RXD0 <=> GPIO25
* RXD1 <=> GPIO26
* CLK <=> GPIO0
*
*/
static void eth_gpio_config_rmii(void)
{
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
/** Event handler for Ethernet events */
static void eth_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
ESP_LOGI(TAG, "Ethernet Link Up");
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;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
const tcpip_adapter_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, "~~~~~~~~~~~");
}
void app_main()
{
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.clock_mode = CONFIG_PHY_CLOCK_MODE;
#ifdef CONFIG_PHY_USE_POWER_PIN
/* Replace the default 'power enable' function with an example-specific one
that toggles a power GPIO. */
config.phy_power_enable = phy_device_power_enable_via_gpio;
#endif
ESP_ERROR_CHECK(esp_eth_init(&config));
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
ESP_ERROR_CHECK(esp_eth_enable()) ;
}

View file

@ -6,4 +6,4 @@ set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/components
$ENV{IDF_PATH}/examples/wifi/iperf/components)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ethernet-iperf)
project(ethernet_iperf)

View file

@ -3,7 +3,7 @@
# project subdirectory.
#
PROJECT_NAME := ethernet-iperf
PROJECT_NAME := ethernet_iperf
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/system/console/components
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/wifi/iperf/components

View file

@ -1,4 +1,4 @@
# Ethernet iperf example
# Ethernet iperf Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
@ -6,48 +6,47 @@
This example demonstrates basic usage of [iperf](https://iperf.fr/) protocol to measure the throughout/bandwidth of Ethernet.
This example is based on esp-idf's console component. For more information about console you can read the [guide](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/console.html).
The cli environment in the example is based on the [console component](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/console.html).
## How to use example
To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. Up until now, ESP-IDF supports four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
### Prepare work
1. Install iperf tool on PC
* Debian/Ubuntu: `sudo apt-get install iperf`
* macOS: `brew install iperf`(if using Homebrew) or `sudo port install iperf`(if using MacPorts)
* Windows(MSYS2): Downloads binaries from [here]( https://iperf.fr/iperf-download.php#windows)
2. Initialize Ethernet on ESP32, run `ethernet start`
3. Get ip information(optional), run `ethernet info`
### Configure the project
### Project configuration in menuconfig
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system. Then go into `Example Configuration` menu.
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you' are using CMake based build system.
* Check whether or not to store the history command into flash under `Store command history in flash` option
1. In the `Example Configuration` menu:
* Set PHY address under `Ethernet PHY address` option, this address depends on the hardware and the PHY configuration. Consult the documentation/datasheet for the PHY hardware you have.
- Address 1 for the common Waveshare LAN8720 PHY breakout and official ESP32-Ethernet-Kit board
* Enable storing history commands in flash under `Store command history in flash`.
* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
* Check whether or not to control PHY's power (if true, you need also to set PHY Power GPIO number later)
2. In the `Component config > Ethernet` menu:
* Set SMI MDC/MDIO GPIO number according to board schematic, default these two GPIOs are set as below:
* Enable `Use ESP32 internal EMAC controller`, and then go into this menu.
* In the `PHY interface`, it's highly recommended that you choose `Reduced Media Independent Interface (RMII)` which will cost fewer pins.
* In the `RMII clock mode`, you can choose the source of RMII clock (50MHz): `Input RMII clock from external` or `Output RMII clock from internal`.
* Once `Output RMII clock from internal` is enabled, you also have to set the number of the GPIO used for outputting the RMII clock under `RMII clock GPIO number`. In this case, you can set the GPIO number to 16 or 17.
* Once `Output RMII clock from GPIO0 (Experimental!)` is enabled, then you have no choice but GPIO0 to output the RMII clock.
* Set SMI MDC/MDIO GPIO number according to board schematic, by default these two GPIOs are set as below:
| Default Example GPIO | RMII Signal | Notes |
| -------------------- | ----------- | ------------- |
| GPIO23 | MDC | Output to PHY |
| GPIO18 | MDIO | Bidirectional |
* Select one kind of EMAC clock mode under `EMAC clock mode` option. Possible configurations of the clock are listed as below:
* If you have connect a GPIO to the PHY chip's RST pin, then you need to enable `Use Reset Pin of PHY Chip` and set the GPIO number under `PHY RST GPIO number`.
| Mode | GPIO Pin | Signal name | Notes |
| -------- | -------- | ------------ | ------------------------------------------------------------ |
| external | GPIO0 | EMAC_TX_CLK | Input of 50MHz PHY clock |
| internal | GPIO0 | CLK_OUT1 | Output of 50MHz APLL clock |
| internal | GPIO16 | EMAC_CLK_OUT | Output of 50MHz APLL clock |
| internal | GPIO17 | EMAC_CLK_180 | Inverted output of 50MHz APLL clock (suitable for long clock trace) |
### Extra configuration in the code (Optional)
- The external reference clock of 50MHz must be supplied on `GPIO0`.
- The ESP32 can generate a 50MHz clock using its APLL. When the APLL is already used as clock source for other purposes (most likely I²S), you have no choice but choose external clock.
* By default Ethernet driver will assume the PHY address to `1`, but you can alway reconfigure this value after `eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();`. The actual PHY address should depend on the hardware you use, so make sure to consult the schematic and datasheet.
### Build and Flash
@ -146,19 +145,18 @@ I (2534456) iperf: want recv=16384
## Suggestions of getting higher bandwidth
1. Higher MCU working frequency will get higher bandwidth
1. Higher MCU working frequency will get higher bandwidth.
2. Put frequency invoked function into IRAM via macro `IRAM_ATTR` in code.
3. Priority of iperf task may also have effect.
## Troubleshooting
- If the PHY address is incorrect then the EMAC will still be initialized, but all attempts to read/write configuration registers in the PHY's register will fail, for example, waiting for auto-negotiation done.
* RMII Clock
* ESP32's MAC and the external PHY device need a common 50MHz reference clock (aka RMII clock). This clock can either be provided by an externally oscillator or generated from internal APLL. The signal integrity of RMII clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce possible ringing.
* ESP32 can generate a 50MHz clock using internal APLL. But if the APLL is already used for other purposes (e.g. I2S peripheral), then you have no choice but use an external RMII clock.
- Check PHY Clock
> The ESP32's MAC and the External PHY device need a common 50MHz reference clock. This clock can either be provided externally by a crystal oscillator (e.g. crystal connected to the PHY or a separate crystal oscillator) or internally by generating from EPS32's APLL. The signal integrity of this clock is strict, so it is highly recommended to add a 33Ω resistor in series to reduce ringing.
- Check GPIO connections, the RMII PHY wiring is fixed which can not be changed through either IOMUX or GPIO Matrix. They're described as below:
* GPIO connections
* RMII PHY wiring is fixed and can not be changed through either IOMUX or GPIO Matrix. They're described as below:
| GPIO | RMII Signal | ESP32 EMAC Function |
| ------ | ----------- | ------------------- |
@ -169,6 +167,4 @@ I (2534456) iperf: want recv=16384
| GPIO26 | RX1 | EMAC_RXD1 |
| GPIO27 | CRS_DV | EMAC_RX_DRV |
- Check GPIO0
> GPIO0 is a strapping pin for entering UART flashing mode on reset, care must be taken when using this pin as `EMAC_TX_CLK`. If the clock output from the PHY is oscillating during reset, the ESP32 may randomly enter UART flashing mode. One solution is to use an additional GPIO as a "power pin", which either powers the PHY on/off or enables/disables the PHY's own oscillator. This prevents the clock signal from being active during a system reset. For this configuration to work, `GPIO0` also needs a pullup resistor and the "power pin" GPIO will need a pullup/pulldown resistor - as appropriate in order to keep the PHY clock disabled when the ESP32 is in reset. See the example source code to see how the "power pin" GPIO can be managed in software.
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View file

@ -1,3 +1,3 @@
idf_component_register(SRCS "cmd_ethernet.c"
"iperf_example_main.c"
INCLUDE_DIRS ".")
"ethernet_example_main.c"
INCLUDE_DIRS ".")

View file

@ -1,6 +1,6 @@
menu "Example Configuration"
config STORE_HISTORY
config EXAMPLE_STORE_HISTORY
bool "Store command history in flash"
default y
help
@ -8,99 +8,35 @@ menu "Example Configuration"
command history. If this option is enabled, initalizes a FAT filesystem
and uses it to store command history.
menu "Etherent PHY Device"
choice PHY_MODEL
prompt "Ethernet PHY Device"
default PHY_TLK110
choice EXAMPLE_ETH_PHY_MODEL
prompt "Ethernet PHY Device"
default EXAMPLE_ETH_PHY_IP101
help
Select the Ethernet PHY device to use in the example.
config EXAMPLE_ETH_PHY_IP101
bool "IP101"
help
Select the PHY driver to use for the example.
config PHY_IP101
bool "IP101"
help
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config PHY_TLK110
bool "TLK110"
help
TLK110 is an Industrial 10/100Mbps Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/TLK110 for information about it.
config PHY_LAN8720
bool "LAN8720"
help
LAN8720 is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
endchoice
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
config PHY_ADDRESS
int "Ethernet PHY Address"
default 31
range 0 31
config EXAMPLE_ETH_PHY_RTL8201
bool "RTL8201/SR8201"
help
PHY Address of your PHY device. It dependens on your schematic design.
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
choice PHY_CLOCK_MODE
prompt "Ethernet PHY Clock Mode"
default PHY_CLOCK_GPIO0_IN
config EXAMPLE_ETH_PHY_LAN8720
bool "LAN8720"
help
Select external (input on GPIO0) or internal (output on GPIO0, GPIO16 or GPIO17) RMII clock.
config PHY_CLOCK_GPIO0_IN
bool "GPIO0 Input"
help
Input of 50MHz RMII clock on GPIO0.
config PHY_CLOCK_GPIO0_OUT
bool "GPIO0 Output"
help
Output the internal 50MHz RMII clock on GPIO0.
config PHY_CLOCK_GPIO16_OUT
bool "GPIO16 Output"
help
Output the internal 50MHz RMII clock on GPIO16.
config PHY_CLOCK_GPIO17_OUT
bool "GPIO17 Output (inverted)"
help
Output the internal 50MHz RMII clock on GPIO17 (inverted signal).
endchoice
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
config PHY_CLOCK_MODE
int
default 0 if PHY_CLOCK_GPIO0_IN
default 1 if PHY_CLOCK_GPIO0_OUT
default 2 if PHY_CLOCK_GPIO16_OUT
default 3 if PHY_CLOCK_GPIO17_OUT
config PHY_USE_POWER_PIN
bool "Use PHY Power (enable / disable) pin"
default n
config EXAMPLE_ETH_PHY_DP83848
bool "DP83848"
help
Use a GPIO "power pin" to power the PHY on/off during operation.
When using GPIO0 to input RMII clock, the reset process will be interfered by this clock.
So we need another GPIO to control the switch on / off of the RMII clock.
if PHY_USE_POWER_PIN
config PHY_POWER_PIN
int "PHY Power GPIO"
default 17
range 0 33
depends on PHY_USE_POWER_PIN
help
GPIO number to use for powering on/off the PHY.
endif
endmenu
menu "Etherent SMI interface"
config PHY_SMI_MDC_PIN
int "SMI MDC Pin Number"
default 23
range 0 33
help
GPIO number used for SMI clock signal.
config PHY_SMI_MDIO_PIN
int "SMI MDIO Pin Number"
default 18
range 0 33
help
GPIO number used for SMI data signal.
endmenu
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
endchoice
endmenu

View file

@ -19,63 +19,13 @@
#include "iperf.h"
#include "sdkconfig.h"
#if CONFIG_PHY_LAN8720
#include "eth_phy/phy_lan8720.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
#elif CONFIG_PHY_TLK110
#include "eth_phy/phy_tlk110.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
#elif CONFIG_PHY_IP101
#include "eth_phy/phy_ip101.h"
#define DEFAULT_ETHERNET_PHY_CONFIG phy_ip101_default_ethernet_config
#endif
static tcpip_adapter_ip_info_t ip;
static bool started = false;
static EventGroupHandle_t eth_event_group;
static const int GOTIP_BIT = BIT0;
#define PIN_PHY_POWER CONFIG_PHY_POWER_PIN
#define PIN_SMI_MDC CONFIG_PHY_SMI_MDC_PIN
#define PIN_SMI_MDIO CONFIG_PHY_SMI_MDIO_PIN
#ifdef CONFIG_PHY_USE_POWER_PIN
static void phy_device_power_enable_via_gpio(bool enable)
{
assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
if (!enable) {
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_pad_select_gpio(PIN_PHY_POWER);
gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT);
if (enable == true) {
gpio_set_level(PIN_PHY_POWER, 1);
ESP_LOGI(__func__, "Power On Ethernet PHY");
} else {
gpio_set_level(PIN_PHY_POWER, 0);
ESP_LOGI(__func__, "Power Off Ethernet PHY");
}
vTaskDelay(1); // Allow the power up/down to take effect, min 300us
if (enable) {
/* call the default PHY-specific power on function */
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
#endif
static void eth_gpio_config_rmii(void)
{
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
}
static esp_eth_handle_t eth_handle = NULL;
/* "ethernet" command */
static struct {
struct arg_str *control;
struct arg_end *end;
@ -89,17 +39,9 @@ static int eth_cmd_control(int argc, char **argv)
return 1;
}
if (!strncmp(eth_control_args.control->sval[0], "start", 5) && !started) {
ESP_ERROR_CHECK(esp_eth_enable());
started = true;
}
if (!strncmp(eth_control_args.control->sval[0], "stop", 4) && started) {
ESP_ERROR_CHECK(esp_eth_disable());
started = false;
}
if (!strncmp(eth_control_args.control->sval[0], "info", 4)) {
uint8_t mac_addr[6];
esp_eth_get_mac(mac_addr);
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
printf("HW ADDR: " MACSTR "\r\n", MAC2STR(mac_addr));
tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip);
printf("ETHIP: " IPSTR "\r\n", IP2STR(&ip.ip));
@ -216,8 +158,8 @@ static int eth_cmd_iperf(int argc, char **argv)
return 0;
}
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == ETH_EVENT && event_id == ETHERNET_EVENT_START) {
started = true;
@ -225,7 +167,7 @@ static void event_handler(void* arg, esp_event_base_t event_base,
xEventGroupClearBits(eth_event_group, GOTIP_BIT);
started = false;
} else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
memcpy(&ip, &event->ip_info, sizeof(ip));
xEventGroupSetBits(eth_event_group, GOTIP_BIT);
}
@ -236,27 +178,30 @@ void register_ethernet()
eth_event_group = xEventGroupCreate();
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
config.phy_addr = CONFIG_PHY_ADDRESS;
config.gpio_config = eth_gpio_config_rmii;
config.tcpip_input = tcpip_adapter_eth_input;
config.clock_mode = CONFIG_PHY_CLOCK_MODE;
#ifdef CONFIG_PHY_USE_POWER_PIN
/* Replace the default 'power enable' function with an example-specific one
that toggles a power GPIO. */
config.phy_power_enable = phy_device_power_enable_via_gpio;
#endif
ESP_ERROR_CHECK(esp_eth_init(&config));
ESP_ERROR_CHECK(tcpip_adapter_set_default_eth_handlers());
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &event_handler, NULL));
eth_control_args.control = arg_str1(NULL, NULL, "<start|stop|info>", "Start/Stop Ethernet or Get info of Ethernet");
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
#if CONFIG_EXAMPLE_ETH_PHY_IP101
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_LAN8720
esp_eth_phy_t *phy = esp_eth_phy_new_lan8720(&phy_config);
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#endif
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &eth_handle));
eth_control_args.control = arg_str1(NULL, NULL, "<info>", "Get info of Ethernet");
eth_control_args.end = arg_end(1);
const esp_console_cmd_t cmd = {
.command = "ethernet",
.help = "Control Ethernet interface",
.help = "Ethernet interface IO control",
.hint = NULL,
.func = eth_cmd_control,
.argtable = &eth_control_args

View file

@ -22,9 +22,9 @@
#include "nvs_flash.h"
#include "sdkconfig.h"
static const char *TAG = "ethernet-console";
static const char *TAG = "eth_example";
#if CONFIG_STORE_HISTORY
#if CONFIG_EXAMPLE_STORE_HISTORY
#define MOUNT_PATH "/data"
#define HISTORY_PATH MOUNT_PATH "/history.txt"
@ -42,7 +42,7 @@ static void initialize_filesystem()
return;
}
}
#endif // CONFIG_STORE_HISTORY
#endif // CONFIG_EXAMPLE_STORE_HISTORY
static void initialize_nvs()
{
@ -103,7 +103,7 @@ static void initialize_console()
/* Set command history size */
linenoiseHistorySetMaxLen(100);
#if CONFIG_STORE_HISTORY
#if CONFIG_EXAMPLE_STORE_HISTORY
/* Load command history from filesystem */
linenoiseHistoryLoad(HISTORY_PATH);
#endif
@ -113,7 +113,7 @@ void app_main()
{
initialize_nvs();
#if CONFIG_STORE_HISTORY
#if CONFIG_EXAMPLE_STORE_HISTORY
initialize_filesystem();
#endif
@ -133,11 +133,10 @@ void app_main()
printf(" | Steps to Test Ethernet Bandwidth |\n");
printf(" | |\n");
printf(" | 1. Enter 'help', check all supported commands |\n");
printf(" | 2. Enter 'ethernet start' |\n");
printf(" | 3. Wait ESP32 to get IP from DHCP |\n");
printf(" | 4. Enter 'ethernet info', optional |\n");
printf(" | 2. Wait ESP32 to get IP from DHCP |\n");
printf(" | 3. Enter 'ethernet info', optional |\n");
printf(" | 4. Server: 'iperf -u -s -i 3' |\n");
printf(" | 4. Client: 'iperf -u -c SERVER_IP -t 60 -i 3' |\n");
printf(" | 5. Client: 'iperf -u -c SERVER_IP -t 60 -i 3' |\n");
printf(" | |\n");
printf(" =======================================================\n\n");
@ -170,7 +169,7 @@ void app_main()
}
/* Add the command to the history */
linenoiseHistoryAdd(line);
#if CONFIG_STORE_HISTORY
#if CONFIG_EXAMPLE_STORE_HISTORY
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
#endif

View file

@ -1,7 +1,3 @@
# Reduce bootloader log verbosity
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2
# Increase main task stack size
CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168
@ -10,7 +6,6 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_APP_OFFSET=0x10000
# Enable FreeRTOS stats formatting functions, needed for 'tasks' command
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
@ -21,7 +16,3 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# ESP32-specific
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
# Ethernet
CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE=y

View file

@ -34,10 +34,8 @@ In the `Example Connection Configuration` menu:
* Choose the network interface in `Connect using` option based on your board. Currently we support both Wi-Fi and Ethernet.
* If you have selected the Wi-Fi interface, you also have to set:
* Wi-Fi SSID and Wi-Fi password that your ESP32 will connect to
* If you have selected the Ethernet interface, you also have to set:
* PHY model in `Ethernet PHY` option, e.g. IP101
* PHY address in `PHY Address` option, which should be determined by your board schematic
* EMAC Clock mode, SMI GPIOs
* If you have selected the Ethernet interface, you also have to:
* Set PHY model under `Ethernet PHY Device` option, e.g. IP101.
In the `Example Configuration` menu: