DHCPv4 client + Ethernet (W5500) Fails to work in SDK 2.4

Hello everyone,

I am working on an application based on dhcpv4_client from the zephyr SDK samples https://developer.nordicsemi.com/nRF_Connect_SDK/doc/2.4.99-dev2/zephyr/samples/net/dhcpv4_client/README.html#dhcpv4-client-sample.

I am using wiz550io v3 ethernet controller which uses W5500 driver.
I made the same implementation on nrf 2.3 SDK and it works, however the same implementation dose not work with 2.4 SDK. I can build the app and flash it. however no data is received, I am not sure it seems that the callback function dose not receive any interpret signal.

The serial monitor print initializing the dhcp_client and then remains stuck.

Note: I am using nrf 2.4 SDK with the nrf52833dk 

# Networking General
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_ARP=y
CONFIG_NET_UDP=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_LOG=y
CONFIG_LOG=y
CONFIG_NET_STATISTICS=y
CONFIG_NET_L2_ETHERNET=y

# Networking Protocols and Extensions
CONFIG_NET_IPV6=n
CONFIG_NET_TCP=y
CONFIG_DNS_RESOLVER=y
CONFIG_DNS_SERVER_IP_ADDRESSES=y
CONFIG_DNS_SERVER1="8.8.8.8"
CONFIG_NET_SOCKETS=y

# Testing and Debugging
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NET_SHELL=y

# System and Library Configurations
CONFIG_NEWLIB_LIBC=y
CONFIG_MAIN_STACK_SIZE=1200
CONFIG_GPIO=y
CONFIG_ENTROPY_GENERATOR=y
CONFIG_INIT_STACKS=y



Networking Hardware Suppor
CONFIG_NETWORKING = y
CONFIG_ETH_DRIVER=y
CONFIG_ETH_W5500=y
CONFIG_ETH_W5500_TIMEOUT=1000
 

Prj.conf file

 

&spi1 {
        compatible = "nordic,nrf-spi";
        status = "okay";
        cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
        w5500: w5500@0 {
                compatible = "wiznet,w5500";
                label = "w5500";
                reg = <0>;
                spi-max-frequency = <1000000>;
                int-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
                reset-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
        };
};

nrf52833dk overlay file 

  • Hello again Raoul,

    I have another update.
    1st test: I have compared the two of versions on DHCPv4 sample 2.3SDK and 2.4 SDK.
    The internet interface is the same, the DHCP initiation is also the same. The difference is within the net management initiation callback, some naming convention and managements of threads within the library. 

    2nd test: was only establishing connection and ping test from my pc to the ethernet controller wiz550i0 .I have commented everything except the network interface function and disabled the DHCP configuration, as well as setup a static IP address.

    /* Networking DHCPv4 client */
    
    /*
     * Copyright (c) 2017 ARM Ltd.
     * Copyright (c) 2016 Intel Corporation.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(net_dhcpv4_client_sample, LOG_LEVEL_DBG);
    
    #include <zephyr/kernel.h>
    #include <zephyr/linker/sections.h>
    #include <errno.h>
    #include <stdio.h>
    
    #include <zephyr/net/net_if.h>
    #include <zephyr/net/net_core.h>
    #include <zephyr/net/net_context.h>
    #include <zephyr/net/net_mgmt.h>
    
    static struct net_mgmt_event_callback mgmt_cb;
    
    // static void handler(struct net_mgmt_event_callback *cb,
    // 		    uint32_t mgmt_event,
    // 		    struct net_if *iface)
    // {
    // 	int i = 0;
    
    // 	if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) {
    // 		return;
    // 	}
    
    // 	for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
    // 		char buf[NET_IPV4_ADDR_LEN];
    
    // 		if (iface->config.ip.ipv4->unicast[i].addr_type !=
    // 							NET_ADDR_DHCP) {
    // 			continue;
    // 		}
    
    // 		LOG_INF("Your address: %s",
    // 			net_addr_ntop(AF_INET,
    // 			    &iface->config.ip.ipv4->unicast[i].address.in_addr,
    // 						  buf, sizeof(buf)));
    // 		LOG_INF("Lease time: %u seconds",
    // 			 iface->config.dhcpv4.lease_time);
    // 		LOG_INF("Subnet: %s",
    // 			net_addr_ntop(AF_INET,
    // 				       &iface->config.ip.ipv4->netmask,
    // 				       buf, sizeof(buf)));
    // 		LOG_INF("Router: %s",
    // 			net_addr_ntop(AF_INET,
    // 						 &iface->config.ip.ipv4->gw,
    // 						 buf, sizeof(buf)));
    // 	}
    // }
    
    int main(void)
    {
    	struct net_if *iface;
    
    	LOG_INF("Run dhcpv4 client");
    
    	// net_mgmt_init_event_callback(&mgmt_cb, handler,
    	// 			     NET_EVENT_IPV4_ADDR_ADD);
    	// net_mgmt_add_event_callback(&mgmt_cb);
    
    	iface = net_if_get_default();
    
    	// net_dhcpv4_start(iface);
    	return 0;
    }
    
     

    Sample code SDK 2.4

    # General config
    CONFIG_NEWLIB_LIBC=y
    CONFIG_MAIN_STACK_SIZE=1200
    
    # nothing here
    CONFIG_SPI=y
    CONFIG_NET_L2_ETHERNET=y
    CONFIG_ETH_W5500=y
    CONFIG_ETH_W5500_TIMEOUT=1000
    CONFIG_NET_DHCPV4=n
    
    # CONFIG_CONSOLE=y
    CONFIG_GPIO=y
    CONFIG_NETWORKING=y
    # CONFIG_NET_IPV6=y
    CONFIG_NET_IPV4=y
    CONFIG_NET_ARP=y
    CONFIG_NET_TCP=y
    CONFIG_NET_UDP=y
    
    
    #CONFIG_APP_EVENT_MANAGER=y
    
    CONFIG_ENTROPY_GENERATOR=y
    CONFIG_TEST_RANDOM_GENERATOR=y
    CONFIG_INIT_STACKS=y
    
    CONFIG_INIT_STACKS=y
    
    CONFIG_NET_STATISTICS=y
    
    
    # CONFIG_NET_PKT_RX_COUNT=32
    # CONFIG_NET_PKT_TX_COUNT=32
    # CONFIG_NET_BUF_RX_COUNT=32
    # CONFIG_NET_BUF_TX_COUNT=32
    
    # CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
    # CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
    #CONFIG_NET_MAX_CONTEXTS=10
    
    CONFIG_NET_MGMT=y
    CONFIG_NET_MGMT_EVENT=y
    
    CONFIG_NET_LOG=y
    CONFIG_LOG=y
    
    # # Network address config
    # CONFIG_NET_CONFIG_SETTINGS=y
    # # CONFIG_NET_CONFIG_NEED_IPV6=y
    # CONFIG_NET_CONFIG_NEED_IPV4=y
    
    # CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8:200::1"
    # CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8:200::2"
    # CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.1.160"
    # CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.168.1.161"
    # CONFIG_NET_CONFIG_MY_IPV4_GW="192.168.1.1"
    #  CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=n
    # #CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:c8"
    # CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT="echo"
    # CONFIG_ETH_NATIVE_POSIX_DRV_NAME="w5500"
    
    
    CONFIG_DNS_RESOLVER=y
    CONFIG_DNS_SERVER_IP_ADDRESSES=y
    CONFIG_DNS_SERVER1="8.8.8.8"
    
    # CONFIG_ETH_NATIVE_POSIX=y
    # CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=y
    
    # CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
    # CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
    # CONFIG_NET_MAX_CONTEXTS=10
    
    CONFIG_NET_SHELL=y
    # CONFIG_NET_DEFAULT_IF_ETHERNET=y
    CONFIG_NET_SOCKETS=y
    # CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    # CONFIG_UART_CONSOLE=n
    # CONFIG_RTT_CONSOLE=y
    
    
    
    CONFIG_NET_CONFIG_SETTINGS=y
    CONFIG_NET_CONFIG_NEED_IPV6=n
    CONFIG_NET_CONFIG_NEED_IPV4=y
    CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.1.3"
    CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
    CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0"
    CONFIG_NET_CONFIG_MY_IPV4_GW="192.168.1.1"

    prj configuration file

    Pinging 192.168.1.3 with 32 bytes of data:
    Reply from 192.168.1.3: bytes=32 time=61ms TTL=64
    Reply from 192.168.1.3: bytes=32 time=3ms TTL=64
    Reply from 192.168.1.3: bytes=32 time=3ms TTL=64
    Reply from 192.168.1.3: bytes=32 time=3ms TTL=64

    terminal output pinging the device from my pc

    uart:~$ net ping 192.168.1.2
    PING 192.168.1.2
    Ping timeout
    

    terminal output pinging my pc from the device

    I did the same thing also for SDK 2.3 sample and I got the same output for both.
    Note: I made all required configuration for the ethernet from my pc side

    3rd Test: I Connected the ethernet to a router and pinged my pc and 8.8.8.8 (Google) server IP address . In both SDK 2.3 and 2.4 pinging my pc which is connected to same network didn't work for some reason. However pinging google did work in SDK 2.3 but not 2.4. 

    Please note that My goal is to establish connection using ethernet socket (wiz550io) which uses w5500 driver in SDK 2.4. 

    Regards,
    Abdullah Al Abri

  • Dear Team,

    I am pleased to report that I have identified and resolved the issue we encountered with the Ethernet controller wiz550io, specifically when using the w5500 driver to establish an internet connection and run protocols such as DHCP.

    The root of the problem lies within the w5500 driver, located at \ncs\v2.4.0\zephyr\drivers\ethernet\eth_w5500.c. Upon thorough examination and debugging of the relevant files, I discovered a critical code block in the driver responsible for generating the MAC address for the chip:

    static void w5500_set_macaddr(const struct device *dev) {
        struct w5500_runtime *ctx = dev->data;
    
    #if DT_INST_PROP(0, zephyr_random_mac_address)
        /* override vendor bytes */
        memset(ctx->mac_addr, '\0', sizeof(ctx->mac_addr));
        ctx->mac_addr[0] = WIZNET_OUI_B0;
        ctx->mac_addr[1] = WIZNET_OUI_B1;
        ctx->mac_addr[2] = WIZNET_OUI_B2;
        if (ctx->generate_mac) {
            ctx->generate_mac(ctx->mac_addr);
        }
    #endif
        w5500_spi_write(dev, W5500_SHAR, ctx->mac_addr, sizeof(ctx->mac_addr));
    }

    Through testing, it became apparent that this code block does not execute as intended. The conditional statement within it fails, resulting in the MAC address being set to all zeros. A properly generated MAC address should consist of 3 vendor-specific bytes and 3 randomly generated bytes. Due to the malfunction of this function, the MAC address defaults to all zeros, leading routers to block the device and DHCP servers to deny it an IP address. This issue persists across nRF SDK versions 2.4, 2.4.2, and 2.5.

    To rectify this, a simple solution is proposed. By modifying the code to either remove the if statement or repeat the same code snippet after the if statement block, we can ensure proper MAC address generation:

    static void w5500_set_macaddr(const struct device *dev) {
        struct w5500_runtime *ctx = dev->data;
    
    #if DT_INST_PROP(0, zephyr_random_mac_address)
        /* override vendor bytes */
        memset(ctx->mac_addr, '\0', sizeof(ctx->mac_addr));
        ctx->mac_addr[0] = WIZNET_OUI_B0;
        ctx->mac_addr[1] = WIZNET_OUI_B1;
        ctx->mac_addr[2] = WIZNET_OUI_B2;
        if (ctx->generate_mac) {
            ctx->generate_mac(ctx->mac_addr);
        }
    #endif
        memset(ctx->mac_addr, '\0', sizeof(ctx->mac_addr));
        ctx->mac_addr[0] = WIZNET_OUI_B0;
        ctx->mac_addr[1] = WIZNET_OUI_B1;
        ctx->mac_addr[2] = WIZNET_OUI_B2;
        if (ctx->generate_mac) {
            ctx->generate_mac(ctx->mac_addr);
        }
        w5500_spi_write(dev, W5500_SHAR, ctx->mac_addr, sizeof(ctx->mac_addr));
    }

    This revised code effectively addresses the issue. I will attach the full file containing the fixed driver for your review and implementation.

    Best Regards,
    Abdullah Al Abri

    /* W5500 Stand-alone Ethernet Controller with SPI
     *
     * Copyright (c) 2020 Linumiz
     * Author: Parthiban Nallathambi <[email protected]>
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #define DT_DRV_COMPAT	wiznet_w5500
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(eth_w5500, CONFIG_ETHERNET_LOG_LEVEL);
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <string.h>
    #include <errno.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    #include <zephyr/net/net_pkt.h>
    #include <zephyr/net/net_if.h>
    #include <zephyr/net/ethernet.h>
    #include <ethernet/eth_stats.h>
    
    #include "eth.h"
    #include "eth_w5500_priv.h"
    
    #define WIZNET_OUI_B0	0x00
    #define WIZNET_OUI_B1	0x08
    #define WIZNET_OUI_B2	0xdc
    
    #define W5500_SPI_BLOCK_SELECT(addr)	(((addr) >> 16) & 0x1f)
    #define W5500_SPI_READ_CONTROL(addr)	(W5500_SPI_BLOCK_SELECT(addr) << 3)
    #define W5500_SPI_WRITE_CONTROL(addr)   \
    	((W5500_SPI_BLOCK_SELECT(addr) << 3) | BIT(2))
    
    static int w5500_spi_read(const struct device *dev, uint32_t addr,
    			  uint8_t *data, uint32_t len)
    {
    	const struct w5500_config *cfg = dev->config;
    	int ret;
    	/* 3 bytes as 0x010203 during command phase */
    	uint8_t tmp[len + 3];
    
    	uint8_t cmd[3] = {
    		addr >> 8,
    		addr,
    		W5500_SPI_READ_CONTROL(addr)
    	};
    	const struct spi_buf tx_buf = {
    		.buf = cmd,
    		.len = ARRAY_SIZE(cmd),
    	};
    	const struct spi_buf_set tx = {
    		.buffers = &tx_buf,
    		.count = 1,
    	};
    	const struct spi_buf rx_buf = {
    		.buf = tmp,
    		.len = ARRAY_SIZE(tmp),
    	};
    	const struct spi_buf_set rx = {
    		.buffers = &rx_buf,
    		.count = 1,
    	};
    
    	ret = spi_transceive_dt(&cfg->spi, &tx, &rx);
    
    	if (!ret) {
    		/* skip the default dummy 0x010203 */
    		memcpy(data, &tmp[3], len);
    	}
    
    	return ret;
    }
    
    static int w5500_spi_write(const struct device *dev, uint32_t addr,
    			   uint8_t *data, uint32_t len)
    {
    	const struct w5500_config *cfg = dev->config;
    	int ret;
    	uint8_t cmd[3] = {
    		addr >> 8,
    		addr,
    		W5500_SPI_WRITE_CONTROL(addr),
    	};
    	const struct spi_buf tx_buf[2] = {
    		{
    			.buf = cmd,
    			.len = ARRAY_SIZE(cmd),
    		},
    		{
    			.buf = data,
    			.len = len,
    		},
    	};
    	const struct spi_buf_set tx = {
    		.buffers = tx_buf,
    		.count = ARRAY_SIZE(tx_buf),
    	};
    
    	ret = spi_write_dt(&cfg->spi, &tx);
    
    	return ret;
    }
    
    static int w5500_readbuf(const struct device *dev, uint16_t offset, uint8_t *buf,
    			 int len)
    {
    	uint32_t addr;
    	int remain = 0;
    	int ret;
    	const uint32_t mem_start = W5500_Sn_RX_MEM_START;
    	const uint16_t mem_size = W5500_RX_MEM_SIZE;
    
    	offset %= mem_size;
    	addr = mem_start + offset;
    
    	if (offset + len > mem_size) {
    		remain = (offset + len) % mem_size;
    		len = mem_size - offset;
    	}
    
    	ret = w5500_spi_read(dev, addr, buf, len);
    	if (ret || !remain) {
    		return ret;
    	}
    
    	return w5500_spi_read(dev, mem_start, buf + len, remain);
    }
    
    static int w5500_writebuf(const struct device *dev, uint16_t offset, uint8_t *buf,
    			  int len)
    {
    	uint32_t addr;
    	int ret = 0;
    	int remain = 0;
    	const uint32_t mem_start = W5500_Sn_TX_MEM_START;
    	const uint32_t mem_size = W5500_TX_MEM_SIZE;
    
    	offset %= mem_size;
    	addr = mem_start + offset;
    
    	if (offset + len > mem_size) {
    		remain = (offset + len) % mem_size;
    		len = mem_size - offset;
    	}
    
    	ret = w5500_spi_write(dev, addr, buf, len);
    	if (ret || !remain) {
    		return ret;
    	}
    
    	return w5500_spi_write(dev, mem_start, buf + len, remain);
    }
    
    static int w5500_command(const struct device *dev, uint8_t cmd)
    {
    	uint8_t reg;
    	uint64_t end = sys_clock_timeout_end_calc(K_MSEC(100));
    
    	w5500_spi_write(dev, W5500_S0_CR, &cmd, 1);
    	while (1) {
    		w5500_spi_read(dev, W5500_S0_CR, &reg, 1);
    		if (!reg) {
    			break;
    			}
    		int64_t remaining = end - sys_clock_tick_get();
    		if (remaining <= 0) {
    			return -EIO;
    			}
    		k_busy_wait(W5500_PHY_ACCESS_DELAY);
    		}
    	return 0;
    }
    
    static int w5500_tx(const struct device *dev, struct net_pkt *pkt)
    {
    	struct w5500_runtime *ctx = dev->data;
    	uint16_t len = net_pkt_get_len(pkt);
    	uint16_t offset;
    	uint8_t off[2];
    	int ret;
    
    	w5500_spi_read(dev, W5500_S0_TX_WR, off, 2);
    	offset = sys_get_be16(off);
    
    	if (net_pkt_read(pkt, ctx->buf, len)) {
    		return -EIO;
    	}
    
    	ret = w5500_writebuf(dev, offset, ctx->buf, len);
    	if (ret < 0) {
    		return ret;
    	}
    
    	sys_put_be16(offset + len, off);
    	w5500_spi_write(dev, W5500_S0_TX_WR, off, 2);
    
    	w5500_command(dev, S0_CR_SEND);
    	if (k_sem_take(&ctx->tx_sem, K_MSEC(10))) {
    		return -EIO;
    	}
    
    	return 0;
    }
    
    static void w5500_rx(const struct device *dev)
    {
    	uint8_t header[2];
    	uint8_t tmp[2];
    	uint16_t off;
    	uint16_t rx_len;
    	uint16_t rx_buf_len;
    	uint16_t read_len;
    	uint16_t reader;
    	struct net_buf *pkt_buf = NULL;
    	struct net_pkt *pkt;
    	struct w5500_runtime *ctx = dev->data;
    	const struct w5500_config *config = dev->config;
    
    	w5500_spi_read(dev, W5500_S0_RX_RSR, tmp, 2);
    	rx_buf_len = sys_get_be16(tmp);
    
    	if (rx_buf_len == 0) {
    		return;
    	}
    
    	w5500_spi_read(dev, W5500_S0_RX_RD, tmp, 2);
    	off = sys_get_be16(tmp);
    
    	w5500_readbuf(dev, off, header, 2);
    	rx_len = sys_get_be16(header) - 2;
    
    	pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, rx_len,
    			AF_UNSPEC, 0, K_MSEC(config->timeout));
    	if (!pkt) {
    		eth_stats_update_errors_rx(ctx->iface);
    		return;
    	}
    
    	pkt_buf = pkt->buffer;
    
    	read_len = rx_len;
    	reader = off + 2;
    
    	do {
    		size_t frag_len;
    		uint8_t *data_ptr;
    		size_t frame_len;
    
    		data_ptr = pkt_buf->data;
    
    		frag_len = net_buf_tailroom(pkt_buf);
    
    		if (read_len > frag_len) {
    			frame_len = frag_len;
    		} else {
    			frame_len = read_len;
    		}
    
    		w5500_readbuf(dev, reader, data_ptr, frame_len);
    		net_buf_add(pkt_buf, frame_len);
    		reader += frame_len;
    
    		read_len -= frame_len;
    		pkt_buf = pkt_buf->frags;
    	} while (read_len > 0);
    
    	if (net_recv_data(ctx->iface, pkt) < 0) {
    		net_pkt_unref(pkt);
    	}
    
    	sys_put_be16(off + 2 + rx_len, tmp);
    	w5500_spi_write(dev, W5500_S0_RX_RD, tmp, 2);
    	w5500_command(dev, S0_CR_RECV);
    }
    
    static void w5500_thread(const struct device *dev)
    {
    	uint8_t ir;
    	struct w5500_runtime *ctx = dev->data;
    	const struct w5500_config *config = dev->config;
    
    	while (true) {
    		k_sem_take(&ctx->int_sem, K_FOREVER);
    
    		while (gpio_pin_get_dt(&(config->interrupt))) {
    			/* Read interrupt */
    			w5500_spi_read(dev, W5500_S0_IR, &ir, 1);
    
    			if (ir) {
    				/* Clear interrupt */
    				w5500_spi_write(dev, W5500_S0_IR, &ir, 1);
    
    				LOG_DBG("IR received");
    
    				if (ir & S0_IR_SENDOK) {
    					k_sem_give(&ctx->tx_sem);
    					LOG_DBG("TX Done");
    				}
    
    				if (ir & S0_IR_RECV) {
    					w5500_rx(dev);
    					LOG_DBG("RX Done");
    				}
    			}
    		}
    	}
    }
    
    static void w5500_iface_init(struct net_if *iface)
    {
    	const struct device *dev = net_if_get_device(iface);
    	struct w5500_runtime *ctx = dev->data;
    
    	net_if_set_link_addr(iface, ctx->mac_addr,
    			     sizeof(ctx->mac_addr),
    			     NET_LINK_ETHERNET);
    
    	if (!ctx->iface) {
    		ctx->iface = iface;
    	}
    
    	ethernet_init(iface);
    }
    
    static enum ethernet_hw_caps w5500_get_capabilities(const struct device *dev)
    {
    	ARG_UNUSED(dev);
    
    	return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T
    #if defined(CONFIG_NET_PROMISCUOUS_MODE)
    		| ETHERNET_PROMISC_MODE
    #endif
    	;
    }
    
    static int w5500_set_config(const struct device *dev,
    			    enum ethernet_config_type type,
    			    const struct ethernet_config *config)
    {
    	struct w5500_runtime *ctx = dev->data;
    
    	switch (type) {
    	case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
    		memcpy(ctx->mac_addr,
    			config->mac_address.addr,
    			sizeof(ctx->mac_addr));
    		w5500_spi_write(dev, W5500_SHAR, ctx->mac_addr, sizeof(ctx->mac_addr));
    		LOG_INF("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x",
    			dev->name,
    			ctx->mac_addr[0], ctx->mac_addr[1],
    			ctx->mac_addr[2], ctx->mac_addr[3],
    			ctx->mac_addr[4], ctx->mac_addr[5]);
    
    		/* Register Ethernet MAC Address with the upper layer */
    		net_if_set_link_addr(ctx->iface, ctx->mac_addr,
    			sizeof(ctx->mac_addr),
    			NET_LINK_ETHERNET);
    
    		return 0;
    	case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
    		if (IS_ENABLED(CONFIG_NET_PROMISCUOUS_MODE)) {
    			uint8_t mode;
    			uint8_t mr = W5500_S0_MR_MF;
    
    			w5500_spi_read(dev, W5500_S0_MR, &mode, 1);
    
    			if (config->promisc_mode) {
    				if (!(mode & BIT(mr))) {
    					return -EALREADY;
    				}
    
    				/* disable MAC filtering */
    				WRITE_BIT(mode, mr, 0);
    			} else {
    				if (mode & BIT(mr)) {
    					return -EALREADY;
    				}
    
    				/* enable MAC filtering */
    				WRITE_BIT(mode, mr, 1);
    			}
    
    			return w5500_spi_write(dev, W5500_S0_MR, &mode, 1);
    		}
    
    		return -ENOTSUP;
    	default:
    		return -ENOTSUP;
    	}
    }
    
    static int w5500_hw_start(const struct device *dev)
    {
    	uint8_t mode = S0_MR_MACRAW | BIT(W5500_S0_MR_MF);
    	uint8_t mask = IR_S0;
    
    	/* configure Socket 0 with MACRAW mode and MAC filtering enabled */
    	w5500_spi_write(dev, W5500_S0_MR, &mode, 1);
    	w5500_command(dev, S0_CR_OPEN);
    
    	/* enable interrupt */
    	w5500_spi_write(dev, W5500_SIMR, &mask, 1);
    
    	return 0;
    }
    
    static int w5500_hw_stop(const struct device *dev)
    {
    	uint8_t mask = 0;
    
    	/* disable interrupt */
    	w5500_spi_write(dev, W5500_SIMR, &mask, 1);
    	w5500_command(dev, S0_CR_CLOSE);
    
    	return 0;
    }
    
    static struct ethernet_api w5500_api_funcs = {
    	.iface_api.init = w5500_iface_init,
    	.get_capabilities = w5500_get_capabilities,
    	.set_config = w5500_set_config,
    	.start = w5500_hw_start,
    	.stop = w5500_hw_stop,
    	.send = w5500_tx,
    };
    
    static int w5500_hw_reset(const struct device *dev)
    {
    	int ret;
    	uint8_t mask = 0;
    	uint8_t tmp = MR_RST;
    
    	ret = w5500_spi_write(dev, W5500_MR, &tmp, 1);
    	if (ret < 0) {
    		return ret;
    	}
    
    	k_msleep(5);
    	tmp = MR_PB;
    	w5500_spi_write(dev, W5500_MR, &tmp, 1);
    
    	/* disable interrupt */
    	return w5500_spi_write(dev, W5500_SIMR, &mask, 1);
    }
    
    static void w5500_gpio_callback(const struct device *dev,
    				struct gpio_callback *cb,
    				uint32_t pins)
    {
    	struct w5500_runtime *ctx =
    		CONTAINER_OF(cb, struct w5500_runtime, gpio_cb);
    
    	k_sem_give(&ctx->int_sem);
    }
    
    static void w5500_set_macaddr(const struct device *dev)
    {
    	struct w5500_runtime *ctx = dev->data;
    
    #if DT_INST_PROP(0, zephyr_random_mac_address)
    	/* override vendor bytes */
    	memset(ctx->mac_addr, '\0', sizeof(ctx->mac_addr));
    	ctx->mac_addr[0] = WIZNET_OUI_B0;
    	ctx->mac_addr[1] = WIZNET_OUI_B1;
    	ctx->mac_addr[2] = WIZNET_OUI_B2;
    	if (ctx->generate_mac) {
    		ctx->generate_mac(ctx->mac_addr);
    	}
    #endif
    	memset(ctx->mac_addr, '\0', sizeof(ctx->mac_addr));
    	ctx->mac_addr[0] = WIZNET_OUI_B0;
    	ctx->mac_addr[1] = WIZNET_OUI_B1;
    	ctx->mac_addr[2] = WIZNET_OUI_B2;
    	if (ctx->generate_mac) {
    		ctx->generate_mac(ctx->mac_addr);
    	}
    	w5500_spi_write(dev, W5500_SHAR, ctx->mac_addr, sizeof(ctx->mac_addr));
    }
    
    static void w5500_memory_configure(const struct device *dev)
    {
    	int i;
    	uint8_t mem = 0x10;
    
    	/* Configure RX & TX memory to 16K */
    	w5500_spi_write(dev, W5500_Sn_RXMEM_SIZE(0), &mem, 1);
    	w5500_spi_write(dev, W5500_Sn_TXMEM_SIZE(0), &mem, 1);
    
    	mem = 0;
    	for (i = 1; i < 8; i++) {
    		w5500_spi_write(dev, W5500_Sn_RXMEM_SIZE(i), &mem, 1);
    		w5500_spi_write(dev, W5500_Sn_TXMEM_SIZE(i), &mem, 1);
    	}
    }
    
    static void w5500_random_mac(uint8_t *mac_addr)
    {
    	gen_random_mac(mac_addr, WIZNET_OUI_B0, WIZNET_OUI_B1, WIZNET_OUI_B2);
    }
    
    static int w5500_init(const struct device *dev)
    {
    	int err;
    	uint8_t rtr[2];
    	const struct w5500_config *config = dev->config;
    	struct w5500_runtime *ctx = dev->data;
    
    	if (!spi_is_ready_dt(&config->spi)) {
    		LOG_ERR("SPI master port %s not ready", config->spi.bus->name);
    		return -EINVAL;
    	}
    
    	if (!device_is_ready(config->interrupt.port)) {
    		LOG_ERR("GPIO port %s not ready", config->interrupt.port->name);
    		return -EINVAL;
    	}
    
    	if (gpio_pin_configure_dt(&config->interrupt, GPIO_INPUT)) {
    		LOG_ERR("Unable to configure GPIO pin %u", config->interrupt.pin);
    		return -EINVAL;
    	}
    
    	gpio_init_callback(&(ctx->gpio_cb), w5500_gpio_callback,
    			   BIT(config->interrupt.pin));
    
    	if (gpio_add_callback(config->interrupt.port, &(ctx->gpio_cb))) {
    		return -EINVAL;
    	}
    
    	gpio_pin_interrupt_configure_dt(&config->interrupt,
    					GPIO_INT_EDGE_FALLING);
    
    	if (config->reset.port) {
    		if (!device_is_ready(config->reset.port)) {
    			LOG_ERR("GPIO port %s not ready", config->reset.port->name);
    			return -EINVAL;
    		}
    		if (gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT)) {
    			LOG_ERR("Unable to configure GPIO pin %u", config->reset.pin);
    			return -EINVAL;
    		}
    		gpio_pin_set_dt(&config->reset, 0);
    		k_usleep(500);
    	}
    
    	err = w5500_hw_reset(dev);
    	if (err) {
    		LOG_ERR("Reset failed");
    		return err;
    	}
    
    	w5500_set_macaddr(dev);
    	w5500_memory_configure(dev);
    
    	/* check retry time value */
    	w5500_spi_read(dev, W5500_RTR, rtr, 2);
    	if (sys_get_be16(rtr) != RTR_DEFAULT) {
    		LOG_ERR("Unable to read RTR register");
    		return -ENODEV;
    	}
    
    	k_thread_create(&ctx->thread, ctx->thread_stack,
    			CONFIG_ETH_W5500_RX_THREAD_STACK_SIZE,
    			(k_thread_entry_t)w5500_thread,
    			(void *)dev, NULL, NULL,
    			K_PRIO_COOP(CONFIG_ETH_W5500_RX_THREAD_PRIO),
    			0, K_NO_WAIT);
    
    	LOG_INF("W5500 Initialized");
    
    	return 0;
    }
    
    static struct w5500_runtime w5500_0_runtime = {
    #if NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0))
    	.mac_addr = DT_INST_PROP(0, local_mac_address),
    #endif
    	.generate_mac = w5500_random_mac,
    	.tx_sem = Z_SEM_INITIALIZER(w5500_0_runtime.tx_sem,
    					1,  UINT_MAX),
    	.int_sem  = Z_SEM_INITIALIZER(w5500_0_runtime.int_sem,
    				      0, UINT_MAX),
    };
    
    static const struct w5500_config w5500_0_config = {
    	.spi = SPI_DT_SPEC_INST_GET(0, SPI_WORD_SET(8), 0),
    	.interrupt = GPIO_DT_SPEC_INST_GET(0, int_gpios),
    	.reset = GPIO_DT_SPEC_INST_GET_OR(0, reset_gpios, { 0 }),
    	.timeout = CONFIG_ETH_W5500_TIMEOUT,
    };
    
    ETH_NET_DEVICE_DT_INST_DEFINE(0,
    		    w5500_init, NULL,
    		    &w5500_0_runtime, &w5500_0_config,
    		    CONFIG_ETH_INIT_PRIORITY, &w5500_api_funcs, NET_ETH_MTU);
    

  • Ran into this same issue on v2.6, commenting out the #if resolved it there as well

    To not have comment out the #if you can set `zephyr,random-mac-address` in the dts file like

    &spi3 {
        w5500: ethernet@0 {
            compatible = "wiznet,w5500";
            zephyr,random-mac-address;
            // other necessary properties
        };
    };

Related