diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 35ecc397b3..36f8d3f069 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -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, diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index cc066f361f..3ebba2ade9 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -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)}, diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h index 5d1c3aaf7c..49bbd9c496 100644 --- a/ports/esp32/modnetwork.h +++ b/ports/esp32/modnetwork.h @@ -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 diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index d8822980b7..38468cf9cf 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.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 diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index c838bd2284..7f14b6e188 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -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 diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index 471e31d627..f63c7ef8eb 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -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")); }