Skip to content

Commit e982c1d

Browse files
damzdpgeorge
authored andcommitted
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.
1 parent 30bac47 commit e982c1d

File tree

6 files changed

+155
-20
lines changed

6 files changed

+155
-20
lines changed

ports/esp32/machine_hw_spi.c

+8
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,14 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
533533
return MP_OBJ_FROM_PTR(self);
534534
}
535535

536+
spi_host_device_t machine_hw_spi_get_host(mp_obj_t in) {
537+
if (mp_obj_get_type(in) != &machine_spi_type) {
538+
mp_raise_ValueError(MP_ERROR_TEXT("expecting a SPI object"));
539+
}
540+
machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)in;
541+
return self->host;
542+
}
543+
536544
STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
537545
.init = machine_hw_spi_init,
538546
.deinit = machine_hw_spi_deinit,

ports/esp32/modnetwork.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
229229
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
230230
#endif
231231

232-
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
232+
#if MICROPY_PY_NETWORK_LAN
233233
{ MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) },
234234
#endif
235235
{ 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[] = {
260260
{ MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
261261
#endif
262262

263-
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
263+
#if MICROPY_PY_NETWORK_LAN
264264
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8710), MP_ROM_INT(PHY_LAN8710) },
265265
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
266266
{ 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[] = {
271271
{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8041), MP_ROM_INT(PHY_KSZ8041) },
272272
#endif
273273

274+
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
275+
{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8851SNL), MP_ROM_INT(PHY_KSZ8851SNL) },
276+
#endif
277+
#if CONFIG_ETH_SPI_ETHERNET_DM9051
278+
{ MP_ROM_QSTR(MP_QSTR_PHY_DM9051), MP_ROM_INT(PHY_DM9051) },
279+
#endif
280+
#if CONFIG_ETH_SPI_ETHERNET_W5500
281+
{ MP_ROM_QSTR(MP_QSTR_PHY_W5500), MP_ROM_INT(PHY_W5500) },
282+
#endif
283+
274284
{ MP_ROM_QSTR(MP_QSTR_ETH_INITIALIZED), MP_ROM_INT(ETH_INITIALIZED)},
275285
{ MP_ROM_QSTR(MP_QSTR_ETH_STARTED), MP_ROM_INT(ETH_STARTED)},
276286
{ MP_ROM_QSTR(MP_QSTR_ETH_STOPPED), MP_ROM_INT(ETH_STOPPED)},

ports/esp32/modnetwork.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929
#include "esp_event.h"
3030

31-
enum { PHY_LAN8710, PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 };
31+
enum { PHY_LAN8710, PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041, PHY_KSZ8851SNL = 100, PHY_DM9051, PHY_W5500 };
32+
#define IS_SPI_PHY(NUM) (NUM >= 100)
3233
enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP };
3334

3435
// Cases similar to ESP8266 user_interface.h

ports/esp32/mpconfigport.h

+18
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,21 @@ typedef long mp_off_t;
217217
#endif
218218

219219
void boardctrl_startup(void);
220+
221+
#ifndef MICROPY_PY_NETWORK_LAN
222+
#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)))
223+
#define MICROPY_PY_NETWORK_LAN (1)
224+
#else
225+
#define MICROPY_PY_NETWORK_LAN (0)
226+
#endif
227+
#endif
228+
229+
#if MICROPY_PY_NETWORK_LAN && CONFIG_ETH_USE_SPI_ETHERNET
230+
#ifndef MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ
231+
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
232+
#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (12)
233+
#else
234+
#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (36)
235+
#endif
236+
#endif
237+
#endif

ports/esp32/mphalport.h

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include "freertos/FreeRTOS.h"
3636
#include "freertos/task.h"
3737

38+
#include "driver/spi_master.h"
39+
3840
#define MICROPY_PLATFORM_VERSION "IDF" IDF_VER
3941

4042
// 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) {
111113
gpio_set_level(pin, v);
112114
}
113115

116+
spi_host_device_t machine_hw_spi_get_host(mp_obj_t in);
117+
114118
#endif // INCLUDED_MPHALPORT_H

ports/esp32/network_lan.c

+111-17
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@
3333
#include "esp_idf_version.h"
3434

3535
// LAN only for ESP32 (not ESP32S2) and only for ESP-IDF v4.1 and higher
36-
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
36+
#if MICROPY_PY_NETWORK_LAN
3737

3838
#include "esp_eth.h"
3939
#include "esp_eth_mac.h"
4040
#include "esp_event.h"
4141
#include "esp_log.h"
4242
#include "esp_netif.h"
43+
#if CONFIG_ETH_USE_SPI_ETHERNET
44+
#include "driver/spi_master.h"
45+
#endif
4346

4447
#include "modnetwork.h"
4548

@@ -48,9 +51,11 @@ typedef struct _lan_if_obj_t {
4851
int if_id; // MUST BE FIRST to match wlan_if_obj_t
4952
bool initialized;
5053
bool active;
51-
uint8_t mdc_pin;
52-
uint8_t mdio_pin;
54+
int8_t mdc_pin;
55+
int8_t mdio_pin;
5356
int8_t phy_power_pin;
57+
int8_t phy_cs_pin;
58+
int8_t phy_int_pin;
5459
uint8_t phy_addr;
5560
uint8_t phy_type;
5661
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
98103
}
99104

100105
enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type,
101-
ARG_ref_clk_mode, ARG_ref_clk };
106+
ARG_ref_clk_mode, ARG_ref_clk, ARG_spi, ARG_cs, ARG_int };
102107
static const mp_arg_t allowed_args[] = {
103108
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
104-
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
105-
{ MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
109+
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
110+
{ MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
106111
{ MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
107112
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
108113
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
109-
// Dynamic ref_clk configuration available at v4.4
110114
#if ESP_IDF_VERSION_MINOR >= 4
115+
// Dynamic ref_clk configuration available at v4.4
111116
{ MP_QSTR_ref_clk_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
112117
{ MP_QSTR_ref_clk, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
113118
#endif
119+
{ MP_QSTR_spi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
120+
{ MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
121+
{ MP_QSTR_int, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
114122
};
115123

116124
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
122130
}
123131
}
124132

125-
self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj);
126-
self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj);
127-
self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj);
133+
#define GET_PIN(XXX) args[XXX].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[XXX].u_obj);
134+
135+
self->mdc_pin = GET_PIN(ARG_mdc);
136+
self->mdio_pin = GET_PIN(ARG_mdio);
137+
self->phy_power_pin = GET_PIN(ARG_power);
138+
self->phy_cs_pin = GET_PIN(ARG_cs);
139+
self->phy_int_pin = GET_PIN(ARG_int);
128140

129141
if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
130142
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
138150
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
139151
args[ARG_phy_type].u_int != PHY_KSZ8041 &&
140152
#endif
153+
#if CONFIG_ETH_USE_SPI_ETHERNET
154+
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
155+
args[ARG_phy_type].u_int != PHY_KSZ8851SNL &&
156+
#endif
157+
#if CONFIG_ETH_SPI_ETHERNET_DM9051
158+
args[ARG_phy_type].u_int != PHY_DM9051 &&
159+
#endif
160+
#if CONFIG_ETH_SPI_ETHERNET_W5500
161+
args[ARG_phy_type].u_int != PHY_W5500 &&
162+
#endif
163+
#endif
141164
args[ARG_phy_type].u_int != PHY_DP83848) {
142165
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy type"));
143166
}
144167

145168
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
146-
mac_config.smi_mdc_gpio_num = self->mdc_pin;
147-
mac_config.smi_mdio_gpio_num = self->mdio_pin;
169+
esp_eth_mac_t *mac = NULL;
170+
148171
// Dynamic ref_clk configuration available at v4.4
149172
#if ESP_IDF_VERSION_MINOR >= 4
150173
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
156179
mac_config.clock_config.rmii.clock_gpio = machine_pin_get_id(args[ARG_ref_clk].u_obj);
157180
}
158181
#endif
159-
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
160182

161183
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
162184
phy_config.phy_addr = self->phy_addr;
163185
phy_config.reset_gpio_num = self->phy_power_pin;
164186
self->phy = NULL;
165187

188+
#if CONFIG_ETH_USE_SPI_ETHERNET
189+
spi_device_handle_t spi_handle = NULL;
190+
if (IS_SPI_PHY(args[ARG_phy_type].u_int)) {
191+
spi_device_interface_config_t devcfg = {
192+
.mode = 0,
193+
.clock_speed_hz = MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ * 1000 * 1000,
194+
.queue_size = 20,
195+
.spics_io_num = self->phy_cs_pin,
196+
};
197+
switch (args[ARG_phy_type].u_int) {
198+
#if CONFIG_ETH_SPI_ETHERNET_DM9051
199+
case PHY_DM9051: {
200+
devcfg.command_bits = 1;
201+
devcfg.address_bits = 7;
202+
break;
203+
}
204+
#endif
205+
#if CONFIG_ETH_SPI_ETHERNET_W5500
206+
case PHY_W5500: {
207+
devcfg.command_bits = 16;
208+
devcfg.address_bits = 8;
209+
break;
210+
}
211+
#endif
212+
}
213+
spi_host_device_t host = machine_hw_spi_get_host(args[ARG_spi].u_obj);
214+
if (spi_bus_add_device(host, &devcfg, &spi_handle) != ESP_OK) {
215+
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("spi_bus_add_device failed"));
216+
}
217+
}
218+
#endif
219+
166220
switch (args[ARG_phy_type].u_int) {
221+
#if CONFIG_IDF_TARGET_ESP32
167222
case PHY_LAN8710:
168223
case PHY_LAN8720:
169224
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
177232
case PHY_DP83848:
178233
self->phy = esp_eth_phy_new_dp83848(&phy_config);
179234
break;
235+
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
180236
case PHY_KSZ8041:
181-
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
182237
self->phy = esp_eth_phy_new_ksz8041(&phy_config);
183238
break;
184-
#endif
185-
default:
186-
mp_raise_ValueError(MP_ERROR_TEXT("unknown phy"));
239+
#endif
240+
#endif
241+
#if CONFIG_ETH_USE_SPI_ETHERNET
242+
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
243+
case PHY_KSZ8851SNL: {
244+
eth_ksz8851snl_config_t chip_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_handle);
245+
chip_config.int_gpio_num = self->phy_int_pin;
246+
mac = esp_eth_mac_new_ksz8851snl(&chip_config, &mac_config);
247+
self->phy = esp_eth_phy_new_ksz8851snl(&phy_config);
248+
break;
249+
}
250+
#endif
251+
#if CONFIG_ETH_SPI_ETHERNET_DM9051
252+
case PHY_DM9051: {
253+
eth_dm9051_config_t chip_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
254+
chip_config.int_gpio_num = self->phy_int_pin;
255+
mac = esp_eth_mac_new_dm9051(&chip_config, &mac_config);
256+
self->phy = esp_eth_phy_new_dm9051(&phy_config);
257+
break;
258+
}
259+
#endif
260+
#if CONFIG_ETH_SPI_ETHERNET_W5500
261+
case PHY_W5500: {
262+
eth_w5500_config_t chip_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
263+
chip_config.int_gpio_num = self->phy_int_pin;
264+
mac = esp_eth_mac_new_w5500(&chip_config, &mac_config);
265+
self->phy = esp_eth_phy_new_w5500(&phy_config);
266+
break;
267+
}
268+
#endif
269+
#endif
187270
}
188271

272+
#if CONFIG_IDF_TARGET_ESP32
273+
if (!IS_SPI_PHY(args[ARG_phy_type].u_int)) {
274+
if (self->mdc_pin == -1 || self->mdio_pin == -1) {
275+
mp_raise_ValueError(MP_ERROR_TEXT("mdc and mdio must be specified"));
276+
}
277+
mac_config.smi_mdc_gpio_num = self->mdc_pin;
278+
mac_config.smi_mdio_gpio_num = self->mdio_pin;
279+
mac = esp_eth_mac_new_esp32(&mac_config);
280+
}
281+
#endif
282+
189283
if (esp_netif_init() != ESP_OK) {
190284
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_init failed"));
191285
}

0 commit comments

Comments
 (0)