Skip to content

Added support for W5500 via. esp_netif_t interface. #7163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions cores/esp32/esp32-hal-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "soc/gpio_sig_map.h"
#include "soc/rtc.h"
#include "driver/periph_ctrl.h"
#include "driver/spi_master.h"

#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
Expand Down Expand Up @@ -136,8 +137,11 @@ static spi_t _spi_bus_array[] = {
#endif
};
#else
#define SPI_MUTEX_LOCK() do {} while (xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS)
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock)
#define SPI_MUTEX_LOCK() if (spi_handle != NULL && spi->num == spi_host) { spi_lock_error = spi_device_acquire_bus(spi_handle, portMAX_DELAY); }\
do {} while ((xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS));\
locked_handle = xTaskGetCurrentTaskHandle();
#define SPI_MUTEX_UNLOCK() if (spi_handle != NULL && spi_lock_error == ESP_OK) { spi_device_release_bus(spi_handle); }\
if (locked_handle == xTaskGetCurrentTaskHandle()) { xSemaphoreGive(spi->lock); }

static spi_t _spi_bus_array[] = {
#if CONFIG_IDF_TARGET_ESP32S2
Expand All @@ -158,6 +162,11 @@ static spi_t _spi_bus_array[] = {
};
#endif

spi_device_handle_t spi_handle = NULL;
TaskHandle_t locked_handle = NULL;
uint8_t spi_host = 0;
esp_err_t spi_lock_error = ESP_FAIL;

void spiAttachSCK(spi_t * spi, int8_t sck)
{
if(!spi) {
Expand Down Expand Up @@ -632,6 +641,13 @@ uint8_t spiGetBitOrder(spi_t * spi)
return (spi->dev->ctrl.wr_bit_order | spi->dev->ctrl.rd_bit_order) == 0;
}

void spiSetDeviceHandle(void * spi_device_handle, uint8_t spi_host_device)
{
spi_handle = spi_device_handle;
// Increase number by 1, because SPI_HOST_1 is 0, SPI_HOST_2 is 1 and SPI_HOST_3 is 2.
spi_host = spi_host_device + 1U;
}

void spiSetBitOrder(spi_t * spi, uint8_t bitOrder)
{
if(!spi) {
Expand Down
2 changes: 1 addition & 1 deletion cores/esp32/esp32-hal-spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void spiWaitReady(spi_t * spi);
uint32_t spiGetClockDiv(spi_t * spi);
uint8_t spiGetDataMode(spi_t * spi);
uint8_t spiGetBitOrder(spi_t * spi);

void spiSetDeviceHandle(void * spi_device_handle, uint8_t spi_host_device);

/*
* Non transaction based lock methods (each locks and unlocks when called)
Expand Down
Empty file.
Empty file.
Empty file.
92 changes: 92 additions & 0 deletions libraries/Ethernet/examples/ETH_W5500/ETH_W5500.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
This sketch shows the Ethernet event usage

*/

#include <ETH.h>

#define MOSI_GPIO 23
#define MISO_GPIO 38
#define SCLK_GPIO 18
#define CS_GPIO 26
#define INT_GPIO 34
#define PHY_RST_GPIO 19

static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case ARDUINO_EVENT_ETH_START:
Serial.println("ETH Started");
//set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
}

void testClient(const char * host, uint16_t port)
{
Serial.print("\nconnecting to ");
Serial.println(host);

WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available());
while (client.available()) {
Serial.write(client.read());
}

Serial.println("closing connection\n");
client.stop();
}

void setup()
{
Serial.begin(115200);
WiFi.onEvent(WiFiEvent);

std::array<uint8_t, 6U> mac_address;
WiFi.macAddress(mac_address.data());
ETH.begin_w5500(mac_address.data(), MOSI_GPIO, MISO_GPIO, SCLK_GPIO, CS_GPIO, INT_GPIO, PHY_RST_GPIO);
SPI.setSpiDeviceHandle(ETH.getSpiDeviceHandle(), ETH.getSpiHost());
}


void loop()
{
if (eth_connected) {
testClient("google.com", 80);
}
delay(10000);
}
137 changes: 137 additions & 0 deletions libraries/Ethernet/src/ETH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@
#include "lwip/err.h"
#include "lwip/dns.h"


#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
#include <hal/spi_hal.h>
#include <driver/spi_common_internal.h>
#endif

extern void tcpipInit();

#if ESP_IDF_VERSION_MAJOR > 3
Expand Down Expand Up @@ -399,6 +405,137 @@ bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_typ
return true;
}

#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
bool ETHClass::beginW5500(uint8_t* mac_address, int8_t mosi_gpio, int8_t miso_gpio, int8_t slck_gpio, int8_t cs_gpio, int8_t int_gpio, int8_t phy_rst_gpio, uint32_t mac_stack_size, int spi_max_transfer_size, spi_common_dma_t spi_dma_channel, uint8_t phy_addr, uint8_t spi_clock_mhz, spi_host_device_t spi_host, eth_phy_type_t type) {
if (type != ETH_PHY_W5500) {
log_e("Using this ETH.begin() method does not support other ethernet modules, besides the W5500.");
return false;
}
else if (mac_address == nullptr) {
log_e("Passed mac address needs to be a valid array the w5500 should be initalized with.");
return false;
}
else if (spi_clock_mhz > 80U) {
log_e("Using a higher spi clock speed than 80MHz is not possible.");
return false;
}
else if (spi_clock_mhz > 30U) {
log_w("Using a higher spi clock speed than 30MHz is possible, but not recommended as it might cause distortions.");
}

// Initializes TCP/IP network interface (should be called only once in application)
// and create default event loop that is running in the background.
tcpipInit();
esp_err_t error = tcpip_adapter_set_default_eth_handlers();
if (error != ESP_OK) {
log_e("Method: (tcpip_adapter_set_default_eth_handlers) failed with error: (%s)", esp_err_to_name(error));
return false;
}

// Create instance of esp-netif for SPI Ethernet.
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
esp_netif_config_t cfg_spi = {
.base = &esp_netif_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
};
esp_netif_t *eth_netif = esp_netif_new(&cfg_spi);

eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.rx_task_stack_size = mac_stack_size;

// Install GPIO ISR handler to be able to service SPI Eth modlues interrupts.
error = gpio_install_isr_service(0);
if (error != ESP_OK) {
log_e("Method: (gpio_install_isr_service) failed with error: (%s)", esp_err_to_name(error));
return false;
}

spi_device_handle = nullptr;
spi_bus_config_t buscfg = {
.mosi_io_num = mosi_gpio,
.miso_io_num = miso_gpio,
.sclk_io_num = slck_gpio,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = spi_max_transfer_size
};
error = spi_bus_initialize(spi_host, &buscfg, spi_dma_channel);
if (error != ESP_OK) {
log_e("Method: (spi_bus_initialize) failed with error: (%s)", esp_err_to_name(error));
return false;
}
spi_device_interface_config_t devcfg = {
.command_bits = 16,
.address_bits = 8,
.mode = 0,
.clock_speed_hz = spi_clock_mhz * 1000 * 1000,
.spics_io_num = cs_gpio,
.queue_size = 20
};
error = spi_bus_add_device(spi_host, &devcfg, &spi_device_handle);
if (error != ESP_OK) {
log_e("Method: (spi_bus_add_device) failed with error: (%s)", esp_err_to_name(error));
return false;
}

// W5500 ethernet driver is based on spi driver.
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_device_handle);
w5500_config.int_gpio_num = int_gpio;

esp_eth_mac_t* eth_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
if (eth_mac == nullptr) {
log_e("Method: (esp_eth_mac_new_w5500) failed with error: (%s)", esp_err_to_name(ESP_FAIL));
return false;
}

eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = phy_addr;
phy_config.reset_gpio_num = phy_rst_gpio;

esp_eth_phy_t *eth_phy = esp_eth_phy_new_w5500(&phy_config);
if (eth_phy == nullptr) {
log_e("Method: (esp_eth_phy_new) failed with error: (%s)", esp_err_to_name(ESP_FAIL));
return false;
}

esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(eth_mac, eth_phy);
eth_handle = nullptr;

error = esp_eth_driver_install(&eth_config, &eth_handle);
if (error != ESP_OK || eth_handle == nullptr) {
log_e("Method: (esp_eth_driver_install) failed with error: (%s)", esp_err_to_name(error));
return false;
}

// Set the mac address.
esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_address);

// Attach Ethernet driver to TCP/IP stack.
error = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle));
if (error != ESP_OK) {
log_e("Method: (esp_netif_attach) failed with error: (%s)", esp_err_to_name(error));
return false;
}

// Start Ethernet driver state machine.
error = esp_eth_start(eth_handle);
if (error != ESP_OK) {
log_e("Method: (esp_eth_start) failed with error: (%s)", esp_err_to_name(error));
return false;
}

return true;
}

spi_device_handle_t& ETHClass::getSpiDeviceHandle(void) {
return spi_device_handle;
}

spi_host_device_t& ETHClass::getSpiHost(void) {
return spi_host_device;
}
#endif

bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2)
{
esp_err_t err = ESP_OK;
Expand Down
16 changes: 15 additions & 1 deletion libraries/Ethernet/src/ETH.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include "esp_system.h"
#include "esp_eth.h"

#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
#include <driver/spi_master.h>
#endif

#ifndef ETH_PHY_ADDR
#define ETH_PHY_ADDR 0
#endif
Expand Down Expand Up @@ -53,7 +57,7 @@
typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT } eth_clock_mode_t;
#endif

typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_DM9051, ETH_PHY_KSZ8041, ETH_PHY_KSZ8081, ETH_PHY_MAX } eth_phy_type_t;
typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_DM9051, ETH_PHY_KSZ8041, ETH_PHY_KSZ8081, ETH_PHY_W5500, ETH_PHY_MAX } eth_phy_type_t;
#define ETH_PHY_IP101 ETH_PHY_TLK110

class ETHClass {
Expand All @@ -62,6 +66,10 @@ class ETHClass {
bool staticIP;
#if ESP_IDF_VERSION_MAJOR > 3
esp_eth_handle_t eth_handle;
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
spi_device_handle_t spi_device_handle = nullptr;
spi_host_device_t spi_host_device = spi_host_device_t::SPI3_HOST;
#endif

protected:
bool started;
Expand All @@ -76,6 +84,12 @@ class ETHClass {

bool begin(uint8_t phy_addr=ETH_PHY_ADDR, int power=ETH_PHY_POWER, int mdc=ETH_PHY_MDC, int mdio=ETH_PHY_MDIO, eth_phy_type_t type=ETH_PHY_TYPE, eth_clock_mode_t clk_mode=ETH_CLK_MODE, bool use_mac_from_efuse=false);

#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
bool beginW5500(uint8_t* mac_address, int8_t mosi_gpio, int8_t miso_gpio, int8_t slck_gpio, int8_t cs_gpio, int8_t int_gpio, int8_t phy_rst_gpio, uint32_t mac_stack_size = 2048, int spi_max_transfer_size = 0, spi_common_dma_t spi_dma_channel = spi_common_dma_t::SPI_DMA_CH_AUTO, uint8_t phy_addr = 1, uint8_t spi_clock_mhz = 10, spi_host_device_t spi_host = SPI3_HOST, eth_phy_type_t type = ETH_PHY_W5500);
spi_device_handle_t& getSpiDeviceHandle(void);
spi_host_device_t& getSpiHost(void);
#endif

bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);

const char * getHostname();
Expand Down
6 changes: 5 additions & 1 deletion libraries/SPI/src/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ void SPIClass::setClockDivider(uint32_t clockDiv)
SPI_PARAM_UNLOCK();
}

void SPIClass::setSpiDeviceHandle(spi_device_handle_t& spi_device_handle, spi_host_device_t& spi_host_device)
{
spiSetDeviceHandle(spi_device_handle, spi_host_device);
}

uint32_t SPIClass::getClockDivider()
{
return spiGetClockDiv(_spi);
Expand Down Expand Up @@ -348,4 +353,3 @@ SPIClass SPI(VSPI);
#else
SPIClass SPI(FSPI);
#endif

10 changes: 9 additions & 1 deletion libraries/SPI/src/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "esp32-hal-spi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include <driver/spi_master.h>

#define SPI_HAS_TRANSACTION

Expand Down Expand Up @@ -68,7 +69,14 @@ class SPIClass
void setDataMode(uint8_t dataMode);
void setFrequency(uint32_t freq);
void setClockDivider(uint32_t clockDiv);


/**
* @brief Sets the spi device handle so that the underlying SPI driver, also respects when the esp-idf SPI driver attempts to use the SPI.
* @param spi_device_handle Spi device handle gettable via. ETH.getSpiDeviceHandle()
* @param spi_device_handle Spi host device gettable via. ETH.getSpiHost()
*/
void setSpiDeviceHandle(spi_device_handle_t& spi_device_handle, spi_host_device_t& spi_host_device);

uint32_t getClockDivider();

void beginTransaction(SPISettings settings);
Expand Down
Loading