mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/support_w5500_raw_mac' into 'master'
eth: support W5500 MAC RAW mode Closes IDF-1749 See merge request espressif/esp-idf!11050
This commit is contained in:
commit
ac477ad6b9
@ -39,6 +39,8 @@
|
||||
#if !DISABLED_FOR_TARGETS(ESP8266, ESP32, ESP32S3) // This testcase for ESP32S2
|
||||
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "test/test_adc_dac_dma.h"
|
||||
|
||||
|
@ -32,9 +32,11 @@
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "test_utils.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/adc_periph.h"
|
||||
#include "soc/dac_periph.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "test/test_common_adc.h"
|
||||
|
||||
#if !DISABLED_FOR_TARGETS(ESP8266, ESP32, ESP32S3) // This testcase for ESP32S2
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define _ESP_TASK_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
|
||||
#define ESP_TASK_PRIO_MAX (configMAX_PRIORITIES)
|
||||
|
@ -32,6 +32,11 @@ if(CONFIG_ETH_ENABLED)
|
||||
"src/esp_eth_phy_dm9051.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ETH_SPI_ETHERNET_W5500)
|
||||
list(APPEND srcs "src/esp_eth_mac_w5500.c"
|
||||
"src/esp_eth_phy_w5500.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ETH_USE_OPENETH)
|
||||
list(APPEND srcs "src/esp_eth_mac_openeth.c")
|
||||
endif()
|
||||
|
@ -46,7 +46,7 @@ menu "Ethernet"
|
||||
This clock can be routed to the external PHY device.
|
||||
ESP32 supports to route the RMII clock to GPIO0/16/17.
|
||||
endchoice
|
||||
endif
|
||||
endif # ETH_PHY_INTERFACE_RMII
|
||||
|
||||
if ETH_RMII_CLK_INPUT
|
||||
config ETH_RMII_CLK_IN_GPIO
|
||||
@ -55,7 +55,7 @@ menu "Ethernet"
|
||||
default 0
|
||||
help
|
||||
ESP32 only supports GPIO0 to input the RMII clock.
|
||||
endif
|
||||
endif # ETH_RMII_CLK_INPUT
|
||||
|
||||
if ETH_RMII_CLK_OUTPUT
|
||||
config ETH_RMII_CLK_OUTPUT_GPIO0
|
||||
@ -77,8 +77,8 @@ menu "Ethernet"
|
||||
default 17
|
||||
help
|
||||
Set the GPIO number to output RMII Clock.
|
||||
endif
|
||||
endif
|
||||
endif # !ETH_RMII_CLK_OUTPUT_GPIO0
|
||||
endif # ETH_RMII_CLK_OUTPUT
|
||||
|
||||
config ETH_DMA_BUFFER_SIZE
|
||||
int "Ethernet DMA buffer size (Byte)"
|
||||
@ -102,7 +102,7 @@ menu "Ethernet"
|
||||
help
|
||||
Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE.
|
||||
Larger number of buffers could increase throughput somehow.
|
||||
endif
|
||||
endif # ETH_USE_ESP32_EMAC
|
||||
|
||||
menuconfig ETH_USE_SPI_ETHERNET
|
||||
bool "Support SPI to Ethernet Module"
|
||||
@ -117,8 +117,17 @@ menu "Ethernet"
|
||||
help
|
||||
DM9051 is a fast Ethernet controller with an SPI interface.
|
||||
It's also integrated with a 10/100M PHY and MAC.
|
||||
Select to enable DM9051 driver.
|
||||
endif
|
||||
Select this to enable DM9051 driver.
|
||||
|
||||
config ETH_SPI_ETHERNET_W5500
|
||||
bool "Use W5500 (MAC RAW)"
|
||||
help
|
||||
W5500 is a HW TCP/IP embedded Ethernet controller.
|
||||
TCP/IP stack, 10/100 Ethernet MAC and PHY are embedded in a single chip.
|
||||
However the driver in ESP-IDF only enables the RAW MAC mode,
|
||||
making it compatible with the software TCP/IP stack.
|
||||
Say yes to enable W5500 driver.
|
||||
endif # ETH_USE_SPI_ETHERNET
|
||||
|
||||
menuconfig ETH_USE_OPENETH
|
||||
bool "Support OpenCores Ethernet MAC (for use with QEMU)"
|
||||
@ -143,5 +152,5 @@ menu "Ethernet"
|
||||
default 1
|
||||
help
|
||||
Number of DMA transmit buffers, each buffer is 1600 bytes.
|
||||
endif
|
||||
endif # ETH_USE_OPENETH
|
||||
endmenu
|
||||
|
@ -12,6 +12,10 @@ ifndef CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_w5500.o src/esp_eth_phy_w5500.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_ETH_USE_OPENETH
|
||||
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_openeth.o
|
||||
endif
|
||||
|
@ -16,9 +16,6 @@
|
||||
#include <stdbool.h>
|
||||
#include "esp_eth_com.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -339,8 +336,8 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config);
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
spi_device_handle_t spi_hdl; /*!< Handle of SPI device driver */
|
||||
int int_gpio_num; /*!< Interrupt GPIO number */
|
||||
void *spi_hdl; /*!< Handle of SPI device driver */
|
||||
int int_gpio_num; /*!< Interrupt GPIO number */
|
||||
} eth_dm9051_config_t;
|
||||
|
||||
/**
|
||||
@ -366,6 +363,39 @@ typedef struct {
|
||||
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config);
|
||||
#endif // CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
|
||||
#if CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
/**
|
||||
* @brief W5500 specific configuration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
void *spi_hdl; /*!< Handle of SPI device driver */
|
||||
int int_gpio_num; /*!< Interrupt GPIO number */
|
||||
} eth_w5500_config_t;
|
||||
|
||||
/**
|
||||
* @brief Default W5500 specific configuration
|
||||
*
|
||||
*/
|
||||
#define ETH_W5500_DEFAULT_CONFIG(spi_device) \
|
||||
{ \
|
||||
.spi_hdl = spi_device, \
|
||||
.int_gpio_num = 4, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create W5500 Ethernet MAC instance
|
||||
*
|
||||
* @param w5500_config: W5500 specific configuration
|
||||
* @param mac_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_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config);
|
||||
#endif // CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
|
||||
#if CONFIG_ETH_USE_OPENETH
|
||||
/**
|
||||
* @brief Create OpenCores Ethernet MAC instance
|
||||
|
@ -277,6 +277,18 @@ esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config);
|
||||
esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
/**
|
||||
* @brief Create a PHY instance of W5500
|
||||
*
|
||||
* @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_w5500(const eth_phy_config_t *config);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -408,7 +408,7 @@ static void emac_dm9051_task(void *arg)
|
||||
uint32_t length = 0;
|
||||
while (1) {
|
||||
// block indefinitely until some task notifies me
|
||||
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
/* clear interrupt status */
|
||||
dm9051_register_read(emac, DM9051_ISR, &status);
|
||||
dm9051_register_write(emac, DM9051_ISR, status);
|
||||
@ -686,13 +686,12 @@ static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
|
||||
rx_len = header.length_low + (header.length_high << 8);
|
||||
/* check if the buffer can hold all the incoming data */
|
||||
if (*length < rx_len - 4) {
|
||||
ESP_LOGE(TAG, "buffer size too small");
|
||||
ESP_LOGE(TAG, "buffer size too small, needs %d", rx_len - 4);
|
||||
/* tell upper layer the size we need */
|
||||
*length = rx_len - 4;
|
||||
ret = ESP_ERR_INVALID_SIZE;
|
||||
goto err;
|
||||
}
|
||||
MAC_CHECK(*length >= rx_len - 4, "buffer size too small", err, ESP_ERR_INVALID_SIZE);
|
||||
MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK,
|
||||
"read rx header failed", err, ESP_FAIL);
|
||||
MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL);
|
||||
|
673
components/esp_eth/src/esp_eth_mac_w5500.c
Normal file
673
components/esp_eth/src/esp_eth_mac_w5500.c
Normal file
@ -0,0 +1,673 @@
|
||||
// Copyright 2020 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_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "hal/cpu_hal.h"
|
||||
#include "w5500.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "w5500-mac";
|
||||
#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 W5500_SPI_LOCK_TIMEOUT_MS (50)
|
||||
#define W5500_TX_MEM_SIZE (0x4000)
|
||||
#define W5500_RX_MEM_SIZE (0x4000)
|
||||
|
||||
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;
|
||||
int int_gpio_num;
|
||||
uint8_t addr[6];
|
||||
bool packets_remain;
|
||||
} emac_w5500_t;
|
||||
|
||||
static inline bool w5500_lock(emac_w5500_t *emac)
|
||||
{
|
||||
return xSemaphoreTake(emac->spi_lock, pdMS_TO_TICKS(W5500_SPI_LOCK_TIMEOUT_MS)) == pdTRUE;
|
||||
}
|
||||
|
||||
static inline bool w5500_unlock(emac_w5500_t *emac)
|
||||
{
|
||||
return xSemaphoreGive(emac->spi_lock) == pdTRUE;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_write(emac_w5500_t *emac, uint32_t address, const void *value, uint32_t len)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
spi_transaction_t trans = {
|
||||
.cmd = (address >> W5500_ADDR_OFFSET),
|
||||
.addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_WRITE << W5500_RWB_OFFSET) | W5500_SPI_OP_MODE_VDM),
|
||||
.length = 8 * len,
|
||||
.tx_buffer = value
|
||||
};
|
||||
if (w5500_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;
|
||||
}
|
||||
w5500_unlock(emac);
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_read(emac_w5500_t *emac, uint32_t address, void *value, uint32_t len)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
spi_transaction_t trans = {
|
||||
.cmd = (address >> W5500_ADDR_OFFSET),
|
||||
.addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_READ << W5500_RWB_OFFSET) | W5500_SPI_OP_MODE_VDM),
|
||||
.length = 8 * len,
|
||||
.rx_buffer = value
|
||||
};
|
||||
if (w5500_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;
|
||||
}
|
||||
w5500_unlock(emac);
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_send_command(emac_w5500_t *emac, uint8_t command, uint32_t timeout_ms)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_CR(0), &command, sizeof(command)) == ESP_OK, "write SCR failed", err, ESP_FAIL);
|
||||
// after W5500 accepts the command, the command register will be cleared automatically
|
||||
uint32_t to = 0;
|
||||
for (to = 0; to < timeout_ms / 10; to++) {
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_CR(0), &command, sizeof(command)) == ESP_OK, "read SCR failed", err, ESP_FAIL);
|
||||
if (!command) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
MAC_CHECK(to < timeout_ms / 10, "send command timeout", err, ESP_ERR_TIMEOUT);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_get_tx_free_size(emac_w5500_t *emac, uint16_t *size)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint16_t free0, free1 = 0;
|
||||
// read TX_FSR register more than once, until we get the same value
|
||||
// this is a trick because we might be interrupted between reading the high/low part of the TX_FSR register (16 bits in length)
|
||||
do {
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_TX_FSR(0), &free0, sizeof(free0)) == ESP_OK, "read TX FSR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_TX_FSR(0), &free1, sizeof(free1)) == ESP_OK, "read TX FSR failed", err, ESP_FAIL);
|
||||
} while (free0 != free1);
|
||||
|
||||
*size = __builtin_bswap16(free0);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_get_rx_received_size(emac_w5500_t *emac, uint16_t *size)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint16_t received0, received1 = 0;
|
||||
do {
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_RX_RSR(0), &received0, sizeof(received0)) == ESP_OK, "read RX RSR failed", err, ESP_FAIL);
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_RX_RSR(0), &received1, sizeof(received1)) == ESP_OK, "read RX RSR failed", err, ESP_FAIL);
|
||||
} while (received0 != received1);
|
||||
*size = __builtin_bswap16(received0);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_write_buffer(emac_w5500_t *emac, const void *buffer, uint32_t len, uint16_t offset)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t remain = len;
|
||||
const uint8_t *buf = buffer;
|
||||
offset %= W5500_TX_MEM_SIZE;
|
||||
if (offset + len > W5500_TX_MEM_SIZE) {
|
||||
remain = (offset + len) % W5500_TX_MEM_SIZE;
|
||||
len = W5500_TX_MEM_SIZE - offset;
|
||||
MAC_CHECK(w5500_write(emac, W5500_MEM_SOCK_TX(0, offset), buf, len) == ESP_OK, "write TX buffer failed", err, ESP_FAIL);
|
||||
offset += len;
|
||||
buf += len;
|
||||
}
|
||||
MAC_CHECK(w5500_write(emac, W5500_MEM_SOCK_TX(0, offset), buf, remain) == ESP_OK, "write TX buffer failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_read_buffer(emac_w5500_t *emac, void *buffer, uint32_t len, uint16_t offset)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t remain = len;
|
||||
uint8_t *buf = buffer;
|
||||
offset %= W5500_RX_MEM_SIZE;
|
||||
if (offset + len > W5500_RX_MEM_SIZE) {
|
||||
remain = (offset + len) % W5500_RX_MEM_SIZE;
|
||||
len = W5500_RX_MEM_SIZE - offset;
|
||||
MAC_CHECK(w5500_read(emac, W5500_MEM_SOCK_RX(0, offset), buf, len) == ESP_OK, "read RX buffer failed", err, ESP_FAIL);
|
||||
offset += len;
|
||||
buf += len;
|
||||
}
|
||||
MAC_CHECK(w5500_read(emac, W5500_MEM_SOCK_RX(0, offset), buf, remain) == ESP_OK, "read RX buffer failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_set_mac_addr(emac_w5500_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_MAC, emac->addr, 6) == ESP_OK, "write MAC address register failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_reset(emac_w5500_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
/* software reset */
|
||||
uint8_t mr = W5500_MR_RST; // Set RST bit (auto clear)
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_MR, &mr, sizeof(mr)) == ESP_OK, "write MR failed", err, ESP_FAIL);
|
||||
uint32_t to = 0;
|
||||
for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_MR, &mr, sizeof(mr)) == ESP_OK, "read MR failed", err, ESP_FAIL);
|
||||
if (!(mr & W5500_MR_RST)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_verify_id(emac_w5500_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t version = 0;
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_VERSIONR, &version, sizeof(version)) == ESP_OK,
|
||||
"read VERSIONR failed", err, ESP_FAIL);
|
||||
// W5500 doesn't have chip ID, we just print the version number instead
|
||||
ESP_LOGI(TAG, "version=%x", version);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_setup_default(emac_w5500_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t reg_value = 16;
|
||||
|
||||
// Only SOCK0 can be used as MAC RAW mode, so we give the whole buffer (16KB TX and 16KB RX) to SOCK0
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_RXBUF_SIZE(0), ®_value, sizeof(reg_value)) == ESP_OK, "set rx buffer size failed", err, ESP_FAIL);
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_TXBUF_SIZE(0), ®_value, sizeof(reg_value)) == ESP_OK, "set tx buffer size failed", err, ESP_FAIL);
|
||||
reg_value = 0;
|
||||
for (int i = 1; i < 8; i++) {
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_RXBUF_SIZE(i), ®_value, sizeof(reg_value)) == ESP_OK, "set rx buffer size failed", err, ESP_FAIL);
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_TXBUF_SIZE(i), ®_value, sizeof(reg_value)) == ESP_OK, "set tx buffer size failed", err, ESP_FAIL);
|
||||
}
|
||||
|
||||
/* Enable ping block, disable PPPoE, WOL */
|
||||
reg_value = W5500_MR_PB;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_MR, ®_value, sizeof(reg_value)) == ESP_OK, "write MR failed", err, ESP_FAIL);
|
||||
/* Disable interrupt for all sockets by default */
|
||||
reg_value = 0;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SIMR, ®_value, sizeof(reg_value)) == ESP_OK, "write SIMR failed", err, ESP_FAIL);
|
||||
/* Enable MAC RAW mode for SOCK0, enable MAC filter, no blocking broadcast and multicast */
|
||||
reg_value = W5500_SMR_MAC_RAW | W5500_SMR_MAC_FILTER;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_MR(0), ®_value, sizeof(reg_value)) == ESP_OK, "write SMR failed", err, ESP_FAIL);
|
||||
/* Enable receive and send event for SOCK0 */
|
||||
reg_value = W5500_SIR_RECV | W5500_SIR_SEND;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_IMR(0), ®_value, sizeof(reg_value)) == ESP_OK, "write SOCK0 IMR failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_start(esp_eth_mac_t *mac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
uint8_t reg_value = 0;
|
||||
/* open SOCK0 */
|
||||
MAC_CHECK(w5500_send_command(emac, W5500_SCR_OPEN, 100) == ESP_OK, "issue OPEN command failed", err, ESP_FAIL);
|
||||
/* enable interrupt for SOCK0 */
|
||||
reg_value = W5500_SIMR_SOCK0;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SIMR, ®_value, sizeof(reg_value)) == ESP_OK, "write SIMR failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_stop(esp_eth_mac_t *mac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
uint8_t reg_value = 0;
|
||||
/* disable interrupt */
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SIMR, ®_value, sizeof(reg_value)) == ESP_OK, "write SIMR failed", err, ESP_FAIL);
|
||||
/* close SOCK0 */
|
||||
MAC_CHECK(w5500_send_command(emac, W5500_SCR_CLOSE, 100) == ESP_OK, "issue CLOSE command failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRAM_ATTR static void w5500_isr_handler(void *arg)
|
||||
{
|
||||
emac_w5500_t *emac = (emac_w5500_t *)arg;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
/* notify w5500 task */
|
||||
vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
|
||||
if (high_task_wakeup != pdFALSE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void emac_w5500_task(void *arg)
|
||||
{
|
||||
emac_w5500_t *emac = (emac_w5500_t *)arg;
|
||||
uint8_t status = 0;
|
||||
uint8_t *buffer = NULL;
|
||||
uint32_t length = 0;
|
||||
while (1) {
|
||||
// block indefinitely until some task notifies me
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
/* read interrupt status */
|
||||
w5500_read(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status));
|
||||
/* packet received */
|
||||
if (status & W5500_SIR_RECV) {
|
||||
status = W5500_SIR_RECV;
|
||||
// clear interrupt status
|
||||
w5500_write(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status));
|
||||
do {
|
||||
length = ETH_MAX_PACKET_SIZE;
|
||||
buffer = heap_caps_malloc(length, MALLOC_CAP_DMA);
|
||||
if (!buffer) {
|
||||
ESP_LOGE(TAG, "no mem for receive buffer");
|
||||
break;
|
||||
} else if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
|
||||
/* pass the buffer to stack (e.g. TCP/IP layer) */
|
||||
if (length) {
|
||||
emac->eth->stack_input(emac->eth, buffer, length);
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
} while (emac->packets_remain);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_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_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
emac->eth = eth;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_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_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
// PHY register and MAC registers are mixed together in W5500
|
||||
// The only PHY register is PHYCFGR
|
||||
MAC_CHECK(phy_reg == W5500_REG_PHYCFGR, "wrong PHY register", err, ESP_FAIL);
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_PHYCFGR, ®_value, sizeof(uint8_t)) == ESP_OK, "write PHY register failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_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_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
// PHY register and MAC registers are mixed together in W5500
|
||||
// The only PHY register is PHYCFGR
|
||||
MAC_CHECK(phy_reg == W5500_REG_PHYCFGR, "wrong PHY register", err, ESP_FAIL);
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_PHYCFGR, reg_value, sizeof(uint8_t)) == ESP_OK, "read PHY register failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
MAC_CHECK(addr, "invalid argument", err, ESP_ERR_INVALID_ARG);
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
memcpy(emac->addr, addr, 6);
|
||||
MAC_CHECK(w5500_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
MAC_CHECK(addr, "invalid argument", err, ESP_ERR_INVALID_ARG);
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
memcpy(addr, emac->addr, 6);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_set_link(esp_eth_mac_t *mac, eth_link_t link)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch (link) {
|
||||
case ETH_LINK_UP:
|
||||
ESP_LOGD(TAG, "link is up");
|
||||
MAC_CHECK(mac->start(mac) == ESP_OK, "w5500 start failed", err, ESP_FAIL);
|
||||
break;
|
||||
case ETH_LINK_DOWN:
|
||||
ESP_LOGD(TAG, "link is down");
|
||||
MAC_CHECK(mac->stop(mac) == ESP_OK, "w5500 stop failed", err, ESP_FAIL);
|
||||
break;
|
||||
default:
|
||||
MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
|
||||
break;
|
||||
}
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch (speed) {
|
||||
case ETH_SPEED_10M:
|
||||
ESP_LOGD(TAG, "working in 10Mbps");
|
||||
break;
|
||||
case ETH_SPEED_100M:
|
||||
ESP_LOGD(TAG, "working in 100Mbps");
|
||||
break;
|
||||
default:
|
||||
MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
|
||||
break;
|
||||
}
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
switch (duplex) {
|
||||
case ETH_DUPLEX_HALF:
|
||||
ESP_LOGD(TAG, "working in half duplex");
|
||||
break;
|
||||
case ETH_DUPLEX_FULL:
|
||||
ESP_LOGD(TAG, "working in full duplex");
|
||||
break;
|
||||
default:
|
||||
MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
|
||||
break;
|
||||
}
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_set_promiscuous(esp_eth_mac_t *mac, bool enable)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
uint8_t smr = 0;
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_MR(0), &smr, sizeof(smr)) == ESP_OK, "read SMR failed", err, ESP_FAIL);
|
||||
if (enable) {
|
||||
smr &= ~W5500_SMR_MAC_FILTER;
|
||||
} else {
|
||||
smr |= W5500_SMR_MAC_FILTER;
|
||||
}
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_MR(0), &smr, sizeof(smr)) == ESP_OK, "write SMR failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_enable_flow_ctrl(esp_eth_mac_t *mac, bool enable)
|
||||
{
|
||||
/* w5500 doesn't support flow control function, so accept any value */
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t ability)
|
||||
{
|
||||
/* w5500 doesn't suppport PAUSE function, so accept any value */
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
uint16_t offset = 0;
|
||||
|
||||
// check if there're free memory to store this packet
|
||||
uint16_t free_size = 0;
|
||||
MAC_CHECK(w5500_get_tx_free_size(emac, &free_size) == ESP_OK, "get free size failed", err, ESP_FAIL);
|
||||
MAC_CHECK(length <= free_size, "free size (%d) < send length (%d)", err, ESP_FAIL, free_size, length);
|
||||
// get current write pointer
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_TX_WR(0), &offset, sizeof(offset)) == ESP_OK, "read TX WR failed", err, ESP_FAIL);
|
||||
offset = __builtin_bswap16(offset);
|
||||
// copy data to tx memory
|
||||
MAC_CHECK(w5500_write_buffer(emac, buf, length, offset) == ESP_OK, "write frame failed", err, ESP_FAIL);
|
||||
// update write pointer
|
||||
offset += length;
|
||||
offset = __builtin_bswap16(offset);
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_TX_WR(0), &offset, sizeof(offset)) == ESP_OK, "write TX WR failed", err, ESP_FAIL);
|
||||
// issue SEND command
|
||||
MAC_CHECK(w5500_send_command(emac, W5500_SCR_SEND, 100) == ESP_OK, "issue SEND command failed", err, ESP_FAIL);
|
||||
|
||||
// pooling the TX done event
|
||||
uint8_t status = 0;
|
||||
do {
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)) == ESP_OK, "read SOCK0 IR failed", err, ESP_FAIL);
|
||||
} while (!(status & W5500_SIR_SEND));
|
||||
// clear the event bit
|
||||
status = W5500_SIR_SEND;
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)) == ESP_OK, "write SOCK0 IR failed", err, ESP_FAIL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
uint16_t offset = 0;
|
||||
uint16_t rx_len = 0;
|
||||
uint16_t remain_bytes = 0;
|
||||
emac->packets_remain = false;
|
||||
|
||||
w5500_get_rx_received_size(emac, &remain_bytes);
|
||||
if (remain_bytes) {
|
||||
// get current read pointer
|
||||
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_RX_RD(0), &offset, sizeof(offset)) == ESP_OK, "read RX RD failed", err, ESP_FAIL);
|
||||
offset = __builtin_bswap16(offset);
|
||||
// read head first
|
||||
MAC_CHECK(w5500_read_buffer(emac, &rx_len, sizeof(rx_len), offset) == ESP_OK, "read frame header failed", err, ESP_FAIL);
|
||||
rx_len = __builtin_bswap16(rx_len) - 2; // data size includes 2 bytes of header
|
||||
offset += 2;
|
||||
// read the payload
|
||||
MAC_CHECK(w5500_read_buffer(emac, buf, rx_len, offset) == ESP_OK, "read payload failed, len=%d, offset=%d", err, ESP_FAIL, rx_len, offset);
|
||||
offset += rx_len;
|
||||
// update read pointer
|
||||
offset = __builtin_bswap16(offset);
|
||||
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_RX_RD(0), &offset, sizeof(offset)) == ESP_OK, "write RX RD failed", err, ESP_FAIL);
|
||||
/* issue RECV command */
|
||||
MAC_CHECK(w5500_send_command(emac, W5500_SCR_RECV, 100) == ESP_OK, "issue RECV command failed", err, ESP_FAIL);
|
||||
// check if there're more data need to process
|
||||
remain_bytes -= rx_len + 2;
|
||||
emac->packets_remain = remain_bytes > 0;
|
||||
}
|
||||
|
||||
*length = rx_len;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_init(esp_eth_mac_t *mac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
esp_eth_mediator_t *eth = emac->eth;
|
||||
esp_rom_gpio_pad_select_gpio(emac->int_gpio_num);
|
||||
gpio_set_direction(emac->int_gpio_num, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(emac->int_gpio_num, GPIO_PULLUP_ONLY);
|
||||
gpio_set_intr_type(emac->int_gpio_num, GPIO_INTR_NEGEDGE); // active low
|
||||
gpio_intr_enable(emac->int_gpio_num);
|
||||
gpio_isr_handler_add(emac->int_gpio_num, w5500_isr_handler, emac);
|
||||
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
|
||||
/* reset w5500 */
|
||||
MAC_CHECK(w5500_reset(emac) == ESP_OK, "reset w5500 failed", err, ESP_FAIL);
|
||||
/* verify chip id */
|
||||
MAC_CHECK(w5500_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL);
|
||||
/* default setup of internal registers */
|
||||
MAC_CHECK(w5500_setup_default(emac) == ESP_OK, "w5500 default setup failed", err, ESP_FAIL);
|
||||
return ESP_OK;
|
||||
err:
|
||||
gpio_isr_handler_remove(emac->int_gpio_num);
|
||||
gpio_reset_pin(emac->int_gpio_num);
|
||||
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_deinit(esp_eth_mac_t *mac)
|
||||
{
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
esp_eth_mediator_t *eth = emac->eth;
|
||||
mac->stop(mac);
|
||||
gpio_isr_handler_remove(emac->int_gpio_num);
|
||||
gpio_reset_pin(emac->int_gpio_num);
|
||||
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t emac_w5500_del(esp_eth_mac_t *mac)
|
||||
{
|
||||
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
|
||||
vTaskDelete(emac->rx_task_hdl);
|
||||
vSemaphoreDelete(emac->spi_lock);
|
||||
free(emac);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config)
|
||||
{
|
||||
esp_eth_mac_t *ret = NULL;
|
||||
emac_w5500_t *emac = NULL;
|
||||
MAC_CHECK(w5500_config && mac_config, "invalid argument", err, NULL);
|
||||
emac = calloc(1, sizeof(emac_w5500_t));
|
||||
MAC_CHECK(emac, "no mem for MAC instance", err, NULL);
|
||||
/* w5500 driver is interrupt driven */
|
||||
MAC_CHECK(w5500_config->int_gpio_num >= 0, "invalid interrupt gpio number", err, NULL);
|
||||
/* bind methods and attributes */
|
||||
emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms;
|
||||
emac->int_gpio_num = w5500_config->int_gpio_num;
|
||||
emac->spi_hdl = w5500_config->spi_hdl;
|
||||
emac->parent.set_mediator = emac_w5500_set_mediator;
|
||||
emac->parent.init = emac_w5500_init;
|
||||
emac->parent.deinit = emac_w5500_deinit;
|
||||
emac->parent.start = emac_w5500_start;
|
||||
emac->parent.stop = emac_w5500_stop;
|
||||
emac->parent.del = emac_w5500_del;
|
||||
emac->parent.write_phy_reg = emac_w5500_write_phy_reg;
|
||||
emac->parent.read_phy_reg = emac_w5500_read_phy_reg;
|
||||
emac->parent.set_addr = emac_w5500_set_addr;
|
||||
emac->parent.get_addr = emac_w5500_get_addr;
|
||||
emac->parent.set_speed = emac_w5500_set_speed;
|
||||
emac->parent.set_duplex = emac_w5500_set_duplex;
|
||||
emac->parent.set_link = emac_w5500_set_link;
|
||||
emac->parent.set_promiscuous = emac_w5500_set_promiscuous;
|
||||
emac->parent.set_peer_pause_ability = emac_w5500_set_peer_pause_ability;
|
||||
emac->parent.enable_flow_ctrl = emac_w5500_enable_flow_ctrl;
|
||||
emac->parent.transmit = emac_w5500_transmit;
|
||||
emac->parent.receive = emac_w5500_receive;
|
||||
/* create mutex */
|
||||
emac->spi_lock = xSemaphoreCreateMutex();
|
||||
MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL);
|
||||
/* create w5500 task */
|
||||
BaseType_t core_num = tskNO_AFFINITY;
|
||||
if (mac_config->flags & ETH_MAC_FLAG_PIN_TO_CORE) {
|
||||
core_num = cpu_hal_get_core_id();
|
||||
}
|
||||
BaseType_t xReturned = xTaskCreatePinnedToCore(emac_w5500_task, "w5500_tsk", mac_config->rx_task_stack_size, emac,
|
||||
mac_config->rx_task_prio, &emac->rx_task_hdl, core_num);
|
||||
MAC_CHECK(xReturned == pdPASS, "create w5500 task failed", err, NULL);
|
||||
return &(emac->parent);
|
||||
|
||||
err:
|
||||
if (emac) {
|
||||
if (emac->rx_task_hdl) {
|
||||
vTaskDelete(emac->rx_task_hdl);
|
||||
}
|
||||
if (emac->spi_lock) {
|
||||
vSemaphoreDelete(emac->spi_lock);
|
||||
}
|
||||
free(emac);
|
||||
}
|
||||
return ret;
|
||||
}
|
252
components/esp_eth/src/esp_eth_phy_w5500.c
Normal file
252
components/esp_eth/src/esp_eth_phy_w5500.c
Normal file
@ -0,0 +1,252 @@
|
||||
// Copyright 2020 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "w5500.h"
|
||||
|
||||
static const char *TAG = "w5500-phy";
|
||||
#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 PHYCFGR(PHY Configuration Register)
|
||||
*
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t link: 1; /*!< Link status */
|
||||
uint8_t speed: 1; /*!< Speed status */
|
||||
uint8_t duplex: 1; /*!< Duplex status */
|
||||
uint8_t opmode: 3; /*!< Operation mode */
|
||||
uint8_t opsel: 1; /*!< Operation select */
|
||||
uint8_t reset: 1; /*!< Reset, when this bit is '0', PHY will get reset */
|
||||
};
|
||||
uint8_t val;
|
||||
} phycfg_reg_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
esp_eth_phy_t parent;
|
||||
esp_eth_mediator_t *eth;
|
||||
uint32_t addr;
|
||||
uint32_t reset_timeout_ms;
|
||||
uint32_t autonego_timeout_ms;
|
||||
eth_link_t link_status;
|
||||
int reset_gpio_num;
|
||||
} phy_w5500_t;
|
||||
|
||||
static esp_err_t w5500_update_link_duplex_speed(phy_w5500_t *w5500)
|
||||
{
|
||||
esp_eth_mediator_t *eth = w5500->eth;
|
||||
eth_speed_t speed = ETH_SPEED_10M;
|
||||
eth_duplex_t duplex = ETH_DUPLEX_HALF;
|
||||
phycfg_reg_t phycfg;
|
||||
|
||||
PHY_CHECK(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)) == ESP_OK, "read PHYCFG failed", err);
|
||||
eth_link_t link = phycfg.link ? ETH_LINK_UP : ETH_LINK_DOWN;
|
||||
/* check if link status changed */
|
||||
if (w5500->link_status != link) {
|
||||
/* when link up, read negotiation result */
|
||||
if (link == ETH_LINK_UP) {
|
||||
if (phycfg.speed) {
|
||||
speed = ETH_SPEED_100M;
|
||||
} else {
|
||||
speed = ETH_SPEED_10M;
|
||||
}
|
||||
if (phycfg.duplex) {
|
||||
duplex = ETH_DUPLEX_FULL;
|
||||
} else {
|
||||
duplex = ETH_DUPLEX_HALF;
|
||||
}
|
||||
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
|
||||
"change speed failed", err);
|
||||
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
|
||||
"change duplex failed", err);
|
||||
}
|
||||
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
|
||||
"change link failed", err);
|
||||
w5500->link_status = link;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
|
||||
{
|
||||
PHY_CHECK(eth, "can't set mediator to null", err);
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
w5500->eth = eth;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_get_link(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
/* Updata information about link, speed, duplex */
|
||||
PHY_CHECK(w5500_update_link_duplex_speed(w5500) == ESP_OK, "update link duplex speed failed", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_reset(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
w5500->link_status = ETH_LINK_DOWN;
|
||||
esp_eth_mediator_t *eth = w5500->eth;
|
||||
phycfg_reg_t phycfg;
|
||||
PHY_CHECK(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)) == ESP_OK, "read PHYCFG failed", err);
|
||||
phycfg.reset = 0; // set to '0' will reset internal PHY
|
||||
PHY_CHECK(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val) == ESP_OK, "write PHYCFG failed", err);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
phycfg.reset = 1; // set to '1' after reset
|
||||
PHY_CHECK(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val) == ESP_OK, "write PHYCFG failed", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_reset_hw(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
// set reset_gpio_num to a negative value can skip hardware reset phy chip
|
||||
if (w5500->reset_gpio_num >= 0) {
|
||||
esp_rom_gpio_pad_select_gpio(w5500->reset_gpio_num);
|
||||
gpio_set_direction(w5500->reset_gpio_num, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(w5500->reset_gpio_num, 0);
|
||||
esp_rom_delay_us(100); // insert min input assert time
|
||||
gpio_set_level(w5500->reset_gpio_num, 1);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_negotiate(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
esp_eth_mediator_t *eth = w5500->eth;
|
||||
|
||||
phycfg_reg_t phycfg;
|
||||
PHY_CHECK(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)) == ESP_OK, "read PHYCFG failed", err);
|
||||
phycfg.opsel = 1; // PHY working mode configured by register
|
||||
phycfg.opmode = 7; // all capable, auto-negotiation enabled
|
||||
PHY_CHECK(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val) == ESP_OK, "write PHYCFG failed", err);
|
||||
|
||||
/* Update information about link, speed, duplex */
|
||||
PHY_CHECK(w5500_update_link_duplex_speed(w5500) == ESP_OK, "update link duplex speed failed", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_pwrctl(esp_eth_phy_t *phy, bool enable)
|
||||
{
|
||||
// power control is not supported for W5500 internal PHY
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_set_addr(esp_eth_phy_t *phy, uint32_t addr)
|
||||
{
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
w5500->addr = addr;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
|
||||
{
|
||||
PHY_CHECK(addr, "addr can't be null", err);
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
*addr = w5500->addr;
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_del(esp_eth_phy_t *phy)
|
||||
{
|
||||
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
|
||||
free(w5500);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
|
||||
{
|
||||
// pause ability advertisement is not supported for W5500 internal PHY
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_init(esp_eth_phy_t *phy)
|
||||
{
|
||||
/* Power on Ethernet PHY */
|
||||
PHY_CHECK(w5500_pwrctl(phy, true) == ESP_OK, "power control failed", err);
|
||||
/* Reset Ethernet PHY */
|
||||
PHY_CHECK(w5500_reset(phy) == ESP_OK, "reset failed", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t w5500_deinit(esp_eth_phy_t *phy)
|
||||
{
|
||||
/* Power off Ethernet PHY */
|
||||
PHY_CHECK(w5500_pwrctl(phy, false) == ESP_OK, "power control failed", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_eth_phy_t *esp_eth_phy_new_w5500(const eth_phy_config_t *config)
|
||||
{
|
||||
PHY_CHECK(config, "invalid arguments", err);
|
||||
phy_w5500_t *w5500 = calloc(1, sizeof(phy_w5500_t));
|
||||
PHY_CHECK(w5500, "no mem for PHY instance", err);
|
||||
w5500->addr = config->phy_addr;
|
||||
w5500->reset_timeout_ms = config->reset_timeout_ms;
|
||||
w5500->reset_gpio_num = config->reset_gpio_num;
|
||||
w5500->link_status = ETH_LINK_DOWN;
|
||||
w5500->autonego_timeout_ms = config->autonego_timeout_ms;
|
||||
w5500->parent.reset = w5500_reset;
|
||||
w5500->parent.reset_hw = w5500_reset_hw;
|
||||
w5500->parent.init = w5500_init;
|
||||
w5500->parent.deinit = w5500_deinit;
|
||||
w5500->parent.set_mediator = w5500_set_mediator;
|
||||
w5500->parent.negotiate = w5500_negotiate;
|
||||
w5500->parent.get_link = w5500_get_link;
|
||||
w5500->parent.pwrctl = w5500_pwrctl;
|
||||
w5500->parent.get_addr = w5500_get_addr;
|
||||
w5500->parent.set_addr = w5500_set_addr;
|
||||
w5500->parent.advertise_pause_ability = w5500_advertise_pause_ability;
|
||||
w5500->parent.del = w5500_del;
|
||||
return &(w5500->parent);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
76
components/esp_eth/src/w5500.h
Normal file
76
components/esp_eth/src/w5500.h
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#define W5500_ADDR_OFFSET (16) // Address length
|
||||
#define W5500_BSB_OFFSET (3) // Block Select Bits offset
|
||||
#define W5500_RWB_OFFSET (2) // Read Write Bits offset
|
||||
|
||||
#define W5500_BSB_COM_REG (0x00) // Common Register
|
||||
#define W5500_BSB_SOCK_REG(s) ((s)*4+1) // Socket Register
|
||||
#define W5500_BSB_SOCK_TX_BUF(s) ((s)*4+2) // Socket TX Buffer
|
||||
#define W5500_BSB_SOCK_RX_BUF(s) ((s)*4+3) // Socket RX Buffer
|
||||
|
||||
#define W5500_ACCESS_MODE_READ (0) // Read Mode
|
||||
#define W5500_ACCESS_MODE_WRITE (1) // Write Mode
|
||||
|
||||
#define W5500_SPI_OP_MODE_VDM (0x00) // Variable Data Length Mode (SPI frame is controlled by CS line)
|
||||
#define W5500_SPI_OP_MODE_FDM_1 (0x01) // Fixed Data Length Mode, 1 Byte Length
|
||||
#define W5500_SPI_OP_MODE_FDM_2 (0x02) // Fixed Data Length Mode, 2 Bytes Length
|
||||
#define W5500_SPI_OP_MODE_FDM_4 (0x03) // Fixed Data Length Mode, 4 Bytes Length
|
||||
|
||||
#define W5500_MAKE_MAP(offset, bsb) ((offset) << W5500_ADDR_OFFSET | (bsb) << W5500_BSB_OFFSET)
|
||||
|
||||
#define W5500_REG_MR W5500_MAKE_MAP(0x0000, W5500_BSB_COM_REG) // Mode
|
||||
#define W5500_REG_MAC W5500_MAKE_MAP(0x0009, W5500_BSB_COM_REG) // MAC Address
|
||||
#define W5500_REG_IR W5500_MAKE_MAP(0x0015, W5500_BSB_COM_REG) // Interrupt
|
||||
#define W5500_REG_IMR W5500_MAKE_MAP(0x0016, W5500_BSB_COM_REG) // Interrupt Mask
|
||||
#define W5500_REG_SIR W5500_MAKE_MAP(0x0017, W5500_BSB_COM_REG) // Socket Interrupt
|
||||
#define W5500_REG_SIMR W5500_MAKE_MAP(0x0018, W5500_BSB_COM_REG) // Socket Interrupt Mask
|
||||
#define W5500_REG_RTR W5500_MAKE_MAP(0x0019, W5500_BSB_COM_REG) // Retry Time
|
||||
#define W5500_REG_RCR W5500_MAKE_MAP(0x001B, W5500_BSB_COM_REG) // Retry Count
|
||||
#define W5500_REG_PHYCFGR W5500_MAKE_MAP(0x002E, W5500_BSB_COM_REG) // PHY Configuration
|
||||
#define W5500_REG_VERSIONR W5500_MAKE_MAP(0x0039, W5500_BSB_COM_REG) // Chip version
|
||||
|
||||
#define W5500_REG_SOCK_MR(s) W5500_MAKE_MAP(0x0000, W5500_BSB_SOCK_REG(s)) // Socket Mode
|
||||
#define W5500_REG_SOCK_CR(s) W5500_MAKE_MAP(0x0001, W5500_BSB_SOCK_REG(s)) // Socket Command
|
||||
#define W5500_REG_SOCK_IR(s) W5500_MAKE_MAP(0x0002, W5500_BSB_SOCK_REG(s)) // Socket Interrupt
|
||||
#define W5500_REG_SOCK_SR(s) W5500_MAKE_MAP(0x0004, W5500_BSB_SOCK_REG(s)) // Socket Status
|
||||
#define W5500_REG_SOCK_RXBUF_SIZE(s) W5500_MAKE_MAP(0x001E, W5500_BSB_SOCK_REG(s)) // Socket Receive Buffer Size
|
||||
#define W5500_REG_SOCK_TXBUF_SIZE(s) W5500_MAKE_MAP(0x001F, W5500_BSB_SOCK_REG(s)) // Socket Transmit Buffer Size
|
||||
#define W5500_REG_SOCK_TX_FSR(s) W5500_MAKE_MAP(0x0020, W5500_BSB_SOCK_REG(s)) // Socket TX Free Size
|
||||
#define W5500_REG_SOCK_TX_RD(s) W5500_MAKE_MAP(0x0022, W5500_BSB_SOCK_REG(s)) // Socket TX Read Pointer
|
||||
#define W5500_REG_SOCK_TX_WR(s) W5500_MAKE_MAP(0x0024, W5500_BSB_SOCK_REG(s)) // Socket TX Write Pointer
|
||||
#define W5500_REG_SOCK_RX_RSR(s) W5500_MAKE_MAP(0x0026, W5500_BSB_SOCK_REG(s)) // Socket RX Received Size
|
||||
#define W5500_REG_SOCK_RX_RD(s) W5500_MAKE_MAP(0x0028, W5500_BSB_SOCK_REG(s)) // Socket RX Read Pointer
|
||||
#define W5500_REG_SOCK_RX_WR(s) W5500_MAKE_MAP(0x002A, W5500_BSB_SOCK_REG(s)) // Socket RX Write Pointer
|
||||
#define W5500_REG_SOCK_IMR(s) W5500_MAKE_MAP(0x002C, W5500_BSB_SOCK_REG(s)) // Socket Interrupt Mask
|
||||
|
||||
#define W5500_MEM_SOCK_TX(s,addr) W5500_MAKE_MAP(addr, W5500_BSB_SOCK_TX_BUF(s)) // Socket TX buffer address
|
||||
#define W5500_MEM_SOCK_RX(s,addr) W5500_MAKE_MAP(addr, W5500_BSB_SOCK_RX_BUF(s)) // Socket RX buffer address
|
||||
|
||||
#define W5500_MR_RST (1<<7) // Software reset
|
||||
#define W5500_MR_PB (1<<4) // Ping block (block the response to a ping request)
|
||||
|
||||
#define W5500_SIMR_SOCK0 (1<<0) // Socket 0 interrupt
|
||||
|
||||
#define W5500_SMR_MAC_RAW (1<<2) // MAC RAW mode
|
||||
#define W5500_SMR_MAC_FILTER (1<<7) // MAC filter
|
||||
|
||||
#define W5500_SCR_OPEN (0x01) // Open command
|
||||
#define W5500_SCR_CLOSE (0x10) // Close command
|
||||
#define W5500_SCR_SEND (0x20) // Send command
|
||||
#define W5500_SCR_RECV (0x40) // Recv command
|
||||
|
||||
#define W5500_SIR_RECV (1<<2) // Receive done
|
||||
#define W5500_SIR_SEND (1<<4) // Send done
|
@ -1,131 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
|
||||
static const char *TAG = "dm9051_test";
|
||||
|
||||
#define ETH_START_BIT BIT(0)
|
||||
#define ETH_STOP_BIT BIT(1)
|
||||
#define ETH_CONNECT_BIT BIT(2)
|
||||
#define ETH_GOT_IP_BIT BIT(3)
|
||||
|
||||
#define ETH_START_TIMEOUT_MS (10000)
|
||||
#define ETH_CONNECT_TIMEOUT_MS (40000)
|
||||
#define ETH_STOP_TIMEOUT_MS (10000)
|
||||
#define ETH_GET_IP_TIMEOUT_MS (60000)
|
||||
|
||||
/** 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)
|
||||
{
|
||||
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT);
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
break;
|
||||
case ETHERNET_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Down");
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
xEventGroupSetBits(eth_event_group, ETH_START_BIT);
|
||||
ESP_LOGI(TAG, "Ethernet Started");
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
xEventGroupSetBits(eth_event_group, ETH_STOP_BIT);
|
||||
ESP_LOGI(TAG, "Ethernet Stopped");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
ESP_LOGI(TAG, "Ethernet Got IP Address");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
|
||||
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
|
||||
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT);
|
||||
}
|
||||
|
||||
TEST_CASE("dm9051 io test", "[ethernet][dm9051][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);
|
||||
test_case_uses_tcpip();
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
// create TCP/IP netif
|
||||
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
esp_netif_t *eth_netif = esp_netif_new(&cfg);
|
||||
// set default handlers to do layer 3 (and up) stuffs
|
||||
TEST_ESP_OK(esp_eth_set_default_handlers(eth_netif));
|
||||
// register user defined event handers
|
||||
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();
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &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;
|
||||
// install Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle));
|
||||
// combine driver with netif
|
||||
void *glue = esp_eth_new_netif_glue(eth_handle);
|
||||
TEST_ESP_OK(esp_netif_attach(eth_netif, glue));
|
||||
// start Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
||||
/* wait for IP lease */
|
||||
vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY));
|
||||
// stop Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_stop(eth_handle));
|
||||
TEST_ESP_OK(esp_eth_del_netif_glue(glue));
|
||||
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_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
|
||||
TEST_ESP_OK(esp_eth_clear_default_handlers(eth_netif));
|
||||
esp_netif_destroy(eth_netif);
|
||||
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
|
@ -67,7 +67,7 @@ all: $(TEST_NAME)
|
||||
|
||||
mdns.o: ../mdns.c
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) --include mdns_mock.h $(MDNS_C_DEPENDENCY_INJECTION) -c $< -o $@
|
||||
@$(CC) $(CFLAGS) -include mdns_mock.h $(MDNS_C_DEPENDENCY_INJECTION) -c $< -o $@
|
||||
|
||||
$(TEST_NAME): $(OBJECTS)
|
||||
@echo "[LD] $@"
|
||||
|
@ -79,7 +79,7 @@ typedef volatile struct {
|
||||
struct {
|
||||
uint32_t miibusy : 1; /*This bit should read logic 0 before writing to PHY Addr Register and PHY data Register.During a PHY register access the software sets this bit to 1'b1 to indicate that a Read or Write access is in progress. PHY data Register is invalid until this bit is cleared by the MAC. Therefore PHY data Register (MII Data) should be kept valid until the MAC clears this bit during a PHY Write operation. Similarly for a read operation the contents of Register 5 are not valid until this bit is cleared. The subsequent read or write operation should happen only after the previous operation is complete. Because there is no acknowledgment from the PHY to MAC after a read or write operation is completed there is no change in the functionality of this bit even when the PHY is not Present.*/
|
||||
uint32_t miiwrite : 1; /*When set this bit indicates to the PHY that this is a Write operation using the MII Data register. If this bit is not set it indicates that this is a Read operation that is placing the data in the MII Data register.*/
|
||||
uint32_t miicsrclk : 4; /*CSR clock range: 1.0 MHz ~ 2.5 MHz. 4'b0000: When the APB clock frequency is 80 MHz the MDC clock frequency is APB CLK/42 4'b0000: When the APB clock frequency is 40 MHz the MDC clock frequency is APB CLK/26.*/
|
||||
uint32_t miicsrclk : 4; /*CSR clock range: 1.0 MHz ~ 2.5 MHz. 4'b0000: When the APB clock frequency is 80 MHz the MDC clock frequency is APB CLK/42 4'b0011: When the APB clock frequency is 40 MHz the MDC clock frequency is APB CLK/26.*/
|
||||
uint32_t miireg : 5; /*These bits select the desired MII register in the selected PHY device.*/
|
||||
uint32_t miidev : 5; /*This field indicates which of the 32 possible PHY devices are being accessed.*/
|
||||
uint32_t reserved16 : 16;
|
||||
|
@ -33,7 +33,7 @@ menu "Example Connection Configuration"
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_W5500
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
@ -51,6 +51,13 @@ menu "Example Connection Configuration"
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
|
||||
config EXAMPLE_USE_W5500
|
||||
bool "W5500 Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_W5500
|
||||
help
|
||||
Select external SPI-Ethernet module (W5500).
|
||||
|
||||
config EXAMPLE_USE_OPENETH
|
||||
bool "OpenCores Ethernet MAC (EXPERIMENTAL)"
|
||||
select ETH_USE_OPENETH
|
||||
@ -108,55 +115,55 @@ menu "Example Connection Configuration"
|
||||
Set the GPIO number used by SMI MDIO.
|
||||
endif
|
||||
|
||||
if EXAMPLE_USE_DM9051
|
||||
config EXAMPLE_DM9051_SPI_HOST
|
||||
if ETH_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.
|
||||
Set the SPI host used to communicate with the SPI Ethernet Controller.
|
||||
|
||||
config EXAMPLE_DM9051_SCLK_GPIO
|
||||
config EXAMPLE_ETH_SPI_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
default 20
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_DM9051_MOSI_GPIO
|
||||
config EXAMPLE_ETH_SPI_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_DM9051_MISO_GPIO
|
||||
config EXAMPLE_ETH_SPI_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_DM9051_CS_GPIO
|
||||
config EXAMPLE_ETH_SPI_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
default 21
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_DM9051_SPI_CLOCK_MHZ
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
default 36
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
|
||||
config EXAMPLE_DM9051_INT_GPIO
|
||||
config EXAMPLE_ETH_SPI_INT_GPIO
|
||||
int "Interrupt GPIO number"
|
||||
default 4
|
||||
help
|
||||
Set the GPIO number used by DM9051 interrupt.
|
||||
endif
|
||||
Set the GPIO number used by the SPI Ethernet module interrupt line.
|
||||
endif # ETH_USE_SPI_ETHERNET
|
||||
|
||||
config EXAMPLE_ETH_PHY_RST_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
@ -168,7 +175,6 @@ menu "Example Connection Configuration"
|
||||
config EXAMPLE_ETH_PHY_ADDR
|
||||
int "PHY Address"
|
||||
range 0 31 if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
default 1
|
||||
help
|
||||
Set PHY address according your board schematic.
|
||||
|
@ -15,7 +15,10 @@
|
||||
#include "esp_wifi_default.h"
|
||||
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#include "esp_eth.h"
|
||||
#endif
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "driver/gpio.h"
|
||||
@ -60,17 +63,17 @@ static const char *s_ipv6_addr_types[] = {
|
||||
"ESP_IP6_ADDR_IS_SITE_LOCAL",
|
||||
"ESP_IP6_ADDR_IS_UNIQUE_LOCAL",
|
||||
"ESP_IP6_ADDR_IS_IPV4_MAPPED_IPV6"
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char *TAG = "example_connect";
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
static esp_netif_t* wifi_start(void);
|
||||
static esp_netif_t *wifi_start(void);
|
||||
static void wifi_stop(void);
|
||||
#endif
|
||||
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
static esp_netif_t* eth_start(void);
|
||||
static esp_netif_t *eth_start(void);
|
||||
static void eth_stop(void);
|
||||
#endif
|
||||
|
||||
@ -81,7 +84,7 @@ static void eth_stop(void);
|
||||
*/
|
||||
static bool is_our_netif(const char *prefix, esp_netif_t *netif)
|
||||
{
|
||||
return strncmp(prefix, esp_netif_get_desc(netif), strlen(prefix)-1) == 0;
|
||||
return strncmp(prefix, esp_netif_get_desc(netif), strlen(prefix) - 1) == 0;
|
||||
}
|
||||
|
||||
/* set up connection, Wi-Fi and/or Ethernet */
|
||||
@ -153,7 +156,7 @@ static void on_got_ipv6(void *arg, esp_event_base_t event_base,
|
||||
}
|
||||
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
|
||||
ESP_LOGI(TAG, "Got IPv6 event: Interface \"%s\" address: " IPV6STR ", type: %s", esp_netif_get_desc(event->esp_netif),
|
||||
IPV62STR(event->ip6_info.ip), s_ipv6_addr_types[ipv6_type]);
|
||||
IPV62STR(event->ip6_info.ip), s_ipv6_addr_types[ipv6_type]);
|
||||
if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) {
|
||||
memcpy(&s_ipv6_addr, &event->ip6_info.ip, sizeof(s_ipv6_addr));
|
||||
xSemaphoreGive(s_semph_get_ip_addrs);
|
||||
@ -172,13 +175,13 @@ esp_err_t example_connect(void)
|
||||
start();
|
||||
ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop));
|
||||
ESP_LOGI(TAG, "Waiting for IP(s)");
|
||||
for (int i=0; i<NR_OF_IP_ADDRESSES_TO_WAIT_FOR; ++i) {
|
||||
for (int i = 0; i < NR_OF_IP_ADDRESSES_TO_WAIT_FOR; ++i) {
|
||||
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
|
||||
}
|
||||
// iterate over active interfaces, and print out IPs of "our" netifs
|
||||
esp_netif_t *netif = NULL;
|
||||
esp_netif_ip_info_t ip;
|
||||
for (int i=0; i<esp_netif_get_nr_of_ifs(); ++i) {
|
||||
for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) {
|
||||
netif = esp_netif_next(netif);
|
||||
if (is_our_netif(TAG, netif)) {
|
||||
ESP_LOGI(TAG, "Connected to %s", esp_netif_get_desc(netif));
|
||||
@ -188,7 +191,7 @@ esp_err_t example_connect(void)
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
esp_ip6_addr_t ip6[MAX_IP6_ADDRS_PER_NETIF];
|
||||
int ip6_addrs = esp_netif_get_all_ip6(netif, ip6);
|
||||
for (int j=0; j< ip6_addrs; ++j) {
|
||||
for (int j = 0; j < ip6_addrs; ++j) {
|
||||
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j]));
|
||||
ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(ip6[j]), s_ipv6_addr_types[ipv6_type]);
|
||||
}
|
||||
@ -234,7 +237,7 @@ static void on_wifi_connect(void *esp_netif, esp_event_base_t event_base,
|
||||
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
static esp_netif_t* wifi_start(void)
|
||||
static esp_netif_t *wifi_start(void)
|
||||
{
|
||||
char *desc;
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
@ -318,7 +321,7 @@ static esp_eth_mac_t *s_mac = NULL;
|
||||
static esp_eth_phy_t *s_phy = NULL;
|
||||
static void *s_eth_glue = NULL;
|
||||
|
||||
static esp_netif_t* eth_start(void)
|
||||
static esp_netif_t *eth_start(void)
|
||||
{
|
||||
char *desc;
|
||||
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
|
||||
@ -328,8 +331,8 @@ static esp_netif_t* eth_start(void)
|
||||
esp_netif_config.if_desc = desc;
|
||||
esp_netif_config.route_prio = 64;
|
||||
esp_netif_config_t netif_config = {
|
||||
.base = &esp_netif_config,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
|
||||
.base = &esp_netif_config,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
|
||||
};
|
||||
esp_netif_t *netif = esp_netif_new(&netif_config);
|
||||
assert(netif);
|
||||
@ -359,31 +362,48 @@ static esp_netif_t* eth_start(void)
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
|
||||
s_phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_DM9051
|
||||
#elif CONFIG_ETH_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_DM9051_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO,
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
#if CONFIG_EXAMPLE_USE_DM9051
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_INT_GPIO;
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_W5500
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
|
||||
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_OPENETH
|
||||
phy_config.autonego_timeout_ms = 100;
|
||||
s_mac = esp_eth_mac_new_openeth(&mac_config);
|
||||
@ -393,6 +413,14 @@ static esp_netif_t* eth_start(void)
|
||||
// Install Ethernet driver
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
|
||||
#if !CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
|
||||
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
|
||||
*/
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
|
||||
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
|
||||
}));
|
||||
#endif
|
||||
// combine driver with netif
|
||||
s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
|
||||
esp_netif_attach(netif, s_eth_glue);
|
||||
|
@ -2,7 +2,7 @@ menu "Example Configuration"
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_W5500
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
@ -20,7 +20,13 @@ menu "Example Configuration"
|
||||
help
|
||||
Select external SPI-Ethernet module (DM9051).
|
||||
|
||||
endchoice
|
||||
config EXAMPLE_USE_W5500
|
||||
bool "W5500 Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_W5500
|
||||
help
|
||||
Select external SPI-Ethernet module (W5500).
|
||||
endchoice # EXAMPLE_USE_ETHERNET
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
@ -58,7 +64,7 @@ menu "Example Configuration"
|
||||
help
|
||||
The KSZ8041 is a single supply 10Base-T/100Base-TX Physical Layer Transceiver.
|
||||
Goto https://www.microchip.com/wwwproducts/en/KSZ8041 for more information about it.
|
||||
endchoice
|
||||
endchoice # EXAMPLE_ETH_PHY_MODEL
|
||||
|
||||
config EXAMPLE_ETH_MDC_GPIO
|
||||
int "SMI MDC GPIO number"
|
||||
@ -71,57 +77,57 @@ menu "Example Configuration"
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SMI MDIO.
|
||||
endif
|
||||
endif # EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
|
||||
if EXAMPLE_USE_DM9051
|
||||
config EXAMPLE_DM9051_SPI_HOST
|
||||
if ETH_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 the SPI Ethernet Controller.
|
||||
|
||||
config EXAMPLE_DM9051_SCLK_GPIO
|
||||
config EXAMPLE_ETH_SPI_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
default 20
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_DM9051_MOSI_GPIO
|
||||
config EXAMPLE_ETH_SPI_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_DM9051_MISO_GPIO
|
||||
config EXAMPLE_ETH_SPI_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_DM9051_CS_GPIO
|
||||
config EXAMPLE_ETH_SPI_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
default 21
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_DM9051_SPI_CLOCK_MHZ
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 5 80
|
||||
default 20
|
||||
default 36
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
|
||||
config EXAMPLE_DM9051_INT_GPIO
|
||||
config EXAMPLE_ETH_SPI_INT_GPIO
|
||||
int "Interrupt GPIO number"
|
||||
default 4
|
||||
help
|
||||
Set the GPIO number used by DM9051 interrupt.
|
||||
endif
|
||||
Set the GPIO number used by the SPI Ethernet module interrupt line.
|
||||
endif # ETH_USE_SPI_ETHERNET
|
||||
|
||||
config EXAMPLE_ETH_PHY_RST_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
@ -132,8 +138,7 @@ menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_ETH_PHY_ADDR
|
||||
int "PHY Address"
|
||||
range 0 31 if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 0 31
|
||||
default 1
|
||||
help
|
||||
Set PHY address according your board schematic.
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
|
||||
static const char *TAG = "eth_example";
|
||||
|
||||
@ -96,35 +99,60 @@ void app_main(void)
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ8041
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_ksz8041(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_DM9051
|
||||
#elif CONFIG_ETH_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_DM9051_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO,
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
#if CONFIG_EXAMPLE_USE_DM9051
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_INT_GPIO;
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_W5500
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
|
||||
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
#endif
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
esp_eth_handle_t eth_handle = NULL;
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
|
||||
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
|
||||
*/
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
|
||||
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
|
||||
}));
|
||||
#endif
|
||||
/* attach Ethernet driver to TCP/IP stack */
|
||||
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
|
||||
/* start Ethernet driver state machine */
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_netif.h"
|
||||
@ -16,7 +17,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "enc28j60.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
static const char *TAG = "eth_example";
|
||||
|
||||
|
@ -2,7 +2,7 @@ menu "Example Configuration"
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_W5500
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
@ -18,8 +18,15 @@ menu "Example Configuration"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_DM9051
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
endchoice
|
||||
Select external SPI-Ethernet module (DM9051).
|
||||
|
||||
config EXAMPLE_USE_W5500
|
||||
bool "W5500 Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_W5500
|
||||
help
|
||||
Select external SPI-Ethernet module (W5500).
|
||||
endchoice # EXAMPLE_USE_ETHERNET
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
@ -51,7 +58,13 @@ menu "Example 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
|
||||
|
||||
config EXAMPLE_ETH_PHY_KSZ8041
|
||||
bool "KSZ8041"
|
||||
help
|
||||
The KSZ8041 is a single supply 10Base-T/100Base-TX Physical Layer Transceiver.
|
||||
Goto https://www.microchip.com/wwwproducts/en/KSZ8041 for more information about it.
|
||||
endchoice # EXAMPLE_ETH_PHY_MODEL
|
||||
|
||||
config EXAMPLE_ETH_MDC_GPIO
|
||||
int "SMI MDC GPIO number"
|
||||
@ -64,57 +77,57 @@ menu "Example Configuration"
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SMI MDIO.
|
||||
endif
|
||||
endif # EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
|
||||
if EXAMPLE_USE_DM9051
|
||||
config EXAMPLE_DM9051_SPI_HOST
|
||||
if ETH_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.
|
||||
Set the SPI host used to communicate with the SPI Ethernet Controller.
|
||||
|
||||
config EXAMPLE_DM9051_SCLK_GPIO
|
||||
config EXAMPLE_ETH_SPI_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
default 20
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_DM9051_MOSI_GPIO
|
||||
config EXAMPLE_ETH_SPI_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_DM9051_MISO_GPIO
|
||||
config EXAMPLE_ETH_SPI_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_DM9051_CS_GPIO
|
||||
config EXAMPLE_ETH_SPI_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
default 21
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_DM9051_SPI_CLOCK_MHZ
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
range 5 80
|
||||
default 36
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
|
||||
config EXAMPLE_DM9051_INT_GPIO
|
||||
config EXAMPLE_ETH_SPI_INT_GPIO
|
||||
int "Interrupt GPIO number"
|
||||
default 4
|
||||
help
|
||||
Set the GPIO number used by DM9051 interrupt.
|
||||
endif
|
||||
Set the GPIO number used by the SPI Ethernet module interrupt line.
|
||||
endif # ETH_USE_SPI_ETHERNET
|
||||
|
||||
config EXAMPLE_ETH_PHY_RST_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
@ -125,8 +138,7 @@ menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_ETH_PHY_ADDR
|
||||
int "PHY Address"
|
||||
range 0 31 if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 0 31
|
||||
default 1
|
||||
help
|
||||
Set PHY address according your board schematic.
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
@ -18,7 +19,9 @@
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_private/wifi.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "eth_example";
|
||||
static esp_eth_handle_t s_eth_handle = NULL;
|
||||
@ -51,7 +54,7 @@ static esp_err_t pkt_wifi2eth(void *buffer, uint16_t len, void *eb)
|
||||
// Forward packets from Ethernet to Wi-Fi
|
||||
// Note that, Ethernet works faster than Wi-Fi on ESP32,
|
||||
// so we need to add an extra queue to balance their speed difference.
|
||||
static esp_err_t pkt_eth2wifi(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t len, void* priv)
|
||||
static esp_err_t pkt_eth2wifi(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t len, void *priv)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
flow_control_msg_t msg = {
|
||||
@ -166,36 +169,63 @@ 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);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ8041
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_ksz8041(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_DM9051
|
||||
#elif CONFIG_ETH_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_DM9051_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO,
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
#if CONFIG_EXAMPLE_USE_DM9051
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_INT_GPIO;
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_W5500
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
|
||||
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
#endif
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
config.stack_input = pkt_eth2wifi;
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
|
||||
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
|
||||
*/
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
|
||||
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
|
||||
}));
|
||||
#endif
|
||||
esp_eth_ioctl(s_eth_handle, ETH_CMD_S_PROMISCUOUS, (void *)true);
|
||||
esp_eth_start(s_eth_handle);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ menu "Example Configuration"
|
||||
choice EXAMPLE_USE_ETHERNET
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_DM9051 if !IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_W5500
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
@ -26,8 +26,15 @@ menu "Example Configuration"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_DM9051
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
endchoice
|
||||
Select external SPI-Ethernet module (DM9051).
|
||||
|
||||
config EXAMPLE_USE_W5500
|
||||
bool "W5500 Module"
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_W5500
|
||||
help
|
||||
Select external SPI-Ethernet module (W5500).
|
||||
endchoice # EXAMPLE_USE_ETHERNET
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
@ -59,7 +66,13 @@ menu "Example 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
|
||||
|
||||
config EXAMPLE_ETH_PHY_KSZ8041
|
||||
bool "KSZ8041"
|
||||
help
|
||||
The KSZ8041 is a single supply 10Base-T/100Base-TX Physical Layer Transceiver.
|
||||
Goto https://www.microchip.com/wwwproducts/en/KSZ8041 for more information about it.
|
||||
endchoice # EXAMPLE_ETH_PHY_MODEL
|
||||
|
||||
config EXAMPLE_ETH_MDC_GPIO
|
||||
int "SMI MDC GPIO number"
|
||||
@ -72,57 +85,57 @@ menu "Example Configuration"
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SMI MDIO.
|
||||
endif
|
||||
endif # EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
|
||||
if EXAMPLE_USE_DM9051
|
||||
config EXAMPLE_DM9051_SPI_HOST
|
||||
if ETH_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.
|
||||
Set the SPI host used to communicate with the SPI Ethernet Controller.
|
||||
|
||||
config EXAMPLE_DM9051_SCLK_GPIO
|
||||
config EXAMPLE_ETH_SPI_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range 0 33
|
||||
default 19
|
||||
default 20
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_DM9051_MOSI_GPIO
|
||||
config EXAMPLE_ETH_SPI_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range 0 33
|
||||
default 23
|
||||
default 19
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_DM9051_MISO_GPIO
|
||||
config EXAMPLE_ETH_SPI_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range 0 33
|
||||
default 25
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_DM9051_CS_GPIO
|
||||
config EXAMPLE_ETH_SPI_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range 0 33
|
||||
default 22
|
||||
default 21
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_DM9051_SPI_CLOCK_MHZ
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 20 80
|
||||
default 20
|
||||
range 5 80
|
||||
default 36
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
|
||||
config EXAMPLE_DM9051_INT_GPIO
|
||||
config EXAMPLE_ETH_SPI_INT_GPIO
|
||||
int "Interrupt GPIO number"
|
||||
default 4
|
||||
help
|
||||
Set the GPIO number used by DM9051 interrupt.
|
||||
endif
|
||||
Set the GPIO number used by the SPI Ethernet module interrupt line.
|
||||
endif # ETH_USE_SPI_ETHERNET
|
||||
|
||||
config EXAMPLE_ETH_PHY_RST_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
@ -133,8 +146,7 @@ menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_ETH_PHY_ADDR
|
||||
int "PHY Address"
|
||||
range 0 31 if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 1 1 if !EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
range 0 31
|
||||
default 1
|
||||
help
|
||||
Set PHY address according your board schematic.
|
||||
|
@ -19,6 +19,9 @@
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "iperf.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
|
||||
static esp_netif_ip_info_t ip;
|
||||
static bool started = false;
|
||||
@ -202,35 +205,62 @@ void register_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);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ8041
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_ksz8041(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_DM9051
|
||||
#elif CONFIG_ETH_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_DM9051_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_DM9051_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_DM9051_SCLK_GPIO,
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_DM9051_SPI_HOST, &buscfg, 1));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
#if CONFIG_EXAMPLE_USE_DM9051
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_DM9051_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_DM9051_CS_GPIO,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_DM9051_SPI_HOST, &devcfg, &spi_handle));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_DM9051_INT_GPIO;
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_W5500
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
|
||||
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
#endif
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
|
||||
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
|
||||
*/
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
|
||||
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
|
||||
}));
|
||||
#endif
|
||||
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
|
||||
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user