esp32/network_lan: Add support for SPI-based ethernet chips.
Add support for various SPI-based ethernet chips (W5500, KSZ8851SNL, DM9051) to the ESP32 port. This leverages the existing support in ESP-IDF for these chips -- which configures these chips in "MAC raw" mode -- and the existing support for network.LAN in the ESP32 port. In particular, this doesn't leverage the wiznet5k support that is used on the rp2 and stm32 ports (because that's for native use of lwIP). Tested on the POE Featherwing (with the SJIRQ solder jumper bridged) and a ESP32-S3 feather. A note about the interrupt pin: The W5500 implementation within ESP-IDF relies on hardware interrupt, and requires the interrupt pin from the W5500 to be wired to a GPIO. This is not the case by default on the Adafruit Ethernet FeatherWing, which makes it not directly compatible with this implementation.
This commit is contained in:
parent
30bac47b12
commit
e982c1d8de
@ -533,6 +533,14 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
spi_host_device_t machine_hw_spi_get_host(mp_obj_t in) {
|
||||
if (mp_obj_get_type(in) != &machine_spi_type) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("expecting a SPI object"));
|
||||
}
|
||||
machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)in;
|
||||
return self->host;
|
||||
}
|
||||
|
||||
STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
|
||||
.init = machine_hw_spi_init,
|
||||
.deinit = machine_hw_spi_deinit,
|
||||
|
@ -229,7 +229,7 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
|
||||
#if MICROPY_PY_NETWORK_LAN
|
||||
{ MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&ppp_make_new_obj) },
|
||||
@ -260,7 +260,7 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
|
||||
#if MICROPY_PY_NETWORK_LAN
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8710), MP_ROM_INT(PHY_LAN8710) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_IP101), MP_ROM_INT(PHY_IP101) },
|
||||
@ -271,6 +271,16 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8041), MP_ROM_INT(PHY_KSZ8041) },
|
||||
#endif
|
||||
|
||||
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8851SNL), MP_ROM_INT(PHY_KSZ8851SNL) },
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_DM9051), MP_ROM_INT(PHY_DM9051) },
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_W5500), MP_ROM_INT(PHY_W5500) },
|
||||
#endif
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_INITIALIZED), MP_ROM_INT(ETH_INITIALIZED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_STARTED), MP_ROM_INT(ETH_STARTED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_STOPPED), MP_ROM_INT(ETH_STOPPED)},
|
||||
|
@ -28,7 +28,8 @@
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
enum { PHY_LAN8710, PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 };
|
||||
enum { PHY_LAN8710, PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041, PHY_KSZ8851SNL = 100, PHY_DM9051, PHY_W5500 };
|
||||
#define IS_SPI_PHY(NUM) (NUM >= 100)
|
||||
enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP };
|
||||
|
||||
// Cases similar to ESP8266 user_interface.h
|
||||
|
@ -217,3 +217,21 @@ typedef long mp_off_t;
|
||||
#endif
|
||||
|
||||
void boardctrl_startup(void);
|
||||
|
||||
#ifndef MICROPY_PY_NETWORK_LAN
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32 || (CONFIG_ETH_USE_SPI_ETHERNET && (CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL || CONFIG_ETH_SPI_ETHERNET_DM9051 || CONFIG_ETH_SPI_ETHERNET_W5500)))
|
||||
#define MICROPY_PY_NETWORK_LAN (1)
|
||||
#else
|
||||
#define MICROPY_PY_NETWORK_LAN (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_LAN && CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#ifndef MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
|
||||
#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (12)
|
||||
#else
|
||||
#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (36)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
#define MICROPY_PLATFORM_VERSION "IDF" IDF_VER
|
||||
|
||||
// The core that the MicroPython task(s) are pinned to.
|
||||
@ -111,4 +113,6 @@ static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) {
|
||||
gpio_set_level(pin, v);
|
||||
}
|
||||
|
||||
spi_host_device_t machine_hw_spi_get_host(mp_obj_t in);
|
||||
|
||||
#endif // INCLUDED_MPHALPORT_H
|
||||
|
@ -33,13 +33,16 @@
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
// LAN only for ESP32 (not ESP32S2) and only for ESP-IDF v4.1 and higher
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
|
||||
#if MICROPY_PY_NETWORK_LAN
|
||||
|
||||
#include "esp_eth.h"
|
||||
#include "esp_eth_mac.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif
|
||||
|
||||
#include "modnetwork.h"
|
||||
|
||||
@ -48,9 +51,11 @@ typedef struct _lan_if_obj_t {
|
||||
int if_id; // MUST BE FIRST to match wlan_if_obj_t
|
||||
bool initialized;
|
||||
bool active;
|
||||
uint8_t mdc_pin;
|
||||
uint8_t mdio_pin;
|
||||
int8_t mdc_pin;
|
||||
int8_t mdio_pin;
|
||||
int8_t phy_power_pin;
|
||||
int8_t phy_cs_pin;
|
||||
int8_t phy_int_pin;
|
||||
uint8_t phy_addr;
|
||||
uint8_t phy_type;
|
||||
esp_eth_phy_t *phy;
|
||||
@ -98,19 +103,22 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
}
|
||||
|
||||
enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type,
|
||||
ARG_ref_clk_mode, ARG_ref_clk };
|
||||
ARG_ref_clk_mode, ARG_ref_clk, ARG_spi, ARG_cs, ARG_int };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
// Dynamic ref_clk configuration available at v4.4
|
||||
#if ESP_IDF_VERSION_MINOR >= 4
|
||||
// Dynamic ref_clk configuration available at v4.4
|
||||
{ MP_QSTR_ref_clk_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_ref_clk, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
#endif
|
||||
{ MP_QSTR_spi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_int, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
@ -122,9 +130,13 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
}
|
||||
}
|
||||
|
||||
self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj);
|
||||
self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj);
|
||||
self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj);
|
||||
#define GET_PIN(XXX) args[XXX].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[XXX].u_obj);
|
||||
|
||||
self->mdc_pin = GET_PIN(ARG_mdc);
|
||||
self->mdio_pin = GET_PIN(ARG_mdio);
|
||||
self->phy_power_pin = GET_PIN(ARG_power);
|
||||
self->phy_cs_pin = GET_PIN(ARG_cs);
|
||||
self->phy_int_pin = GET_PIN(ARG_int);
|
||||
|
||||
if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy address"));
|
||||
@ -138,13 +150,24 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
|
||||
args[ARG_phy_type].u_int != PHY_KSZ8041 &&
|
||||
#endif
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
|
||||
args[ARG_phy_type].u_int != PHY_KSZ8851SNL &&
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
args[ARG_phy_type].u_int != PHY_DM9051 &&
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
args[ARG_phy_type].u_int != PHY_W5500 &&
|
||||
#endif
|
||||
#endif
|
||||
args[ARG_phy_type].u_int != PHY_DP83848) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy type"));
|
||||
}
|
||||
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
mac_config.smi_mdc_gpio_num = self->mdc_pin;
|
||||
mac_config.smi_mdio_gpio_num = self->mdio_pin;
|
||||
esp_eth_mac_t *mac = NULL;
|
||||
|
||||
// Dynamic ref_clk configuration available at v4.4
|
||||
#if ESP_IDF_VERSION_MINOR >= 4
|
||||
if (args[ARG_ref_clk_mode].u_int != -1) {
|
||||
@ -156,14 +179,46 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
mac_config.clock_config.rmii.clock_gpio = machine_pin_get_id(args[ARG_ref_clk].u_obj);
|
||||
}
|
||||
#endif
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
|
||||
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
phy_config.phy_addr = self->phy_addr;
|
||||
phy_config.reset_gpio_num = self->phy_power_pin;
|
||||
self->phy = NULL;
|
||||
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
if (IS_SPI_PHY(args[ARG_phy_type].u_int)) {
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.mode = 0,
|
||||
.clock_speed_hz = MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ * 1000 * 1000,
|
||||
.queue_size = 20,
|
||||
.spics_io_num = self->phy_cs_pin,
|
||||
};
|
||||
switch (args[ARG_phy_type].u_int) {
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
case PHY_DM9051: {
|
||||
devcfg.command_bits = 1;
|
||||
devcfg.address_bits = 7;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
case PHY_W5500: {
|
||||
devcfg.command_bits = 16;
|
||||
devcfg.address_bits = 8;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
spi_host_device_t host = machine_hw_spi_get_host(args[ARG_spi].u_obj);
|
||||
if (spi_bus_add_device(host, &devcfg, &spi_handle) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("spi_bus_add_device failed"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (args[ARG_phy_type].u_int) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
case PHY_LAN8710:
|
||||
case PHY_LAN8720:
|
||||
self->phy = esp_eth_phy_new_lan8720(&phy_config);
|
||||
@ -177,15 +232,54 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
case PHY_DP83848:
|
||||
self->phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
break;
|
||||
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
|
||||
case PHY_KSZ8041:
|
||||
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
|
||||
self->phy = esp_eth_phy_new_ksz8041(&phy_config);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unknown phy"));
|
||||
#endif
|
||||
#endif
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
|
||||
case PHY_KSZ8851SNL: {
|
||||
eth_ksz8851snl_config_t chip_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_handle);
|
||||
chip_config.int_gpio_num = self->phy_int_pin;
|
||||
mac = esp_eth_mac_new_ksz8851snl(&chip_config, &mac_config);
|
||||
self->phy = esp_eth_phy_new_ksz8851snl(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
case PHY_DM9051: {
|
||||
eth_dm9051_config_t chip_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
chip_config.int_gpio_num = self->phy_int_pin;
|
||||
mac = esp_eth_mac_new_dm9051(&chip_config, &mac_config);
|
||||
self->phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ETH_SPI_ETHERNET_W5500
|
||||
case PHY_W5500: {
|
||||
eth_w5500_config_t chip_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
chip_config.int_gpio_num = self->phy_int_pin;
|
||||
mac = esp_eth_mac_new_w5500(&chip_config, &mac_config);
|
||||
self->phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if (!IS_SPI_PHY(args[ARG_phy_type].u_int)) {
|
||||
if (self->mdc_pin == -1 || self->mdio_pin == -1) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("mdc and mdio must be specified"));
|
||||
}
|
||||
mac_config.smi_mdc_gpio_num = self->mdc_pin;
|
||||
mac_config.smi_mdio_gpio_num = self->mdio_pin;
|
||||
mac = esp_eth_mac_new_esp32(&mac_config);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (esp_netif_init() != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_init failed"));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user