Merge branch 'feature/support_spi_ethernet' into 'master'
ethernet: support dm9051 Closes IDFGH-1443 and IDFGH-1439 See merge request espressif/esp-idf!5345
This commit is contained in:
commit
8bed3a3dd2
23 changed files with 1945 additions and 256 deletions
|
@ -8,6 +8,11 @@ if(CONFIG_IDF_TARGET_ESP32)
|
|||
list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ETH_SPI_ETHERNET_DM9051)
|
||||
list(APPEND esp_eth_srcs "src/esp_eth_mac_dm9051.c"
|
||||
"src/esp_eth_phy_dm9051.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${esp_eth_srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
LDFRAGMENTS "linker.lf"
|
||||
|
|
|
@ -2,7 +2,7 @@ menu "Ethernet"
|
|||
|
||||
menuconfig ETH_USE_ESP32_EMAC
|
||||
depends on IDF_TARGET_ESP32
|
||||
bool "Use ESP32 internal EMAC controller"
|
||||
bool "Support ESP32 internal EMAC controller"
|
||||
default y
|
||||
help
|
||||
ESP32 integrates a 10/100M Ethernet MAC controller.
|
||||
|
@ -128,4 +128,29 @@ menu "Ethernet"
|
|||
Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE.
|
||||
Larger number of buffers could increase throughput somehow.
|
||||
endif
|
||||
|
||||
menuconfig ETH_USE_SPI_ETHERNET
|
||||
bool "Support SPI to Ethernet Module"
|
||||
default y
|
||||
help
|
||||
ESP-IDF can also support some SPI-Ethernet module.
|
||||
|
||||
if ETH_USE_SPI_ETHERNET
|
||||
menuconfig ETH_SPI_ETHERNET_DM9051
|
||||
bool "Use DM9051"
|
||||
default y
|
||||
help
|
||||
DM9051 is a fast Ethernet controller with an SPI interface.
|
||||
It's also integrated with a 10/100M PHY and MAC.
|
||||
Set true to enable DM9051 driver.
|
||||
|
||||
if ETH_SPI_ETHERNET_DM9051
|
||||
config ETH_DM9051_INT_GPIO
|
||||
int "DM9051 Interrupt GPIO number"
|
||||
default 4
|
||||
range 0 33
|
||||
help
|
||||
Set the GPIO number used by DM9051's Interrupt pin.
|
||||
endif
|
||||
endif
|
||||
endmenu
|
||||
|
|
|
@ -8,3 +8,7 @@ COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
|||
ifndef CONFIG_IDF_TARGET_ESP32
|
||||
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o
|
||||
endif
|
||||
|
|
|
@ -20,6 +20,11 @@ extern "C" {
|
|||
#include <stdbool.h>
|
||||
#include "esp_eth_com.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Ethernet MAC
|
||||
|
@ -115,6 +120,7 @@ struct esp_eth_mac_s {
|
|||
* - 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_ERR_TIMEOUT: read PHY register failed because of timeout
|
||||
* - ESP_FAIL: read PHY register failed because some other error occurred
|
||||
*
|
||||
*/
|
||||
|
@ -131,6 +137,7 @@ struct esp_eth_mac_s {
|
|||
* @return
|
||||
* - ESP_OK: write PHY register successfully
|
||||
* - ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC
|
||||
* - ESP_ERR_TIMEOUT: write PHY register failed because of timeout
|
||||
* - ESP_FAIL: write PHY register failed because some other error occurred
|
||||
*
|
||||
*/
|
||||
|
@ -241,6 +248,10 @@ typedef struct {
|
|||
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 */
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
spi_device_handle_t spi_hdl; /*!< Handle of spi device */
|
||||
#endif
|
||||
|
||||
} eth_mac_config_t;
|
||||
|
||||
/**
|
||||
|
@ -255,6 +266,7 @@ typedef struct {
|
|||
.queue_len = 100, \
|
||||
}
|
||||
|
||||
#if CONFIG_ETH_USE_ESP32_EMAC
|
||||
/**
|
||||
* @brief Create ESP32 Ethernet MAC instance
|
||||
*
|
||||
|
@ -265,7 +277,20 @@ typedef struct {
|
|||
* - NULL: create MAC instance failed because some error occurred
|
||||
*/
|
||||
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
/**
|
||||
* @brief Create DM9051 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_dm9051(const eth_mac_config_t *config);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -222,6 +222,18 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config);
|
|||
*/
|
||||
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config);
|
||||
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
/**
|
||||
* @brief Create a PHY instance of DM9051
|
||||
*
|
||||
* @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_dm9051(const eth_phy_config_t *config);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
[mapping:esp_eth]
|
||||
archive: libesp_eth.a
|
||||
entries:
|
||||
if ETH_USE_ESP32_EMAC = y:
|
||||
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)
|
||||
if ETH_SPI_ETHERNET_DM9051 = y:
|
||||
esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text)
|
||||
|
|
852
components/esp_eth/src/esp_eth_mac_dm9051.c
Normal file
852
components/esp_eth/src/esp_eth_mac_dm9051.c
Normal file
|
@ -0,0 +1,852 @@
|
|||
// 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/gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "emac_dm9051";
|
||||
#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 (100)
|
||||
#define DM9051_SPI_LOCK_TIMEOUT_MS (50)
|
||||
#define DM9051_PHY_OPERATION_TIMEOUT_US (1000)
|
||||
|
||||
/**
|
||||
* @brief Registers in DM9051
|
||||
*
|
||||
*/
|
||||
#define DM9051_NCR (0x00) // Network Control Register
|
||||
#define DM9051_NSR (0x01) // Network Status Register
|
||||
#define DM9051_TCR (0x02) // Tx Control Register
|
||||
#define DM9051_TSR1 (0x03) // Tx Status Register I
|
||||
#define DM9051_TSR2 (0x04) // Tx Status Register II
|
||||
#define DM9051_RCR (0x05) // Rx Control Register
|
||||
#define DM9051_RSR (0x06) // Rx Status Register
|
||||
#define DM9051_ROCR (0x07) // Receive Overflow Counter Register
|
||||
#define DM9051_BPTR (0x08) // Back Pressure Threshold Register
|
||||
#define DM9051_FCTR (0x09) // Flow Control Threshold Register
|
||||
#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register
|
||||
#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register
|
||||
#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register
|
||||
#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low
|
||||
#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High
|
||||
#define DM9051_WCR (0x0F) // Wake Up Control Register
|
||||
#define DM9051_PAR (0x10) // Physical Address Register
|
||||
#define DM9051_MAR (0x16) // Multicast Address Hash Table Register
|
||||
#define DM9051_GPCR (0x1E) // General Purpose Control Register
|
||||
#define DM9051_GPR (0x1F) // General Purpose Register
|
||||
#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte
|
||||
#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte
|
||||
#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte
|
||||
#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte
|
||||
#define DM9051_VIDL (0x28) // Vendor ID Low Byte
|
||||
#define DM9051_VIDH (0x29) // Vendor ID High Byte
|
||||
#define DM9051_PIDL (0x2A) // Product ID Low Byte
|
||||
#define DM9051_PIDH (0x2B) // Product ID High Byte
|
||||
#define DM9051_CHIPR (0x2C) // CHIP Revision
|
||||
#define DM9051_TCR2 (0x2D) // Transmit Control Register 2
|
||||
#define DM9051_ATCR (0x30) // Auto-Transmit Control Register
|
||||
#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register
|
||||
#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register
|
||||
#define DM9051_SBCR (0x38) // SPI Bus Control Register
|
||||
#define DM9051_INTCR (0x39) // INT Pin Control Register
|
||||
#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register
|
||||
#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register
|
||||
#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register
|
||||
#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register
|
||||
#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register
|
||||
#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register
|
||||
#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register
|
||||
#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register
|
||||
#define DM9051_MLEDCR (0x57) // More LED Control Register
|
||||
#define DM9051_MEMSCR (0x59) // Memory Control Register
|
||||
#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register
|
||||
#define DM9051_MBSR (0x5D) // Memory BIST Status Register
|
||||
#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register
|
||||
#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register
|
||||
#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register
|
||||
#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register
|
||||
#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte
|
||||
#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte
|
||||
#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register
|
||||
#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register
|
||||
#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte
|
||||
#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte
|
||||
#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register
|
||||
#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register
|
||||
#define DM9051_ISR (0x7E) // Interrupt Status Register
|
||||
#define DM9051_IMR (0x7F) // Interrupt Mask Register
|
||||
|
||||
/**
|
||||
* @brief status and flag of DM9051 specific registers
|
||||
*
|
||||
*/
|
||||
#define DM9051_SPI_RD (0) // Burst Read Command
|
||||
#define DM9051_SPI_WR (1) // Burst Write Command
|
||||
|
||||
#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function
|
||||
#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY
|
||||
#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us
|
||||
|
||||
#define NSR_SPEED (1 << 7) // Speed of Internal PHY
|
||||
#define NSR_LINKST (1 << 6) // Link Status of Internal PHY
|
||||
#define NSR_WAKEST (1 << 5) // Wakeup Event Status
|
||||
#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status
|
||||
#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status
|
||||
#define NSR_RXOV (1 << 1) // RX Memory Overflow Status
|
||||
#define NSR_RXRDY (1 << 0) // RX Packet Ready
|
||||
|
||||
#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely
|
||||
|
||||
#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable
|
||||
#define RCR_DIS_LONG (1 << 5) // Discard Long Packet
|
||||
#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet
|
||||
#define RCR_ALL (1 << 3) // Receive All Multicast
|
||||
#define RCR_RUNT (1 << 2) // Receive Runt Packet
|
||||
#define RCR_PRMSC (1 << 1) // Promiscuous Mode
|
||||
#define RCR_RXEN (1 << 0) // RX Enable
|
||||
|
||||
#define RSR_RF (1 << 7) // Runt Frame
|
||||
#define RSR_MF (1 << 6) // Multicast Frame
|
||||
#define RSR_LCS (1 << 5) // Late Collision Seen
|
||||
#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out
|
||||
#define RSR_PLE (1 << 3) // Physical Layer Error
|
||||
#define RSR_AE (1 << 2) // Alignment Error
|
||||
#define RSR_CE (1 << 1) // CRC Error
|
||||
#define RSR_FOE (1 << 0) // RX Memory Overflow Error
|
||||
|
||||
#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control
|
||||
|
||||
#define EPCR_REEP (1 << 5) // Reload EEPROM
|
||||
#define EPCR_WEP (1 << 4) // Write EEPROM Enable
|
||||
#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select
|
||||
#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command
|
||||
#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command
|
||||
#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status
|
||||
|
||||
#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet
|
||||
|
||||
#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control
|
||||
|
||||
#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation
|
||||
#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation
|
||||
#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation
|
||||
|
||||
#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer
|
||||
#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer
|
||||
|
||||
#define ISR_LNKCHGS (1 << 5) // Link Status Change
|
||||
#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow
|
||||
#define ISR_ROS (1 << 2) // Receive Overflow
|
||||
#define ISR_PT (1 << 1) // Packet Transmitted
|
||||
#define ISR_PR (1 << 0) // Packet Received
|
||||
#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR)
|
||||
|
||||
#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode
|
||||
#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt
|
||||
#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt
|
||||
#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt
|
||||
#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt
|
||||
#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt
|
||||
#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI)
|
||||
|
||||
typedef struct {
|
||||
uint8_t flag;
|
||||
uint8_t status;
|
||||
uint8_t length_low;
|
||||
uint8_t length_high;
|
||||
} dm9051_rx_header_t;
|
||||
|
||||
typedef struct {
|
||||
esp_eth_mac_t parent;
|
||||
esp_eth_mediator_t *eth;
|
||||
spi_device_handle_t spi_hdl;
|
||||
SemaphoreHandle_t spi_lock;
|
||||
TaskHandle_t rx_task_hdl;
|
||||
uint32_t sw_reset_timeout_ms;
|
||||
uint8_t addr[6];
|
||||
bool packets_remain;
|
||||
} emac_dm9051_t;
|
||||
|
||||
static inline bool dm9051_lock(emac_dm9051_t *emac)
|
||||
{
|
||||
return xSemaphoreTake(emac->spi_lock, DM9051_SPI_LOCK_TIMEOUT_MS) == pdTRUE;
|
||||
}
|
||||
|
||||
static inline bool dm9051_unlock(emac_dm9051_t *emac)
|
||||
{
|
||||
return xSemaphoreGive(emac->spi_lock) == pdTRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write value to dm9051 internal register
|
||||
*/
|
||||
static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
spi_transaction_t trans = {
|
||||
.cmd = DM9051_SPI_WR,
|
||||
.addr = reg_addr,
|
||||
.length = 8,
|
||||
.flags = SPI_TRANS_USE_TXDATA
|
||||
};
|
||||
trans.tx_data[0] = value;
|
||||
if (dm9051_lock(emac)) {
|
||||
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
dm9051_unlock(emac);
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read value from dm9051 internal register
|
||||
*/
|
||||
static esp_err_t dm9051_register_read(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t *value)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
spi_transaction_t trans = {
|
||||
.cmd = DM9051_SPI_RD,
|
||||
.addr = reg_addr,
|
||||
.length = 8,
|
||||
.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA
|
||||
};
|
||||
if (dm9051_lock(emac)) {
|
||||
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
|
||||
ret = ESP_FAIL;
|
||||
} else {
|
||||
*value = trans.rx_data[0];
|
||||
}
|
||||
dm9051_unlock(emac);
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write buffer to dm9051 internal memory
|
||||
*/
|
||||
static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
spi_transaction_t trans = {
|
||||
.cmd = DM9051_SPI_WR,
|
||||
.addr = DM9051_MWCMD,
|
||||
.length = len * 8,
|
||||
.tx_buffer = buffer
|
||||
};
|
||||
if (dm9051_lock(emac)) {
|
||||
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
dm9051_unlock(emac);
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read buffer from dm9051 internal memory
|
||||
*/
|
||||
static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
spi_transaction_t trans = {
|
||||
.cmd = DM9051_SPI_RD,
|
||||
.addr = DM9051_MRCMD,
|
||||
.length = len * 8,
|
||||
.rx_buffer = buffer
|
||||
};
|
||||
if (dm9051_lock(emac)) {
|
||||
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
dm9051_unlock(emac);
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read mac address from internal registers
|
||||
*/
|
||||
static esp_err_t dm9051_get_mac_addr(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_PAR + i, &emac->addr[i]) == ESP_OK, "read PAR failed", err, ESP_FAIL);
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set new mac address to internal registers
|
||||
*/
|
||||
static esp_err_t dm9051_set_mac_addr(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_PAR + i, emac->addr[i]) == ESP_OK, "write PAR failed", err, ESP_FAIL);
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief clear multicast hash table
|
||||
*/
|
||||
static esp_err_t dm9051_clear_multicast_table(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* rx broadcast packet control by bit7 of MAC register 1DH */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_BCASTCR, 0x00) == ESP_OK, "write BCASTCR failed", err, ESP_FAIL);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + i, 0x00) == ESP_OK, "write MAR failed", err, ESP_FAIL);
|
||||
}
|
||||
/* enable receive broadcast paclets */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + 7, 0x80) == ESP_OK, "write MAR failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief software reset dm9051 internal register
|
||||
*/
|
||||
static esp_err_t dm9051_reset(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* power on phy */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_GPR, 0x00) == ESP_OK, "write GPR failed", err, ESP_FAIL);
|
||||
/* mac and phy register won't be accesable within at least 1ms */
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
/* software reset */
|
||||
uint8_t ncr = NCR_RST;
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, ncr) == ESP_OK, "write NCR failed", err, ESP_FAIL);
|
||||
uint32_t to = 0;
|
||||
for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL);
|
||||
if (!(ncr & NCR_RST)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief verify dm9051 chip ID
|
||||
*/
|
||||
static esp_err_t dm9051_verify_id(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t id[2];
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_VIDL, &id[0]) == ESP_OK, "read VIDL failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_VIDH, &id[1]) == ESP_OK, "read VIDH failed", err, ESP_FAIL);
|
||||
MAC_CHECK(0x0A46 == *(uint16_t *)id, "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_PIDL, &id[0]) == ESP_OK, "read PIDL failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_PIDH, &id[1]) == ESP_OK, "read PIDH failed", err, ESP_FAIL);
|
||||
MAC_CHECK(0x9051 == *(uint16_t *)id, "wrong Product ID", err, ESP_ERR_INVALID_VERSION);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief default setup for dm9051 internal registers
|
||||
*/
|
||||
static esp_err_t dm9051_setup_default(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* disable wakeup */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, 0x00) == ESP_OK, "write NCR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_WCR, 0x00) == ESP_OK, "write WCR failed", err, ESP_FAIL);
|
||||
/* stop transmitting, enable appending pad, crc for packets */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, 0x00) == ESP_OK, "write TCR failed", err, ESP_FAIL);
|
||||
/* stop receiving, no promiscuous mode, no runt packet(size < 64bytes), not all multicast packets*/
|
||||
/* discard long packet(size > 1522bytes) and crc error packet, enable watchdog */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, RCR_DIS_LONG | RCR_DIS_CRC) == ESP_OK, "write RCR failed", err, ESP_FAIL);
|
||||
/* send jam pattern (duration time = 1.15ms) when rx free space < 3k bytes */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_BPTR, 0x3F) == ESP_OK, "write BPTR failed", err, ESP_FAIL);
|
||||
/* flow control: high water threshold = 3k bytes, low water threshold = 8k bytes */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_FCTR, 0x38) == ESP_OK, "write FCTR failed", err, ESP_FAIL);
|
||||
/* enable flow control */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_FCR, FCR_FLOW_ENABLE) == ESP_OK, "write FCR failed", err, ESP_FAIL);
|
||||
/* retry late collision packet, at most two transmit command can be issued before transmit complete */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_TCR2, TCR2_RLCP) == ESP_OK, "write TCR2 failed", err, ESP_FAIL);
|
||||
/* enable auto transmit */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_ATCR, ATCR_AUTO_TX) == ESP_OK, "write ATCR failed", err, ESP_FAIL);
|
||||
/* generate checksum for UDP, TCP and IPv4 packets */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_TCSCR, TCSCR_IPCSE | TCSCR_TCPCSE | TCSCR_UDPCSE) == ESP_OK,
|
||||
"write TCSCR failed", err, ESP_FAIL);
|
||||
/* disable check sum for receive packets */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_RCSCSR, 0x00) == ESP_OK, "write RCSCSR failed", err, ESP_FAIL);
|
||||
/* interrupt pin config: push-pull output, active high */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_INTCR, 0x00) == ESP_OK, "write INTCR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_INTCKCR, 0x00) == ESP_OK, "write INTCKCR failed", err, ESP_FAIL);
|
||||
/* no length limitation for rx packets */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_RLENCR, 0x00) == ESP_OK, "write RLENCR failed", err, ESP_FAIL);
|
||||
/* 3K-byte for TX and 13K-byte for RX */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_MEMSCR, 0x00) == ESP_OK, "write MEMSCR failed", err, ESP_FAIL);
|
||||
/* reset tx and rx memory pointer */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX) == ESP_OK,
|
||||
"write MPTRCR failed", err, ESP_FAIL);
|
||||
/* clear network status: wakeup event, tx complete */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END) == ESP_OK, "write NSR failed", err, ESP_FAIL);
|
||||
/* clear interrupt status */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS) == ESP_OK, "write ISR failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief start dm9051: enable interrupt and start receive
|
||||
*/
|
||||
static esp_err_t dm9051_start(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* enable interrupt */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, IMR_ALL) == ESP_OK, "write IMR failed", err, ESP_FAIL);
|
||||
/* enable rx */
|
||||
uint8_t rcr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
|
||||
rcr |= RCR_RXEN;
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief stop dm9051: disable interrupt and stop receive
|
||||
*/
|
||||
static esp_err_t dm9051_stop(emac_dm9051_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* disable interrupt */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, 0x00) == ESP_OK, "write IMR failed", err, ESP_FAIL);
|
||||
/* disable rx */
|
||||
uint8_t rcr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
|
||||
rcr &= ~RCR_RXEN;
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dm9051_isr_handler(void *arg)
|
||||
{
|
||||
emac_dm9051_t *emac = (emac_dm9051_t *)arg;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
/* notify dm9051 task */
|
||||
vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
|
||||
if (high_task_wakeup != pdFALSE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void emac_dm9051_task(void *arg)
|
||||
{
|
||||
emac_dm9051_t *emac = (emac_dm9051_t *)arg;
|
||||
uint8_t status = 0;
|
||||
uint8_t *buffer = NULL;
|
||||
uint32_t length = 0;
|
||||
while (1) {
|
||||
if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) {
|
||||
/* clear interrupt status */
|
||||
dm9051_register_read(emac, DM9051_ISR, &status);
|
||||
dm9051_register_write(emac, DM9051_ISR, status);
|
||||
/* packet received */
|
||||
if (status & ISR_PR) {
|
||||
do {
|
||||
buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA);
|
||||
if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
|
||||
/* pass the buffer to stack (e.g. TCP/IP layer) */
|
||||
emac->eth->stack_input(emac->eth, buffer, length);
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
} while (emac->packets_remain);
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_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_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
emac->eth = eth;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_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_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
/* check if phy access is in progress */
|
||||
uint8_t epcr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_INVALID_STATE);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK,
|
||||
"write EPAR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRL, (uint8_t)(reg_value & 0xFF)) == ESP_OK,
|
||||
"write EPDRL failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRH, (uint8_t)((reg_value >> 8) & 0xFF)) == ESP_OK,
|
||||
"write EPDRH failed", err, ESP_FAIL);
|
||||
/* select PHY and select write operation */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, EPCR_EPOS | EPCR_ERPRW) == ESP_OK, "write EPCR failed", err, ESP_FAIL);
|
||||
/* polling the busy flag */
|
||||
uint32_t to = 0;
|
||||
do {
|
||||
ets_delay_us(100);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
|
||||
to += 100;
|
||||
} while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US);
|
||||
MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_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_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
/* check if phy access is in progress */
|
||||
uint8_t epcr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(!(epcr & 0x01), "phy is busy", err, ESP_ERR_INVALID_STATE);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK,
|
||||
"write EPAR failed", err, ESP_FAIL);
|
||||
/* Select PHY and select read operation */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, 0x0C) == ESP_OK, "write EPCR failed", err, ESP_FAIL);
|
||||
/* polling the busy flag */
|
||||
uint32_t to = 0;
|
||||
do {
|
||||
ets_delay_us(100);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
|
||||
to += 100;
|
||||
} while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US);
|
||||
MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT);
|
||||
uint8_t value_h = 0;
|
||||
uint8_t value_l = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRH, &value_h) == ESP_OK, "read EPDRH failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &value_l) == ESP_OK, "read EPDRL failed", err, ESP_FAIL);
|
||||
*reg_value = (value_h << 8) | value_l;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_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_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
memcpy(emac->addr, addr, 6);
|
||||
MAC_CHECK(dm9051_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_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_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
memcpy(addr, emac->addr, 6);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_set_link(esp_eth_mac_t *mac, eth_link_t link)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
uint8_t nsr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL);
|
||||
switch (link) {
|
||||
case ETH_LINK_UP:
|
||||
MAC_CHECK(nsr & NSR_LINKST, "phy is not link up", err, ESP_ERR_INVALID_STATE);
|
||||
MAC_CHECK(dm9051_start(emac) == ESP_OK, "dm9051 start failed", err, ESP_FAIL);
|
||||
break;
|
||||
case ETH_LINK_DOWN:
|
||||
MAC_CHECK(!(nsr & NSR_LINKST), "phy is not link down", err, ESP_ERR_INVALID_STATE);
|
||||
MAC_CHECK(dm9051_stop(emac) == ESP_OK, "dm9051 stop failed", err, ESP_FAIL);
|
||||
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_dm9051_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
uint8_t nsr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL);
|
||||
switch (speed) {
|
||||
case ETH_SPEED_10M:
|
||||
MAC_CHECK(nsr & NSR_SPEED, "phy speed is not at 10Mbps", err, ESP_ERR_INVALID_STATE);
|
||||
break;
|
||||
case ETH_SPEED_100M:
|
||||
MAC_CHECK(!(nsr & NSR_SPEED), "phy speed is not at 100Mbps", err, ESP_ERR_INVALID_STATE);
|
||||
break;
|
||||
default:
|
||||
MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
uint8_t ncr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL);
|
||||
switch (duplex) {
|
||||
case ETH_DUPLEX_HALF:
|
||||
MAC_CHECK(!(ncr & NCR_FDX), "phy is not at half duplex", err, ESP_ERR_INVALID_STATE);
|
||||
break;
|
||||
case ETH_DUPLEX_FULL:
|
||||
MAC_CHECK(ncr & NCR_FDX, "phy is not at full duplex", err, ESP_ERR_INVALID_STATE);
|
||||
break;
|
||||
default:
|
||||
MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_set_promiscuous(esp_eth_mac_t *mac, bool enable)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
uint8_t rcr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
|
||||
if (enable) {
|
||||
rcr |= RCR_PRMSC;
|
||||
} else {
|
||||
rcr &= ~RCR_PRMSC;
|
||||
}
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_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 last transmit complete */
|
||||
uint8_t tcr = 0;
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_TCR, &tcr) == ESP_OK, "read TCR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(!(tcr & TCR_TXREQ), "last transmit still in progress", err, ESP_ERR_INVALID_STATE);
|
||||
/* set tx length */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLL, length & 0xFF) == ESP_OK, "write TXPLL failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLH, (length >> 8) & 0xFF) == ESP_OK, "write TXPLH failed", err, ESP_FAIL);
|
||||
/* copy data to tx memory */
|
||||
MAC_CHECK(dm9051_memory_write(emac, buf, length) == ESP_OK, "write memory failed", err, ESP_FAIL);
|
||||
/* issue tx polling command */
|
||||
tcr |= TCR_TXREQ;
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, tcr) == ESP_OK, "write TCR failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
|
||||
uint8_t rxbyte = 0;
|
||||
uint16_t rx_len = 0;
|
||||
__attribute__((aligned(4))) dm9051_rx_header_t header; // SPI driver needs the rx buffer 4 byte align
|
||||
emac->packets_remain = false;
|
||||
/* dummy read, get the most updated data */
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
|
||||
/* rxbyte must be 0xFF, 0 or 1 */
|
||||
if (rxbyte > 1) {
|
||||
MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL);
|
||||
/* reset rx fifo pointer */
|
||||
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL);
|
||||
ets_delay_us(10);
|
||||
MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL);
|
||||
MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL);
|
||||
} else if (rxbyte) {
|
||||
MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL);
|
||||
rx_len = header.length_low + (header.length_high << 8);
|
||||
MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL);
|
||||
MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status);
|
||||
*length = rx_len - 4; // substract the CRC length (4Bytes)
|
||||
/* dummy read, get the most updated data */
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
|
||||
emac->packets_remain = rxbyte > 0;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = emac->eth;
|
||||
/* init gpio used by spi-ethernet interrupt */
|
||||
gpio_pad_select_gpio(CONFIG_ETH_DM9051_INT_GPIO);
|
||||
gpio_set_direction(CONFIG_ETH_DM9051_INT_GPIO, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(CONFIG_ETH_DM9051_INT_GPIO, GPIO_PULLDOWN_ONLY);
|
||||
gpio_set_intr_type(CONFIG_ETH_DM9051_INT_GPIO, GPIO_INTR_POSEDGE);
|
||||
gpio_intr_enable(CONFIG_ETH_DM9051_INT_GPIO);
|
||||
gpio_isr_handler_add(CONFIG_ETH_DM9051_INT_GPIO, dm9051_isr_handler, emac);
|
||||
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
|
||||
/* reset dm9051 */
|
||||
MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL);
|
||||
/* verify chip id */
|
||||
MAC_CHECK(dm9051_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL);
|
||||
/* default setup of internal registers */
|
||||
MAC_CHECK(dm9051_setup_default(emac) == ESP_OK, "dm9051 default setup failed", err, ESP_FAIL);
|
||||
/* clear multicast hash table */
|
||||
MAC_CHECK(dm9051_clear_multicast_table(emac) == ESP_OK, "clear multicast table failed", err, ESP_FAIL);
|
||||
/* get emac address from eeprom */
|
||||
MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO);
|
||||
gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO);
|
||||
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac)
|
||||
{
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = emac->eth;
|
||||
dm9051_stop(emac);
|
||||
gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO);
|
||||
gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO);
|
||||
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac)
|
||||
{
|
||||
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
|
||||
vTaskDelete(emac->rx_task_hdl);
|
||||
vSemaphoreDelete(emac->spi_lock);
|
||||
free(emac);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config)
|
||||
{
|
||||
esp_eth_mac_t *ret = NULL;
|
||||
MAC_CHECK(config, "can't set mac config to null", err, NULL);
|
||||
MAC_CHECK(config->spi_hdl, "can't set spi handle to null", err, NULL);
|
||||
emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t));
|
||||
MAC_CHECK(emac, "calloc emac failed", err, NULL);
|
||||
/* bind methods and attributes */
|
||||
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
|
||||
emac->spi_hdl = config->spi_hdl;
|
||||
emac->parent.set_mediator = emac_dm9051_set_mediator;
|
||||
emac->parent.init = emac_dm9051_init;
|
||||
emac->parent.deinit = emac_dm9051_deinit;
|
||||
emac->parent.del = emac_dm9051_del;
|
||||
emac->parent.write_phy_reg = emac_dm9051_write_phy_reg;
|
||||
emac->parent.read_phy_reg = emac_dm9051_read_phy_reg;
|
||||
emac->parent.set_addr = emac_dm9051_set_addr;
|
||||
emac->parent.get_addr = emac_dm9051_get_addr;
|
||||
emac->parent.set_speed = emac_dm9051_set_speed;
|
||||
emac->parent.set_duplex = emac_dm9051_set_duplex;
|
||||
emac->parent.set_link = emac_dm9051_set_link;
|
||||
emac->parent.set_promiscuous = emac_dm9051_set_promiscuous;
|
||||
emac->parent.transmit = emac_dm9051_transmit;
|
||||
emac->parent.receive = emac_dm9051_receive;
|
||||
/* create mutex */
|
||||
emac->spi_lock = xSemaphoreCreateMutex();
|
||||
MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL);
|
||||
/* create dm9051 task */
|
||||
BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", config->rx_task_stack_size, emac,
|
||||
config->rx_task_prio, &emac->rx_task_hdl);
|
||||
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL);
|
||||
return &(emac->parent);
|
||||
err_tsk:
|
||||
vSemaphoreDelete(emac->spi_lock);
|
||||
err_lock:
|
||||
free(emac);
|
||||
err:
|
||||
return ret;
|
||||
}
|
|
@ -41,6 +41,7 @@ static const char *TAG = "emac_esp32";
|
|||
} while (0)
|
||||
|
||||
#define RX_QUEUE_WAIT_MS (20)
|
||||
#define PHY_OPERATION_TIMEOUT_US (1000)
|
||||
|
||||
typedef struct {
|
||||
esp_eth_mac_t parent;
|
||||
|
@ -49,12 +50,8 @@ typedef struct {
|
|||
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];
|
||||
|
@ -78,9 +75,15 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
|
|||
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);
|
||||
/* polling the busy flag */
|
||||
uint32_t to = 0;
|
||||
bool busy = true;
|
||||
do {
|
||||
ets_delay_us(100);
|
||||
busy = emac_hal_is_mii_busy(emac->hal);
|
||||
to += 100;
|
||||
} while (busy && to < PHY_OPERATION_TIMEOUT_US);
|
||||
MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
|
@ -93,9 +96,15 @@ static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
|
|||
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);
|
||||
/* polling the busy flag */
|
||||
uint32_t to = 0;
|
||||
bool busy = true;
|
||||
do {
|
||||
ets_delay_us(100);
|
||||
busy = emac_hal_is_mii_busy(emac->hal);
|
||||
to += 100;
|
||||
} while (busy && to < PHY_OPERATION_TIMEOUT_US);
|
||||
MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
|
||||
/* Store value */
|
||||
*reg_value = emac_hal_get_phy_data(emac->hal);
|
||||
return ESP_OK;
|
||||
|
@ -224,16 +233,14 @@ err:
|
|||
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);
|
||||
emac->eth->stack_input(emac->eth, buffer, length);
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
|
@ -298,50 +305,32 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
|
|||
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);
|
||||
periph_module_disable(PERIPH_EMAC_MODULE);
|
||||
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);
|
||||
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
|
||||
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);
|
||||
esp_intr_free(emac->intr_hdl);
|
||||
vTaskDelete(emac->rx_task_hdl);
|
||||
vSemaphoreDelete(emac->rx_counting_sem);
|
||||
int i = 0;
|
||||
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
|
||||
free(emac->hal->rx_buf[i]);
|
||||
|
@ -400,10 +389,6 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
|
|||
/* 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;
|
||||
|
@ -418,7 +403,29 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
|
|||
emac->parent.set_promiscuous = emac_esp32_set_promiscuous;
|
||||
emac->parent.transmit = emac_esp32_transmit;
|
||||
emac->parent.receive = emac_esp32_receive;
|
||||
/* 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_intr, NULL);
|
||||
/* create counting semaphore */
|
||||
emac->rx_counting_sem = xSemaphoreCreateCounting(config->queue_len, 0);
|
||||
MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, NULL);
|
||||
/* create rx task */
|
||||
BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
|
||||
config->rx_task_prio, &emac->rx_task_hdl);
|
||||
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL);
|
||||
return &(emac->parent);
|
||||
err_task:
|
||||
vSemaphoreDelete(emac->rx_counting_sem);
|
||||
err_sem:
|
||||
esp_intr_free(emac->intr_hdl);
|
||||
err_intr:
|
||||
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
|
||||
free(emac->tx_buf[i]);
|
||||
}
|
||||
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
|
||||
free(emac->rx_buf[i]);
|
||||
}
|
||||
err_buffer:
|
||||
free(emac->hal);
|
||||
err_hal:
|
||||
|
|
302
components/esp_eth/src/esp_eth_phy_dm9051.c
Normal file
302
components/esp_eth/src/esp_eth_phy_dm9051.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
// 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 = "dm9051";
|
||||
#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 DSCR(DAVICOM Specified Configuration Register)
|
||||
*
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t reserved1 : 1; /* Reserved */
|
||||
uint32_t sleep : 1; /* Set 1 to enable PHY into sleep mode */
|
||||
uint32_t mfpsc : 1; /* MII frame preamble suppression control bit */
|
||||
uint32_t smrst : 1; /* Set 1 to reset all state machines of PHY */
|
||||
uint32_t rpdctr_en : 1; /* Set 1 to enable automatic reduced power down */
|
||||
uint32_t reserved2 : 2; /* Reserved */
|
||||
uint32_t flink100 : 1; /* Force Good Link in 100Mbps */
|
||||
uint32_t reserved3 : 2; /* Reserved */
|
||||
uint32_t tx_fx : 1; /* 100BASE-TX or FX Mode Control */
|
||||
uint32_t reserved4 : 1; /* Reserved */
|
||||
uint32_t bp_adpok : 1; /* BYPASS ADPOK */
|
||||
uint32_t bp_align : 1; /* Bypass Symbol Alignment Function */
|
||||
uint32_t bp_scr : 1; /* Bypass Scrambler/Descrambler Function */
|
||||
uint32_t bp_4b5b : 1; /* Bypass 4B5B Encoding and 5B4B Decoding */
|
||||
};
|
||||
uint32_t val;
|
||||
} dscr_reg_t;
|
||||
#define ETH_PHY_DSCR_REG_ADDR (0x10)
|
||||
|
||||
/**
|
||||
* @brief DSCSR(DAVICOM Specified Configuration and Status Register)
|
||||
*
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t anmb : 4; /* Auto-Negotiation Monitor Bits */
|
||||
uint32_t phy_addr : 5; /* PHY Address */
|
||||
uint32_t reserved : 3; /* Reserved */
|
||||
uint32_t hdx10 : 1; /* 10M Half-Duplex Operation Mode */
|
||||
uint32_t fdx10 : 1; /* 10M Full-Duplex Operation Mode */
|
||||
uint32_t hdx100 : 1; /* 100M Half-Duplex Operation Mode */
|
||||
uint32_t fdx100 : 1; /* 100M Full-Duplex Operation Mode */
|
||||
};
|
||||
uint32_t val;
|
||||
} dscsr_reg_t;
|
||||
#define ETH_PHY_DSCSR_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_dm9051_t;
|
||||
|
||||
static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
|
||||
{
|
||||
PHY_CHECK(eth, "can't set mediator for dm9051 to null", err);
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
dm9051->eth = eth;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_get_link(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = dm9051->eth;
|
||||
bmsr_reg_t bmsr;
|
||||
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->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 (dm9051->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);
|
||||
dm9051->link_status = link;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_reset(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = dm9051->eth;
|
||||
dscr_reg_t dscr;
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err);
|
||||
dscr.smrst = 1;
|
||||
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, "write DSCR failed", err);
|
||||
bmcr_reg_t bmcr = {.reset = 1};
|
||||
PHY_CHECK(eth->phy_reg_write(eth, dm9051->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 < dm9051->reset_timeout_ms / 10; to++) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err);
|
||||
if (!bmcr.reset && !dscr.smrst) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "PHY reset timeout", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = dm9051->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, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
|
||||
/* Wait for auto negotiation complete */
|
||||
bmsr_reg_t bmsr;
|
||||
dscsr_reg_t dscsr;
|
||||
uint32_t to = 0;
|
||||
for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err);
|
||||
if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (to >= dm9051->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, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR 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 (dscsr.fdx100 || dscsr.hdx100) {
|
||||
speed = ETH_SPEED_100M;
|
||||
} else {
|
||||
speed = ETH_SPEED_10M;
|
||||
}
|
||||
if (dscsr.fdx100 || dscsr.fdx10) {
|
||||
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 (dm9051->link_status != link) {
|
||||
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
|
||||
dm9051->link_status = link;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = dm9051->eth;
|
||||
bmcr_reg_t bmcr;
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->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, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->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 dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
dm9051->addr = addr;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
|
||||
{
|
||||
PHY_CHECK(addr, "get phy address failed", err);
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
*addr = dm9051->addr;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_del(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
free(dm9051);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_init(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
|
||||
esp_eth_mediator_t *eth = dm9051->eth;
|
||||
/* Power on Ethernet PHY */
|
||||
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
|
||||
/* Reset Ethernet PHY */
|
||||
PHY_CHECK(dm9051_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, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
|
||||
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
|
||||
PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, "wrong PHY chip ID", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t dm9051_deinit(esp_eth_phy_t *phy)
|
||||
{
|
||||
/* Power off Ethernet PHY */
|
||||
PHY_CHECK(dm9051_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_dm9051(const eth_phy_config_t *config)
|
||||
{
|
||||
PHY_CHECK(config, "can't set phy config to null", err);
|
||||
PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err);
|
||||
phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
|
||||
PHY_CHECK(dm9051, "calloc dm9051 object failed", err);
|
||||
dm9051->name = "dm9051";
|
||||
dm9051->addr = config->phy_addr;
|
||||
dm9051->reset_timeout_ms = config->reset_timeout_ms;
|
||||
dm9051->link_status = ETH_LINK_DOWN;
|
||||
dm9051->autonego_timeout_ms = config->autonego_timeout_ms;
|
||||
dm9051->parent.reset = dm9051_reset;
|
||||
dm9051->parent.init = dm9051_init;
|
||||
dm9051->parent.deinit = dm9051_deinit;
|
||||
dm9051->parent.set_mediator = dm9051_set_mediator;
|
||||
dm9051->parent.negotiate = dm9051_negotiate;
|
||||
dm9051->parent.get_link = dm9051_get_link;
|
||||
dm9051->parent.pwrctl = dm9051_pwrctl;
|
||||
dm9051->parent.get_addr = dm9051_get_addr;
|
||||
dm9051->parent.set_addr = dm9051_set_addr;
|
||||
dm9051->parent.del = dm9051_del;
|
||||
|
||||
return &(dm9051->parent);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
#include "test_utils.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "esp_eth_test";
|
||||
/** Event handler for Ethernet events */
|
||||
|
@ -89,3 +90,48 @@ TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]")
|
|||
TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle));
|
||||
vTaskDelay(portMAX_DELAY);
|
||||
}
|
||||
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
TEST_CASE("dm9051 io test", "[ethernet][ignore]")
|
||||
{
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = 25,
|
||||
.mosi_io_num = 23,
|
||||
.sclk_io_num = 19,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
TEST_ESP_OK(spi_bus_initialize(HSPI_HOST, &buscfg, 1));
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = 20 * 1000 * 1000,
|
||||
.spics_io_num = 22,
|
||||
.queue_size = 20
|
||||
};
|
||||
TEST_ESP_OK(spi_bus_add_device(HSPI_HOST, &devcfg, &spi_handle));
|
||||
gpio_install_isr_service(0);
|
||||
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, ð_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();
|
||||
mac_config.spi_hdl = spi_handle;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&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, ð_handle));
|
||||
vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY));
|
||||
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_ESP_OK(spi_bus_remove_device(spi_handle));
|
||||
TEST_ESP_OK(spi_bus_free(HSPI_HOST));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -163,8 +163,6 @@ void emac_hal_reset_desc_chain(emac_hal_context_t *hal)
|
|||
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 */
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
menu "Example Connection Configuration"
|
||||
|
||||
choice EXAMPLE_CONNECT_INTERFACE
|
||||
prompt "Connect using"
|
||||
default EXAMPLE_CONNECT_WIFI
|
||||
|
@ -15,27 +14,49 @@ menu "Example Connection Configuration"
|
|||
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_CONNECT_WIFI
|
||||
config EXAMPLE_WIFI_SSID
|
||||
depends on EXAMPLE_CONNECT_WIFI
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
depends on EXAMPLE_CONNECT_WIFI
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
Can be left blank if the network has no security set.
|
||||
endif
|
||||
|
||||
if EXAMPLE_CONNECT_ETHERNET
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
config EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
depends on IDF_TARGET_ESP32
|
||||
select ETH_USE_ESP32_EMAC
|
||||
bool "Internal EMAC"
|
||||
help
|
||||
Select internal Ethernet MAC controller.
|
||||
|
||||
config EXAMPLE_USE_SPI_ETHERNET
|
||||
bool "SPI Ethernet Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
depends on EXAMPLE_CONNECT_ETHERNET
|
||||
prompt "Ethernet PHY Device"
|
||||
default EXAMPLE_ETH_PHY_IP101
|
||||
help
|
||||
Select the PHY driver to use for the example.
|
||||
Select the Ethernet PHY device to use in the example.
|
||||
|
||||
config EXAMPLE_ETH_PHY_IP101
|
||||
bool "IP101"
|
||||
|
@ -60,8 +81,53 @@ menu "Example Connection Configuration"
|
|||
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
|
||||
endif
|
||||
|
||||
if EXAMPLE_USE_SPI_ETHERNET
|
||||
config EXAMPLE_ETH_SPI_HOST
|
||||
int "SPI Host Number"
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Set the SPI host used to communicate with DM9051.
|
||||
|
||||
config EXAMPLE_ETH_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_ETH_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_ETH_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_ETH_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
endif
|
||||
endif
|
||||
|
||||
config EXAMPLE_CONNECT_IPV6
|
||||
bool "Obtain IPv6 link-local address"
|
||||
|
@ -69,5 +135,4 @@ menu "Example Connection Configuration"
|
|||
help
|
||||
By default, examples will wait until IPv4 and IPv6 addresses are obtained.
|
||||
Disable this option if the network does not support IPv6.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -187,8 +187,9 @@ static void start()
|
|||
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_USE_INTERNAL_ETHERNET
|
||||
s_mac = esp_eth_mac_new_esp32(&mac_config);
|
||||
#if CONFIG_EXAMPLE_ETH_PHY_IP101
|
||||
s_phy = esp_eth_phy_new_ip101(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
||||
|
@ -197,9 +198,33 @@ static void start()
|
|||
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
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
|
||||
mac_config.spi_hdl = spi_handle;
|
||||
s_mac = esp_eth_mac_new_dm9051(&mac_config);
|
||||
s_phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#endif
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
|
||||
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
|
||||
s_connection_name = "Ethernet";
|
||||
}
|
||||
|
|
|
@ -15,18 +15,24 @@ If you have a new Ethernet application to go (for example, connect to IoT cloud
|
|||
|
||||
### 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.
|
||||
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 up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
|
||||
|
||||
`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration.
|
||||
|
||||
### 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 the kind of Ethernet this example will run on under `Ethernet Type`.
|
||||
* If `Internal EMAC` is selected:
|
||||
* 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:
|
||||
* If `SPI Ethernet Module` is selected:
|
||||
* Set SPI specific configuration, including GPIO and clock speed.
|
||||
|
||||
2. In the `Component config > Ethernet` menu:
|
||||
* If `Internal EMAC` is selected:
|
||||
* 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`.
|
||||
|
@ -41,10 +47,16 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i
|
|||
|
||||
* 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`.
|
||||
|
||||
* If `SPI Ethernet Module` is selected:
|
||||
* Set the GPIO number used by interrupt pin under `DM9051 Interrupt 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.
|
||||
|
||||
**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified.
|
||||
|
||||
### 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.
|
||||
|
@ -56,20 +68,20 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
|
|||
## 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: ~~~~~~~~~~~
|
||||
I (394) eth_example: Ethernet Started
|
||||
I (3934) eth_example: Ethernet Link Up
|
||||
I (3934) eth_example: Ethernet HW Addr 30:ae:a4:c6:87:5b
|
||||
I (5864) tcpip_adapter: eth ip: 192.168.2.151, mask: 255.255.255.0, gw: 192.168.2.2
|
||||
I (5864) eth_example: Ethernet Got IP Address
|
||||
I (5864) eth_example: ~~~~~~~~~~~
|
||||
I (5864) eth_example: ETHIP:192.168.2.151
|
||||
I (5874) eth_example: ETHMASK:255.255.255.0
|
||||
I (5874) eth_example: ETHGW:192.168.2.2
|
||||
I (5884) eth_example: ~~~~~~~~~~~
|
||||
```
|
||||
|
||||
Now you can ping your ESP32 in the terminal by entering `ping 192.168.2.151` (it depends on the actual IP address you get).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* RMII Clock
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
menu "Example Configuration"
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
config EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
depends on IDF_TARGET_ESP32
|
||||
select ETH_USE_ESP32_EMAC
|
||||
bool "Internal EMAC"
|
||||
help
|
||||
Select internal Ethernet MAC controller.
|
||||
|
||||
config EXAMPLE_USE_SPI_ETHERNET
|
||||
bool "SPI Ethernet Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
prompt "Ethernet PHY Device"
|
||||
default EXAMPLE_ETH_PHY_IP101
|
||||
|
@ -30,5 +51,49 @@ menu "Example Configuration"
|
|||
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
|
||||
endif
|
||||
|
||||
if EXAMPLE_USE_SPI_ETHERNET
|
||||
config EXAMPLE_ETH_SPI_HOST
|
||||
int "SPI Host Number"
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Set the SPI host used to communicate with DM9051.
|
||||
|
||||
config EXAMPLE_ETH_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_ETH_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_ETH_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_ETH_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
endif
|
||||
endmenu
|
||||
|
|
|
@ -17,15 +17,21 @@
|
|||
#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)
|
||||
{
|
||||
uint8_t mac_addr[6] = {0};
|
||||
/* we can get the ethernet driver handle from event data */
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
|
||||
break;
|
||||
case ETHERNET_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Down");
|
||||
|
@ -66,8 +72,9 @@ void app_main()
|
|||
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_USE_INTERNAL_ETHERNET
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_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
|
||||
|
@ -76,7 +83,33 @@ void app_main()
|
|||
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
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
|
||||
mac_config.spi_hdl = spi_handle;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#endif
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
|
||||
esp_eth_handle_t eth_handle = NULL;
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));
|
||||
}
|
||||
|
|
|
@ -12,20 +12,26 @@ 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 four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, 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 up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
|
||||
|
||||
`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration.
|
||||
|
||||
### 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.
|
||||
* 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`.
|
||||
* Choose the kind of Ethernet this example will run on under `Ethernet Type`.
|
||||
* If `Internal EMAC` is selected:
|
||||
* Choose PHY device under `Ethernet PHY Device`, by default, the **ESP32-Ethernet-Kit** has an `IP101` on board.
|
||||
|
||||
* If `SPI Ethernet Module` is selected:
|
||||
* Set SPI specific configuration, including GPIO and clock speed.
|
||||
|
||||
2. In the `Component config > Ethernet` menu:
|
||||
|
||||
* If `Internal EMAC` is selected:
|
||||
* 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`.
|
||||
|
@ -40,10 +46,14 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i
|
|||
|
||||
* 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`.
|
||||
|
||||
* If `SPI Ethernet Module` is selected:
|
||||
* Set the GPIO number used by interrupt pin under `DM9051 Interrupt 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.peripheral (e.g. I²S), you'd better choose the external clock.
|
||||
|
||||
**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
menu "Example Configuration"
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
config EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
depends on IDF_TARGET_ESP32
|
||||
select ETH_USE_ESP32_EMAC
|
||||
bool "Internal EMAC"
|
||||
help
|
||||
Select internal Ethernet MAC controller.
|
||||
|
||||
config EXAMPLE_USE_SPI_ETHERNET
|
||||
bool "SPI Ethernet Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
prompt "Ethernet PHY Device"
|
||||
default EXAMPLE_ETH_PHY_IP101
|
||||
|
@ -30,6 +51,51 @@ menu "Example Configuration"
|
|||
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
|
||||
endif
|
||||
|
||||
if EXAMPLE_USE_SPI_ETHERNET
|
||||
config EXAMPLE_ETH_SPI_HOST
|
||||
int "SPI Host Number"
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Set the SPI host used to communicate with DM9051.
|
||||
|
||||
config EXAMPLE_ETH_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_ETH_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_ETH_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_ETH_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
endif
|
||||
|
||||
config EXAMPLE_WIFI_SSID
|
||||
string "Wi-Fi SSID"
|
||||
|
|
|
@ -145,8 +145,9 @@ static void initialize_ethernet(void)
|
|||
{
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, eth_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_USE_INTERNAL_ETHERNET
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_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
|
||||
|
@ -155,6 +156,31 @@ static void initialize_ethernet(void)
|
|||
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
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
|
||||
mac_config.spi_hdl = spi_handle;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#endif
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
config.stack_input = pkt_eth2wifi;
|
||||
|
|
|
@ -10,9 +10,13 @@ The cli environment in the example is based on the [console component](https://d
|
|||
|
||||
## 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.
|
||||
### Hardware Required
|
||||
|
||||
### Prepare work
|
||||
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 up to four Ethernet PHY: `LAN8720`, `IP101`, `DP83848` and `RTL8201`, additional PHY drivers should be implemented by users themselves.
|
||||
|
||||
`esp_eth` component not only supports ESP32 internal Ethernet MAC controller, but also can drive third-party Ethernet module which integrates MAC and PHY and provides SPI interface. This example also take the **DM9051** as an example, illustrating how to install the Ethernet driver with only a little different configuration.
|
||||
|
||||
### Other Preparation
|
||||
|
||||
1. Install iperf tool on PC
|
||||
* Debian/Ubuntu: `sudo apt-get install iperf`
|
||||
|
@ -24,12 +28,16 @@ To run this example, it's recommended that you have an official ESP32 Ethernet d
|
|||
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:
|
||||
|
||||
* Enable storing history commands in flash under `Store command history in flash`.
|
||||
* Choose the kind of Ethernet this example will run on under `Ethernet Type`.
|
||||
* If `Internal EMAC` is selected:
|
||||
* 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:
|
||||
* If `SPI Ethernet Module` is selected:
|
||||
* Set SPI specific configuration, including GPIO and clock speed.
|
||||
|
||||
2. In the `Component config > Ethernet` menu:
|
||||
* If `Internal EMAC` is selected:
|
||||
* 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`.
|
||||
|
@ -44,10 +52,15 @@ Enter `make menuconfig` if you are using GNU Make based build system or enter `i
|
|||
|
||||
* 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`.
|
||||
|
||||
* If `SPI Ethernet Module` is selected:
|
||||
* Set the GPIO number used by interrupt pin under `DM9051 Interrupt 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.
|
||||
|
||||
**Note:** DM9051 has a fixed PHY address `1`, which cannot be modified.
|
||||
|
||||
### 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.
|
||||
|
@ -73,15 +86,15 @@ UDP buffer size: 208 KByte (default)
|
|||
------------------------------------------------------------
|
||||
[ 3] local 192.168.2.160 port 5001 connected with 192.168.2.156 port 49154
|
||||
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
|
||||
[ 3] 0.0- 3.0 sec 24.8 MBytes 69.5 Mbits/sec 0.172 ms 1/17721 (0.0056%)
|
||||
[ 3] 3.0- 6.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17719 (0%)
|
||||
[ 3] 6.0- 9.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17719 (0%)
|
||||
[ 3] 9.0-12.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17718 (0%)
|
||||
[ 3] 12.0-15.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17717 (0%)
|
||||
[ 3] 15.0-18.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17720 (0%)
|
||||
[ 3] 18.0-21.0 sec 24.8 MBytes 69.5 Mbits/sec 0.170 ms 0/17721 (0%)
|
||||
[ 3] 21.0-24.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17720 (0%)
|
||||
[ 3] 24.0-27.0 sec 24.8 MBytes 69.5 Mbits/sec 0.169 ms 0/17723 (0%)
|
||||
[ 3] 0.0- 3.0 sec 26.1 MBytes 72.8 Mbits/sec 0.198 ms 1/18585 (0.0054%)
|
||||
[ 3] 3.0- 6.0 sec 26.3 MBytes 73.7 Mbits/sec 0.192 ms 0/18792 (0%)
|
||||
[ 3] 6.0- 9.0 sec 26.3 MBytes 73.5 Mbits/sec 0.189 ms 0/18741 (0%)
|
||||
[ 3] 9.0-12.0 sec 26.2 MBytes 73.3 Mbits/sec 0.191 ms 43/18739 (0.23%)
|
||||
[ 3] 12.0-15.0 sec 26.3 MBytes 73.5 Mbits/sec 0.194 ms 0/18739 (0%)
|
||||
[ 3] 15.0-18.0 sec 26.3 MBytes 73.5 Mbits/sec 0.191 ms 0/18741 (0%)
|
||||
[ 3] 18.0-21.0 sec 26.3 MBytes 73.5 Mbits/sec 0.187 ms 0/18752 (0%)
|
||||
[ 3] 21.0-24.0 sec 26.3 MBytes 73.4 Mbits/sec 0.192 ms 0/18737 (0%)
|
||||
[ 3] 24.0-27.0 sec 26.3 MBytes 73.5 Mbits/sec 0.188 ms 0/18739 (0%)
|
||||
```
|
||||
|
||||
#### ESP32 output
|
||||
|
@ -89,16 +102,17 @@ UDP buffer size: 208 KByte (default)
|
|||
```bash
|
||||
mode=udp-client sip=192.168.2.156:5001, dip=192.168.2.160:5001, interval=3, time=30
|
||||
Interval Bandwidth
|
||||
0- 3 sec 69.34 Mbits/sec
|
||||
3- 6 sec 69.55 Mbits/sec
|
||||
6- 9 sec 69.55 Mbits/sec
|
||||
9- 12 sec 69.55 Mbits/sec
|
||||
12- 15 sec 69.55 Mbits/sec
|
||||
15- 18 sec 69.56 Mbits/sec
|
||||
18- 21 sec 69.56 Mbits/sec
|
||||
21- 24 sec 69.56 Mbits/sec
|
||||
24- 27 sec 69.56 Mbits/sec
|
||||
27- 30 sec 69.56 Mbits/sec
|
||||
0- 3 sec 72.92 Mbits/sec
|
||||
3- 6 sec 73.76 Mbits/sec
|
||||
6- 9 sec 73.56 Mbits/sec
|
||||
9- 12 sec 73.56 Mbits/sec
|
||||
12- 15 sec 73.56 Mbits/sec
|
||||
15- 18 sec 73.56 Mbits/sec
|
||||
18- 21 sec 73.61 Mbits/sec
|
||||
21- 24 sec 73.55 Mbits/sec
|
||||
24- 27 sec 73.56 Mbits/sec
|
||||
27- 30 sec 73.56 Mbits/sec
|
||||
0- 30 sec 73.52 Mbits/sec
|
||||
```
|
||||
|
||||
### Test downlink bandwidth
|
||||
|
@ -119,11 +133,13 @@ UDP buffer size: 208 KByte (default)
|
|||
[ 3] 3.0- 6.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 6.0- 9.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 9.0-12.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 12.0-15.0 sec 28.6 MBytes 79.9 Mbits/sec
|
||||
[ 3] 15.0-18.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 18.0-21.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 21.0-24.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 12.0-15.0 sec 28.4 MBytes 79.5 Mbits/sec
|
||||
[ 3] 15.0-18.0 sec 28.6 MBytes 79.9 Mbits/sec
|
||||
[ 3] 18.0-21.0 sec 28.6 MBytes 79.9 Mbits/sec
|
||||
[ 3] 21.0-24.0 sec 28.6 MBytes 79.9 Mbits/sec
|
||||
[ 3] 24.0-27.0 sec 28.6 MBytes 80.0 Mbits/sec
|
||||
[ 3] 27.0-30.0 sec 28.5 MBytes 79.7 Mbits/sec
|
||||
[ 3] 0.0-30.0 sec 286 MBytes 79.9 Mbits/sec
|
||||
```
|
||||
|
||||
#### ESP32 output
|
||||
|
@ -131,16 +147,17 @@ UDP buffer size: 208 KByte (default)
|
|||
mode=udp-server sip=192.168.2.156:5001, dip=0.0.0.0:5001, interval=3, time=30
|
||||
Interval Bandwidth
|
||||
I (2534456) iperf: want recv=16384
|
||||
0- 30 sec 72.67 Mbits/sec
|
||||
3- 6 sec 74.18 Mbits/sec
|
||||
6- 9 sec 73.14 Mbits/sec
|
||||
9- 12 sec 73.65 Mbits/sec
|
||||
12- 15 sec 72.87 Mbits/sec
|
||||
15- 18 sec 73.29 Mbits/sec
|
||||
18- 21 sec 74.35 Mbits/sec
|
||||
21- 24 sec 72.28 Mbits/sec
|
||||
24- 27 sec 73.39 Mbits/sec
|
||||
27- 30 sec 73.49 Mbits/sec
|
||||
0- 3 sec 79.36 Mbits/sec
|
||||
3- 6 sec 79.56 Mbits/sec
|
||||
6- 9 sec 79.51 Mbits/sec
|
||||
9- 12 sec 79.24 Mbits/sec
|
||||
12- 15 sec 77.33 Mbits/sec
|
||||
15- 18 sec 79.01 Mbits/sec
|
||||
18- 21 sec 78.58 Mbits/sec
|
||||
21- 24 sec 78.24 Mbits/sec
|
||||
24- 27 sec 79.56 Mbits/sec
|
||||
27- 30 sec 77.20 Mbits/sec
|
||||
0- 30 sec 78.76 Mbits/sec
|
||||
```
|
||||
|
||||
## Suggestions of getting higher bandwidth
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_STORE_HISTORY
|
||||
bool "Store command history in flash"
|
||||
default y
|
||||
|
@ -8,6 +7,28 @@ menu "Example Configuration"
|
|||
command history. If this option is enabled, initalizes a FAT filesystem
|
||||
and uses it to store command history.
|
||||
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_SPI_ETHERNET if !IDF_TARGET_ESP32
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
config EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
depends on IDF_TARGET_ESP32
|
||||
select ETH_USE_ESP32_EMAC
|
||||
bool "Internal EMAC"
|
||||
help
|
||||
Select internal Ethernet MAC controller.
|
||||
|
||||
config EXAMPLE_USE_SPI_ETHERNET
|
||||
bool "SPI Ethernet Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
endchoice
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
prompt "Ethernet PHY Device"
|
||||
default EXAMPLE_ETH_PHY_IP101
|
||||
|
@ -38,5 +59,49 @@ menu "Example Configuration"
|
|||
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
|
||||
endif
|
||||
|
||||
if EXAMPLE_USE_SPI_ETHERNET
|
||||
config EXAMPLE_ETH_SPI_HOST
|
||||
int "SPI Host Number"
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Set the SPI host used to communicate with DM9051.
|
||||
|
||||
config EXAMPLE_ETH_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_ETH_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_ETH_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_ETH_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
endif
|
||||
endmenu
|
||||
|
|
|
@ -183,8 +183,9 @@ void register_ethernet()
|
|||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_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_USE_INTERNAL_ETHERNET
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_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
|
||||
|
@ -193,6 +194,31 @@ void register_ethernet()
|
|||
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
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver, so need to specify the spi handle */
|
||||
mac_config.spi_hdl = spi_handle;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#endif
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));
|
||||
|
|
|
@ -85,7 +85,7 @@ static void initialize_console()
|
|||
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = {
|
||||
.max_cmdline_args = 8,
|
||||
.max_cmdline_args = 16,
|
||||
.max_cmdline_length = 256,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
|
|
Loading…
Reference in a new issue