mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/ethernet_lan8720' into 'master'
ethernet: Add LAN8720 phy support, move PHY to components Encompasses PR #383 https://github.com/espressif/esp-idf/pull/383 Also includes changes to move PHY support functions into ethernet component, similar to #398 https://github.com/espressif/esp-idf/pull/398/files. See merge request !540
This commit is contained in:
commit
90c8bd93e0
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
COMPONENT_SRCDIRS := . eth_phy
|
||||
|
@ -204,6 +204,25 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
|
||||
return value;
|
||||
}
|
||||
|
||||
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
|
||||
{
|
||||
unsigned start = xTaskGetTickCount();
|
||||
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
|
||||
uint16_t current_value = 0;
|
||||
|
||||
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
|
||||
current_value = esp_eth_smi_read(reg_num);
|
||||
if ((current_value & value_mask) == (value & value_mask)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
vTaskDelay(1);
|
||||
}
|
||||
ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x (mask 0x%04x). Current value 0x%04x",
|
||||
reg_num, value, value_mask, current_value);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
static void emac_set_user_config_data(eth_config_t *config )
|
||||
{
|
||||
emac_config.phy_addr = config->phy_addr;
|
||||
@ -532,7 +551,7 @@ static void emac_set_macaddr_reg(void)
|
||||
static void emac_check_phy_init(void)
|
||||
{
|
||||
emac_config.emac_phy_check_init();
|
||||
if (emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) {
|
||||
if (emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
|
||||
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
|
||||
} else {
|
||||
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
|
||||
@ -547,7 +566,7 @@ static void emac_check_phy_init(void)
|
||||
emac_config.emac_flow_ctrl_partner_support = false;
|
||||
#else
|
||||
if (emac_config.emac_flow_ctrl_enable == true) {
|
||||
if (emac_config.emac_phy_get_partner_pause_enable() == true && emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) {
|
||||
if (emac_config.emac_phy_get_partner_pause_enable() == true && emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
|
||||
emac_enable_flowctrl();
|
||||
emac_config.emac_flow_ctrl_partner_support = true;
|
||||
} else {
|
||||
@ -954,7 +973,7 @@ esp_err_t esp_eth_init(eth_config_t *config)
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
emac_config.emac_phy_power_enable(true);
|
||||
emac_config.emac_phy_power_enable(true);
|
||||
|
||||
//before set emac reg must enable clk
|
||||
emac_enable_clk(true);
|
||||
|
75
components/ethernet/eth_phy/phy_common.c
Normal file
75
components/ethernet/eth_phy/phy_common.c
Normal file
@ -0,0 +1,75 @@
|
||||
// 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)
|
||||
{
|
||||
gpio_matrix_out(mdc_gpio, EMAC_MDC_O_IDX, 0, 0);
|
||||
gpio_matrix_out(mdio_gpio, EMAC_MDO_O_IDX, 0, 0);
|
||||
gpio_matrix_in(mdio_gpio, EMAC_MDI_I_IDX, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
149
components/ethernet/eth_phy/phy_lan8720.c
Normal file
149
components/ethernet/eth_phy/phy_lan8720.c
Normal file
@ -0,0 +1,149 @@
|
||||
// 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_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_eth.h"
|
||||
|
||||
#include "eth_phy/phy_lan8720.h"
|
||||
#include "eth_phy/phy_reg.h"
|
||||
|
||||
/* Value of MII_PHY_IDENTIFIER_REGs for Microchip LAN8720
|
||||
* (Except for bottom 4 bits of ID2, used for model revision)
|
||||
*/
|
||||
#define LAN8720_PHY_ID1 0x0007
|
||||
#define LAN8720_PHY_ID2 0xc0f0
|
||||
#define LAN8720_PHY_ID2_MASK 0xFFF0
|
||||
|
||||
/* LAN8720-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_SPECIAL_CONTROL_STATUS_REG (0x1f)
|
||||
#define AUTO_NEGOTIATION_DONE BIT(12)
|
||||
#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
|
||||
#define SPEED_INDICATION_100T BIT(3)
|
||||
#define SPEED_INDICATION_10T BIT(2)
|
||||
#define DUPLEX_INDICATION_FULL BIT(4)
|
||||
|
||||
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) {
|
||||
esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
|
||||
// TODO: only enable if config.flow_ctrl_enable == true
|
||||
phy_mii_enable_flow_ctrl();
|
||||
}
|
||||
}
|
||||
|
||||
void 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;
|
||||
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, 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);
|
||||
} while(res1 != ESP_OK || res2 != ESP_OK);
|
||||
|
||||
esp_eth_smi_write(SW_STRAP_CONTROL_REG,
|
||||
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
|
||||
|
||||
|
||||
ets_delay_us(300);
|
||||
|
||||
// TODO: only enable if config.flow_ctrl_enable == true
|
||||
phy_mii_enable_flow_ctrl();
|
||||
}
|
||||
|
||||
const eth_config_t phy_lan8720_default_ethernet_config = {
|
||||
// By default, the PHY address is 0 or 1 based on PHYAD0
|
||||
// pin. Can also be overriden in software. See datasheet
|
||||
// for defaults.
|
||||
.phy_addr = 0,
|
||||
.mac_mode = ETH_MODE_RMII,
|
||||
//Only FULLDUPLEX mode support flow ctrl now!
|
||||
.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,
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
173
components/ethernet/eth_phy/phy_tlk110.c
Normal file
173
components/ethernet/eth_phy/phy_tlk110.c
Normal file
@ -0,0 +1,173 @@
|
||||
// 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_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_eth.h"
|
||||
|
||||
#include "eth_phy/phy_tlk110.h"
|
||||
#include "eth_phy/phy_reg.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
/* Value of MII_PHY_IDENTIFIER_REG for TI TLK110,
|
||||
Excluding bottom 4 bytes of ID2, used for model revision
|
||||
*/
|
||||
#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();
|
||||
}
|
||||
}
|
||||
|
||||
void 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;
|
||||
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, 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);
|
||||
} while(res1 != ESP_OK || res2 != ESP_OK);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
const eth_config_t phy_tlk110_default_ethernet_config = {
|
||||
// PHY address configured by PHYADx pins. Default value of 0x1
|
||||
// is used if all pins are unconnected.
|
||||
.phy_addr = 0x1,
|
||||
.mac_mode = ETH_MODE_RMII,
|
||||
//Only FULLDUPLEX mode support flow ctrl now!
|
||||
.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,
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
#ifndef __ESP_ETH_H__
|
||||
#define __ESP_ETH_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
@ -24,7 +25,7 @@ extern "C" {
|
||||
|
||||
typedef enum {
|
||||
ETH_MODE_RMII = 0,
|
||||
ETH_MDOE_MII,
|
||||
ETH_MODE_MII,
|
||||
} eth_mode_t;
|
||||
|
||||
typedef enum {
|
||||
@ -34,7 +35,7 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
ETH_MODE_HALFDUPLEX = 0,
|
||||
ETH_MDOE_FULLDUPLEX,
|
||||
ETH_MODE_FULLDUPLEX,
|
||||
} eth_duplex_mode_t;
|
||||
|
||||
typedef enum {
|
||||
@ -99,9 +100,10 @@ typedef struct {
|
||||
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 */
|
||||
|
||||
|
||||
} eth_config_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Init ethernet mac
|
||||
*
|
||||
@ -173,7 +175,7 @@ void esp_eth_get_mac(uint8_t mac[6]);
|
||||
void esp_eth_smi_write(uint32_t reg_num, uint16_t value);
|
||||
|
||||
/**
|
||||
* @brief Write phy reg with smi interface.
|
||||
* @brief Read phy reg with smi interface.
|
||||
*
|
||||
* @note phy base addr must be right.
|
||||
*
|
||||
@ -183,6 +185,35 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value);
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
59
components/ethernet/include/eth_phy/phy.h
Normal file
59
components/ethernet/include/eth_phy/phy.h
Normal file
@ -0,0 +1,59 @@
|
||||
// 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"
|
||||
|
||||
/* Common PHY-management functions.
|
||||
|
||||
These are not enough to drive any particular Ethernet PHY, but they provide a common configuration structure and
|
||||
management functions.
|
||||
*/
|
||||
|
||||
/* Configure fixed pins for RMII data interface.
|
||||
|
||||
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);
|
||||
|
||||
/* Configure variable pins for SMI (MDIO) ethernet functions.
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/* Enable flow control in standard PHY MII register.
|
||||
*/
|
||||
void phy_mii_enable_flow_ctrl(void);
|
||||
|
||||
bool phy_mii_check_link_status(void);
|
||||
|
||||
bool phy_mii_get_partner_pause_enable(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
67
components/ethernet/include/eth_phy/phy_lan8720.h
Normal file
67
components/ethernet/include/eth_phy/phy_lan8720.h
Normal file
@ -0,0 +1,67 @@
|
||||
// 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 all LAN8720 PHY SMI configuration registers
|
||||
*
|
||||
* @note These registers are dumped at 'debug' level, so output
|
||||
* may not be visible depending on default log levels.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
eth_speed_mode_t phy_lan8720_get_speed_mode(void);
|
||||
|
||||
/* @brief Default LAN8720 phy_get_duplex_mode function.
|
||||
*/
|
||||
eth_duplex_mode_t phy_lan8720_get_duplex_mode(void);
|
||||
|
||||
/* @brief Default LAN8720 phy_power_enable function.
|
||||
*
|
||||
* @note This function may need to be replaced with a custom function
|
||||
* if the PHY has a GPIO to enable power or start a clock.
|
||||
*
|
||||
* Consult the ethernet example to see how this is done.
|
||||
*/
|
||||
void phy_lan8720_power_enable(bool);
|
||||
|
||||
/* @brief Default LAN8720 phy_init function.
|
||||
*/
|
||||
void phy_lan8720_init(void);
|
||||
|
||||
/* @brief Default LAN8720 PHY configuration
|
||||
*
|
||||
* This configuration is not suitable for use as-is, it will need
|
||||
* to be modified for your particular PHY hardware setup.
|
||||
*
|
||||
* Consult the Ethernet example to see how this is done.
|
||||
*/
|
||||
extern const eth_config_t phy_lan8720_default_ethernet_config;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
37
components/ethernet/include/eth_phy/phy_reg.h
Normal file
37
components/ethernet/include/eth_phy/phy_reg.h
Normal file
@ -0,0 +1,37 @@
|
||||
// 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
|
||||
|
||||
/* 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_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_NEG_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)
|
66
components/ethernet/include/eth_phy/phy_tlk110.h
Normal file
66
components/ethernet/include/eth_phy/phy_tlk110.h
Normal file
@ -0,0 +1,66 @@
|
||||
// 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 all TLK110 PHY SMI configuration registers
|
||||
*
|
||||
* @note These registers are dumped at 'debug' level, so output
|
||||
* may not be visible depending on default log levels.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
eth_speed_mode_t phy_tlk110_get_speed_mode(void);
|
||||
|
||||
/* @brief Default TLK110 phy_get_duplex_mode function.
|
||||
*/
|
||||
eth_duplex_mode_t phy_tlk110_get_duplex_mode(void);
|
||||
|
||||
/* @brief Default TLK110 phy_power_enable function.
|
||||
*
|
||||
* @note This function may need to be replaced with a custom function
|
||||
* if the PHY has a GPIO to enable power or start a clock.
|
||||
*
|
||||
* Consult the ethernet example to see how this is done.
|
||||
*/
|
||||
void phy_tlk110_power_enable(bool);
|
||||
|
||||
/* @brief Default TLK110 phy_init function.
|
||||
*/
|
||||
void phy_tlk110_init(void);
|
||||
|
||||
/* @brief Default TLK110 PHY configuration
|
||||
*
|
||||
* This configuration is not suitable for use as-is, it will need
|
||||
* to be modified for your particular PHY hardware setup.
|
||||
*
|
||||
* Consult the Ethernet example to see how this is done.
|
||||
*/
|
||||
extern const eth_config_t phy_tlk110_default_ethernet_config;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -13,10 +13,17 @@ Header Files
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* :component_file:`ethernet/include/esp_eth.h`
|
||||
* :component_file:`ethernet/include/phy/phy.h`
|
||||
|
||||
Macros
|
||||
^^^^^^
|
||||
PHY Interfaces
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The configured PHY model(s) are set in software by configuring the eth_config_t structure for the given PHY.
|
||||
|
||||
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.
|
||||
|
||||
* :component_file:`ethernet/include/phy/phy_tlk110.h`
|
||||
* :component_file:`ethernet/include/phy/phy_lan8720.h`
|
||||
|
||||
Type Definitions
|
||||
^^^^^^^^^^^^^^^^
|
||||
@ -55,4 +62,13 @@ Functions
|
||||
.. doxygenfunction:: esp_eth_get_mac
|
||||
.. doxygenfunction:: esp_eth_smi_write
|
||||
.. doxygenfunction:: esp_eth_smi_read
|
||||
.. doxygenfunction:: esp_eth_smi_wait_value
|
||||
.. doxygenfunction:: esp_eth_smi_wait_set
|
||||
.. doxygenfunction:: esp_eth_free_rx_buf
|
||||
|
||||
|
||||
PHY Configuration Constants
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. doxygenvariable:: phy_tlk110_default_ethernet_config
|
||||
.. doxygenvariable:: phy_lan8720_default_ethernet_config
|
||||
|
@ -1,6 +1,56 @@
|
||||
# ethernet Example
|
||||
# Ethernet Example
|
||||
|
||||
Init ethernet interface and enable it ,then you can ping it if it got ip address.
|
||||
Initialises the ethernet interface and enables it, then sends DHCP requests and tries to obtain a DHCP lease. If successful then you will be able to ping the device.
|
||||
|
||||
# PHY Configuration
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
||||
Use "make menuconfig" to set the PHY model and the PHY address, and configure the SMI I/O pins (see below). These configuration items will vary depending on the hardware configuration you are using.
|
||||
|
||||
The default example configuration is correct for Espressif's Ethernet board with TLK110 PHY. Other hardware will require different configuration and/or changes to the example.
|
||||
|
||||
## PHY Address
|
||||
|
||||
The PHY address depends on the hardware and the PHY configuration. Consult the documentation/datasheet for the PHY hardware you have.
|
||||
|
||||
* Default address 31 is correct for Espressif's Ethernet board with TLK110 PHY.
|
||||
* Address 1 is correct for the common Waveshare LAN8720 PHY breakout.
|
||||
* Other LAN8720 breakouts may take address 0.
|
||||
|
||||
If the PHY address is incorrect then the EMAC will initialise but all attempts to read/write configuration registers on the PHY will fail.
|
||||
|
||||
## RMII PHY Wiring
|
||||
|
||||
The following PHY connections are required for RMII PHY data connections. These GPIO pin assignments cannot be changed.
|
||||
|
||||
| GPIO | RMII Signal | ESP32 EMAC Function | Notes |
|
||||
| ------- | ----------- | ------------------- | ----- |
|
||||
| 0 | REF_CLK | EMAC_TX_CLK | Currently this must be a 50MHz reference clock input from the PHY (ext_osc configuration). |
|
||||
| 21 | TX_EN | EMAC_TX_EN | |
|
||||
| 19 | TX0 | EMAC_TXD0 | |
|
||||
| 22 | TX1 | EMAC_TXD1 | |
|
||||
| 25 | RX0 | EMAC_RXD0 | |
|
||||
| 26 | RX1 | EMAC_RXD1 | |
|
||||
| 27 | CRS_DV | EMAC_RX_DRV | |
|
||||
|
||||
## RMII PHY SMI Wiring
|
||||
|
||||
The following PHY connections are required for RMII PHY SMI (aka MDIO) management interface. These GPIO pin assignments can be changed to any unused GPIO pin.
|
||||
|
||||
For the example, these pins are configured via `make menuconfig` under the Example configuration.
|
||||
|
||||
| Default Example GPIO | RMII Signal | Notes |
|
||||
| -------------------- | ----------- | ------------- |
|
||||
| 23 | MDC | Output to PHY |
|
||||
| 18 | MDIO | Bidirectional |
|
||||
|
||||
The defaults in the example are correct for Espressif's Ethernet development board.
|
||||
|
||||
## Note about GPIO0
|
||||
|
||||
Because GPIO0 is a strapping pin for entering UART flashing mode on reset, care must be taken when also 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.
|
||||
|
||||
The example defaults to using GPIO 17 for this function, but it can be overriden. On Espressif's Ethernet development board, GPIO 17 is the power pin used to enable/disable the PHY oscillator.
|
||||
|
54
examples/ethernet/ethernet/main/Kconfig.projbuild
Normal file
54
examples/ethernet/ethernet/main/Kconfig.projbuild
Normal file
@ -0,0 +1,54 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice PHY_MODEL
|
||||
prompt "Ethernet PHY"
|
||||
default CONFIG_PHY_TLK110
|
||||
help
|
||||
Select the PHY driver to use for the example.
|
||||
|
||||
config PHY_TLK110
|
||||
bool "TI TLK110 PHY"
|
||||
help
|
||||
Select this to use the TI TLK110 PHY
|
||||
|
||||
config PHY_LAN8720
|
||||
bool "Microchip LAN8720 PHY"
|
||||
help
|
||||
Select this to use the Microchip LAN8720 PHY
|
||||
|
||||
endchoice
|
||||
|
||||
config PHY_ADDRESS
|
||||
int "PHY Address (0-31)"
|
||||
default 31
|
||||
range 0 31
|
||||
help
|
||||
Select the PHY Address (0-31) for the hardware configuration and PHY model.
|
||||
|
||||
config 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.
|
||||
Consult the example README for more details
|
||||
|
||||
config PHY_POWER_PIN
|
||||
int "PHY Power GPIO"
|
||||
default 17
|
||||
depends on PHY_USE_POWER_PIN
|
||||
help
|
||||
GPIO number to use for powering on/off the PHY.
|
||||
|
||||
config PHY_SMI_MDC_PIN
|
||||
int "SMI MDC Pin"
|
||||
default 23
|
||||
help
|
||||
GPIO number to use for SMI clock output MDC to PHY.
|
||||
|
||||
config PHY_SMI_MDIO_PIN
|
||||
int "SMI MDIO Pin"
|
||||
default 18
|
||||
help
|
||||
GPIO number to use for SMI data pin MDIO to/from PHY.
|
||||
|
||||
endmenu
|
@ -32,110 +32,70 @@
|
||||
#include "tcpip_adapter.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "tlk110_phy.h"
|
||||
|
||||
#ifdef CONFIG_PHY_LAN8720
|
||||
#include "eth_phy/phy_lan8720.h"
|
||||
#define DEFAULT_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
|
||||
#endif
|
||||
#ifdef CONFIG_PHY_TLK110
|
||||
#include "eth_phy/phy_tlk110.h"
|
||||
#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
|
||||
#endif
|
||||
|
||||
static const char *TAG = "eth_example";
|
||||
|
||||
#define DEFAULT_PHY_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG)
|
||||
#define PIN_PHY_POWER 17
|
||||
#define PIN_SMI_MDC 23
|
||||
#define PIN_SMI_MDIO 18
|
||||
#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
|
||||
|
||||
void phy_tlk110_check_phy_init(void)
|
||||
{
|
||||
while((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & AUTO_NEGOTIATION_COMPLETE ) != AUTO_NEGOTIATION_COMPLETE)
|
||||
{};
|
||||
while((esp_eth_smi_read(PHY_STATUS_REG) & AUTO_NEGOTIATION_STATUS ) != AUTO_NEGOTIATION_STATUS)
|
||||
{};
|
||||
while((esp_eth_smi_read(CABLE_DIAGNOSTIC_CONTROL_REG) & DIAGNOSTIC_DONE ) != DIAGNOSTIC_DONE)
|
||||
{};
|
||||
}
|
||||
#ifdef CONFIG_PHY_USE_POWER_PIN
|
||||
/* This replaces the default PHY power on/off function with one that
|
||||
also uses a GPIO for power on/off.
|
||||
|
||||
eth_speed_mode_t phy_tlk110_get_speed_mode(void)
|
||||
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 rather than overriding with this one.
|
||||
*/
|
||||
static void phy_device_power_enable_via_gpio(bool enable)
|
||||
{
|
||||
if((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS ) != SPEED_STATUS) {
|
||||
return ETH_SPEED_MODE_100M;
|
||||
} else {
|
||||
return ETH_SPEED_MODE_10M;
|
||||
}
|
||||
}
|
||||
assert(DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable);
|
||||
|
||||
eth_duplex_mode_t phy_tlk110_get_duplex_mode(void)
|
||||
{
|
||||
if((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS ) == DUPLEX_STATUS) {
|
||||
return ETH_MDOE_FULLDUPLEX;
|
||||
} else {
|
||||
return ETH_MODE_HALFDUPLEX;
|
||||
}
|
||||
}
|
||||
if (!enable) {
|
||||
/* Do the PHY-specific power_enable(false) function before powering down */
|
||||
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false);
|
||||
}
|
||||
|
||||
bool phy_tlk110_check_phy_link_status(void)
|
||||
{
|
||||
return ((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & LINK_STATUS) == LINK_STATUS );
|
||||
}
|
||||
|
||||
bool phy_tlk110_get_partner_pause_enable(void)
|
||||
{
|
||||
if((esp_eth_smi_read(PHY_LINK_PARTNER_ABILITY_REG) & PARTNER_PAUSE) == PARTNER_PAUSE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void phy_enable_flow_ctrl(void)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
data = esp_eth_smi_read(AUTO_NEG_ADVERTISEMENT_REG);
|
||||
esp_eth_smi_write(AUTO_NEG_ADVERTISEMENT_REG,data|ASM_DIR|PAUSE);
|
||||
}
|
||||
|
||||
void phy_tlk110_power_enable(bool enable)
|
||||
{
|
||||
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_LOGD(TAG, "phy_device_power_enable(TRUE)");
|
||||
} else {
|
||||
gpio_set_level(PIN_PHY_POWER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void phy_tlk110_init(void)
|
||||
{
|
||||
esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET);
|
||||
|
||||
while (esp_eth_smi_read(PHY_IDENTIFIER_REG) != OUI_MSB_21TO6_DEF) {
|
||||
ESP_LOGD(TAG, "power_enable(FALSE)");
|
||||
}
|
||||
|
||||
esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_PHY_CONFIG | SW_STRAP_CONFIG_DONE);
|
||||
|
||||
ets_delay_us(300);
|
||||
// Allow the power up/down to take effect, min 300us
|
||||
vTaskDelay(1);
|
||||
|
||||
//if config.flow_ctrl_enable == true ,enable this
|
||||
phy_enable_flow_ctrl();
|
||||
if (enable) {
|
||||
/* Run the PHY-specific power on operations now the PHY has power */
|
||||
DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void eth_gpio_config_rmii(void)
|
||||
static void eth_gpio_config_rmii(void)
|
||||
{
|
||||
//txd0 to gpio19 ,can not change
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
|
||||
//tx_en to gpio21 ,can not change
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
|
||||
//txd1 to gpio22 , can not change
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
|
||||
//rxd0 to gpio25 , can not change
|
||||
gpio_set_direction(25, GPIO_MODE_INPUT);
|
||||
//rxd1 to gpio26 ,can not change
|
||||
gpio_set_direction(26, GPIO_MODE_INPUT);
|
||||
//rmii clk ,can not change
|
||||
gpio_set_direction(0, GPIO_MODE_INPUT);
|
||||
|
||||
//mdc to gpio23
|
||||
gpio_matrix_out(PIN_SMI_MDC, EMAC_MDC_O_IDX, 0, 0);
|
||||
//mdio to gpio18
|
||||
gpio_matrix_out(PIN_SMI_MDIO, EMAC_MDO_O_IDX, 0, 0);
|
||||
gpio_matrix_in(PIN_SMI_MDIO, EMAC_MDI_I_IDX, 0);
|
||||
// RMII data pins are fixed:
|
||||
// TXD0 = GPIO19
|
||||
// TXD1 = GPIO22
|
||||
// TX_EN = GPIO21
|
||||
// RXD0 = GPIO25
|
||||
// RXD1 = GPIO26
|
||||
// CLK == GPIO0
|
||||
phy_rmii_configure_data_interface_pins();
|
||||
// MDC is GPIO 23, MDIO is GPIO 18
|
||||
phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO);
|
||||
}
|
||||
|
||||
void eth_task(void *pvParameter)
|
||||
@ -149,11 +109,11 @@ void eth_task(void *pvParameter)
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
|
||||
if (tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip) == 0) {
|
||||
ESP_LOGI(TAG, "\n~~~~~~~~~~~\n");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "ETHIP:"IPSTR, IP2STR(&ip.ip));
|
||||
ESP_LOGI(TAG, "ETHPMASK:"IPSTR, IP2STR(&ip.netmask));
|
||||
ESP_LOGI(TAG, "ETHPGW:"IPSTR, IP2STR(&ip.gw));
|
||||
ESP_LOGI(TAG, "\n~~~~~~~~~~~\n");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,20 +124,17 @@ void app_main()
|
||||
tcpip_adapter_init();
|
||||
esp_event_loop_init(NULL, NULL);
|
||||
|
||||
eth_config_t config;
|
||||
config.phy_addr = PHY31;
|
||||
config.mac_mode = ETH_MODE_RMII;
|
||||
config.phy_init = phy_tlk110_init;
|
||||
eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG;
|
||||
/* Set the PHY address in the example configuration */
|
||||
config.phy_addr = CONFIG_PHY_ADDRESS;
|
||||
config.gpio_config = eth_gpio_config_rmii;
|
||||
config.tcpip_input = tcpip_adapter_eth_input;
|
||||
config.phy_check_init = phy_tlk110_check_phy_init;
|
||||
config.phy_check_link = phy_tlk110_check_phy_link_status;
|
||||
config.phy_get_speed_mode = phy_tlk110_get_speed_mode;
|
||||
config.phy_get_duplex_mode = phy_tlk110_get_duplex_mode;
|
||||
//Only FULLDUPLEX mode support flow ctrl now!
|
||||
config.flow_ctrl_enable = true;
|
||||
config.phy_get_partner_pause_enable = phy_tlk110_get_partner_pause_enable;
|
||||
config.phy_power_enable = phy_tlk110_power_enable;
|
||||
|
||||
#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
|
||||
|
||||
ret = esp_eth_init(&config);
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
#define BASIC_MODE_STATUS_REG (0x1)
|
||||
#define AUTO_NEGOTIATION_COMPLETE BIT(5)
|
||||
#define LINK_STATUS BIT(2)
|
||||
|
||||
#define PHY_IDENTIFIER_REG (0x2)
|
||||
#define OUI_MSB_21TO6_DEF 0x2000
|
||||
|
||||
#define AUTO_NEG_ADVERTISEMENT_REG (0x4)
|
||||
#define ASM_DIR BIT(11)
|
||||
#define PAUSE BIT(10)
|
||||
|
||||
#define PHY_LINK_PARTNER_ABILITY_REG (0x5)
|
||||
#define PARTNER_ASM_DIR BIT(11)
|
||||
#define PARTNER_PAUSE BIT(10)
|
||||
|
||||
#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 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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user