mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
Merge pull request #20301 from elektrozaun/driver_w5500
driver/w5500: driver for the W5500 ethernet chip
This commit is contained in:
commit
e2449184ab
@ -333,6 +333,7 @@ typedef enum {
|
||||
NETDEV_ESP_WIFI,
|
||||
NETDEV_CDC_ECM,
|
||||
NETDEV_TINYUSB,
|
||||
NETDEV_W5500,
|
||||
/* add more if needed */
|
||||
} netdev_type_t;
|
||||
/** @} */
|
||||
@ -360,11 +361,11 @@ typedef enum {
|
||||
* be used by upper layers to store reference information.
|
||||
*/
|
||||
struct netdev {
|
||||
const struct netdev_driver *driver; /**< ptr to that driver's interface. */
|
||||
netdev_event_cb_t event_callback; /**< callback for device events */
|
||||
void *context; /**< ptr to network stack context */
|
||||
const struct netdev_driver *driver; /**< ptr to that driver's interface. */
|
||||
netdev_event_cb_t event_callback; /**< callback for device events */
|
||||
void *context; /**< ptr to network stack context */
|
||||
#ifdef MODULE_NETDEV_LAYER
|
||||
netdev_t *lower; /**< ptr to the lower netdev layer */
|
||||
netdev_t *lower; /**< ptr to the lower netdev layer */
|
||||
#endif
|
||||
#ifdef MODULE_L2FILTER
|
||||
l2filter_t filter[CONFIG_L2FILTER_LISTSIZE]; /**< link layer address filters */
|
||||
@ -401,12 +402,12 @@ void netdev_register_signal(struct netdev *dev, netdev_type_t type, uint8_t inde
|
||||
static inline void netdev_register(struct netdev *dev, netdev_type_t type, uint8_t index)
|
||||
{
|
||||
#ifdef MODULE_NETDEV_REGISTER
|
||||
dev->type = type;
|
||||
dev->type = type;
|
||||
dev->index = index;
|
||||
#else
|
||||
(void) dev;
|
||||
(void) type;
|
||||
(void) index;
|
||||
(void)dev;
|
||||
(void)type;
|
||||
(void)index;
|
||||
#endif
|
||||
|
||||
if (IS_ACTIVE(CONFIG_NETDEV_REGISTER_SIGNAL)) {
|
||||
|
90
drivers/include/w5500.h
Normal file
90
drivers/include/w5500.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_w5500 W5500 ethernet driver
|
||||
* @ingroup drivers_netdev
|
||||
* @brief Driver for W5500 ethernet devices
|
||||
*
|
||||
* This device driver only exposes the MACRAW mode of W5500 devices, so it does
|
||||
* not offer any support for the on-chip IPv4, UDP, and TCP capabilities of
|
||||
* these chips. In connection with RIOT we are only interested in the RAW
|
||||
* Ethernet packets, which we can use through netdev with any software network
|
||||
* stack provided by RIOT (e.g. GNRC). This enables W5500 devices to communicate
|
||||
* via IPv6, enables unlimited connections, and more...
|
||||
*
|
||||
* @note This driver can be used in polling or interrupt mode.
|
||||
* On some shields the interrupt line is not enabled by default,
|
||||
* you have to close the corresponding solder bridge to make the
|
||||
* interrupt mode work...
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Interface definition for the W5500 device driver
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef W5500_H
|
||||
#define W5500_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "periph/spi.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "net/netdev.h"
|
||||
#include "kernel_defines.h"
|
||||
#include "ztimer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief W5500 device descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
spi_t spi; /**< SPI bus used */
|
||||
spi_clk_t clk; /**< clock speed used on the selected SPI bus */
|
||||
gpio_t cs; /**< pin connected to the chip select line */
|
||||
gpio_t irq; /**< pin connected to the INT line */
|
||||
uint32_t polling_interval_ms; /**< interval for polling, 0 if interrupt mode */
|
||||
} w5500_params_t;
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for W5500 devices
|
||||
*/
|
||||
typedef struct w5500 {
|
||||
netdev_t netdev; /**< extends the netdev structure */
|
||||
w5500_params_t p; /**< device configuration parameters */
|
||||
uint16_t frame_size; /**< size of the frame which has been send */
|
||||
bool link_up; /**< used to prevent sending the same LINK event twice */
|
||||
bool frame_sent; /**< indicates that the frame has been transmitted */
|
||||
ztimer_t timerInstance; /**< stores the polling interval timer in polling mode */
|
||||
} w5500_t;
|
||||
|
||||
/**
|
||||
* @brief So the initial device setup
|
||||
*
|
||||
* This function pre-initializes the netdev structure, saves the configuration
|
||||
* parameters and finally initializes the SPI bus and the used GPIO pins.
|
||||
*
|
||||
* @param [out] dev the handle of the device to initialize
|
||||
* @param [in] params parameters for device initialization
|
||||
* @param [in] index Index of @p params in a global parameter struct array.
|
||||
* If initialized manually, pass a unique identifier instead.
|
||||
*/
|
||||
void w5500_setup(w5500_t *dev, const w5500_params_t *params, uint8_t index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* W5500_H */
|
||||
/** @} */
|
52
drivers/w5500/Kconfig
Normal file
52
drivers/w5500/Kconfig
Normal file
@ -0,0 +1,52 @@
|
||||
# Copyright (C) 2023 Stefan Schmidt
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
menuconfig MODULE_W5500
|
||||
bool "W5500 Ethernet Adapter"
|
||||
depends on HAS_PERIPH_GPIO
|
||||
depends on HAS_PERIPH_GPIO_IRQ
|
||||
depends on HAS_PERIPH_SPI
|
||||
depends on TEST_KCONFIG
|
||||
select MODULE_LUID
|
||||
select MODULE_NETDEV_ETH
|
||||
select MODULE_PERIPH_GPIO
|
||||
select MODULE_PERIPH_GPIO_IRQ
|
||||
select MODULE_PERIPH_SPI
|
||||
|
||||
config HAVE_W5500
|
||||
bool
|
||||
select MODULE_W5500 if MODULE_NETDEV_DEFAULT
|
||||
help
|
||||
Indicates that a w5500 ethernet adapter is present.
|
||||
|
||||
if MODULE_W5500
|
||||
|
||||
config W5500_USE_POLLING
|
||||
bool "Use driver in polling mode"
|
||||
default y
|
||||
|
||||
if W5500_USE_POLLING
|
||||
|
||||
config W5500_POLLING_INTERVAL
|
||||
int "Polling interval in ms"
|
||||
default 100
|
||||
|
||||
#endif # W5500_USE_POLLING
|
||||
|
||||
config W5500_MAC_FILTER
|
||||
bool "Enable hardware MAC filter"
|
||||
default n
|
||||
|
||||
config W5500_BROADCAST_FILTER
|
||||
bool "Enable hardware broadcast filter"
|
||||
default n
|
||||
|
||||
config W5500_MULTICAST_FILTER
|
||||
bool "Enable hardware multicast filter"
|
||||
default n
|
||||
|
||||
endif # MODULE_W5500
|
1
drivers/w5500/Makefile
Normal file
1
drivers/w5500/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
6
drivers/w5500/Makefile.dep
Normal file
6
drivers/w5500/Makefile.dep
Normal file
@ -0,0 +1,6 @@
|
||||
FEATURES_REQUIRED += periph_gpio_irq
|
||||
FEATURES_REQUIRED += periph_spi
|
||||
USEMODULE += luid
|
||||
USEMODULE += iolist
|
||||
USEMODULE += netdev_eth
|
||||
USEMODULE += ztimer_msec
|
2
drivers/w5500/Makefile.include
Normal file
2
drivers/w5500/Makefile.include
Normal file
@ -0,0 +1,2 @@
|
||||
USEMODULE_INCLUDES_w5500 := $(LAST_MAKEFILEDIR)/include
|
||||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_w5500)
|
73
drivers/w5500/include/w5500_params.h
Normal file
73
drivers/w5500/include/w5500_params.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_w5500
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Default parameters for W5500 Ethernet devices
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef W5500_PARAMS_H
|
||||
#define W5500_PARAMS_H
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Default configuration parameters for the W5500 driver
|
||||
* @{
|
||||
*/
|
||||
#ifndef W5500_PARAM_SPI
|
||||
#define W5500_PARAM_SPI (SPI_DEV(0)) /**< Default SPI device */
|
||||
#endif
|
||||
#ifndef W5500_PARAM_SPI_CLK
|
||||
#define W5500_PARAM_SPI_CLK (SPI_CLK_10MHZ) /**< Default SPI speed */
|
||||
#endif
|
||||
#ifndef W5500_PARAM_CS
|
||||
#define W5500_PARAM_CS (GPIO_PIN(0, 27)) /**< Default SPI chip select pin */
|
||||
#endif
|
||||
#ifndef W5500_PARAM_INT
|
||||
#define W5500_PARAM_INT GPIO_UNDEF /**< set to invalid */
|
||||
#endif
|
||||
#ifndef CONFIG_W5500_POLLING_INTERVAL
|
||||
#define CONFIG_W5500_POLLING_INTERVAL 100u /**< default polling interval 100 ms */
|
||||
#endif
|
||||
|
||||
#ifndef W5500_PARAMS
|
||||
/**
|
||||
* @brief W5500 initialization parameters
|
||||
*/
|
||||
|
||||
#define W5500_PARAMS { .spi = W5500_PARAM_SPI, \
|
||||
.clk = W5500_PARAM_SPI_CLK, \
|
||||
.cs = W5500_PARAM_CS, \
|
||||
.irq = W5500_PARAM_INT, \
|
||||
.polling_interval_ms = CONFIG_W5500_POLLING_INTERVAL }
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief W5500 configuration
|
||||
*/
|
||||
static const w5500_params_t w5500_params[] = {
|
||||
W5500_PARAMS
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* W5500_PARAMS_H */
|
||||
/** @} */
|
177
drivers/w5500/include/w5500_regs.h
Normal file
177
drivers/w5500/include/w5500_regs.h
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_w5500
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Register definitions for W5500 devices
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef W5500_REGS_H
|
||||
#define W5500_REGS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The W5500 is accessed by sending a 16 Bit address first, then a 8 bit control byte
|
||||
which determines to which register (common or one of the 8 Sockets) this address shall be
|
||||
applied and finally the data.
|
||||
|
||||
In order to simplify the functions to read and write to the W5500 via SPI the defined register
|
||||
addresses contain the control byte in the upper 5 bits and the actual register address in the
|
||||
lower 13 bits:
|
||||
0b00000 -> common register (0x0xxx)
|
||||
0b00001 -> Socket 0 register (0x08xx)
|
||||
|
||||
The RX and TX buffers are accessed via separate functions in order to be able to access the full
|
||||
16 kB buffers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name Common registers (with BSB 00000 in the upper 5 bits).
|
||||
* @{
|
||||
*/
|
||||
#define REG_MODE (0x0000) /**< Mode. */
|
||||
#define REG_GAR0 (0x0001) /**< Gateway address 0. */
|
||||
#define REG_GAR1 (0x0002) /**< Gateway address 1. */
|
||||
#define REG_GAR2 (0x0003) /**< Gateway address 2. */
|
||||
#define REG_GAR3 (0x0004) /**< Gateway address 3. */
|
||||
#define REG_SUBR0 (0x0005) /**< Subnet mask 0. */
|
||||
#define REG_SUBR1 (0x0006) /**< Subnet mask 1. */
|
||||
#define REG_SUBR2 (0x0007) /**< Subnet mask 2. */
|
||||
#define REG_SUBR3 (0x0008) /**< Subnet mask 3. */
|
||||
#define REG_SHAR0 (0x0009) /**< Source hardware address 0. */
|
||||
#define REG_SHAR1 (0x000a) /**< Source hardware address 1. */
|
||||
#define REG_SHAR2 (0x000b) /**< Source hardware address 2. */
|
||||
#define REG_SHAR3 (0x000c) /**< Source hardware address 3. */
|
||||
#define REG_SHAR4 (0x000d) /**< Source hardware address 4. */
|
||||
#define REG_SHAR5 (0x000e) /**< Source hardware address 5. */
|
||||
#define REG_SIPR0 (0x000f) /**< Source IP address 0. */
|
||||
#define REG_SIPR1 (0x0010) /**< Source IP address 1. */
|
||||
#define REG_SIPR2 (0x0011) /**< Source IP address 2. */
|
||||
#define REG_SIPR3 (0x0012) /**< Source IP address 3. */
|
||||
#define REG_INTLEVEL0 (0x0013) /**< Interrupt low level timer 0. */
|
||||
#define REG_INTLEVEL1 (0x0014) /**< Interrupt low level timer 1. */
|
||||
#define REG_IR (0x0015) /**< Interrupt flags. */
|
||||
#define REG_IMR (0x0016) /**< Interrupt masks. */
|
||||
#define REG_SIR (0x0017) /**< Socket interrupt. */
|
||||
#define REG_SIMR (0x0018) /**< Socket interrupt mask. */
|
||||
#define REG_RTR0 (0x0019) /**< Retry time 0. */
|
||||
#define REG_RTR1 (0x001a) /**< Retry time 1. */
|
||||
#define REG_RCR (0x001b) /**< Retry count. */
|
||||
#define REG_PTIMER (0x001c) /**< Ppp lcp request timer. */
|
||||
#define REG_PMAGIC (0x001d) /**< Ppp lcp magic number. */
|
||||
#define REG_PHAR0 (0x001e) /**< Ppp destination mac address 0. */
|
||||
#define REG_PHAR1 (0x001f) /**< Ppp destination mac address 1. */
|
||||
#define REG_PHAR2 (0x0020) /**< Ppp destination mac address 2. */
|
||||
#define REG_PHAR3 (0x0021) /**< Ppp destination mac address 3. */
|
||||
#define REG_PHAR4 (0x0022) /**< Ppp destination mac address 4. */
|
||||
#define REG_PHAR5 (0x0023) /**< Ppp destination mac address 5. */
|
||||
#define REG_PSID0 (0x0024) /**< Ppp session identification 0. */
|
||||
#define REG_PSID1 (0x0025) /**< Ppp session identification 1. */
|
||||
#define REG_PMRU0 (0x0026) /**< Ppp maximum segment size 0. */
|
||||
#define REG_PMRU1 (0x0027) /**< Ppp maximum segment size 1. */
|
||||
#define REG_UIPR0 (0x0028) /**< Unreachable IP address 0. */
|
||||
#define REG_UIPR1 (0x0029) /**< Unreachable IP address 1. */
|
||||
#define REG_UIPR2 (0x002a) /**< Unreachable IP address 2. */
|
||||
#define REG_UIPR3 (0x002b) /**< Unreachable IP address 3. */
|
||||
#define REG_UPORT0 (0x002c) /**< Unreachable port 0. */
|
||||
#define REG_UPORT1 (0x002d) /**< Unreachable port 1. */
|
||||
#define REG_PHYCFGR (0x002e) /**< Phy configuration. */
|
||||
#define REG_VERSIONR (0x0039) /**< Chip version. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Socket 0 register block (with BSB 00001 in the upper 5 bits).
|
||||
* @{
|
||||
*/
|
||||
#define REG_S0_MR (0x0800) /**< Socket 0 mode */
|
||||
#define REG_S0_CR (0x0801) /**< Socket 0 command */
|
||||
#define REG_S0_IR (0x0802) /**< Socket 0 interrupt */
|
||||
#define REG_S0_SR (0x0803) /**< Socket 0 status */
|
||||
#define REG_S0_PORT0 (0x0804) /**< Socket 0 Source port 0 */
|
||||
#define REG_S0_PORT1 (0x0805) /**< Socket 0 Source port 1 */
|
||||
#define REG_S0_DHAR0 (0x0806) /**< Socket 0 destination hardware address 0 */
|
||||
#define REG_S0_DHAR1 (0x0807) /**< Socket 0 destination hardware address 1 */
|
||||
#define REG_S0_DHAR2 (0x0808) /**< Socket 0 destination hardware address 2 */
|
||||
#define REG_S0_DHAR3 (0x0809) /**< Socket 0 destination hardware address 3 */
|
||||
#define REG_S0_DHAR4 (0x080a) /**< Socket 0 destination hardware address 4 */
|
||||
#define REG_S0_DHAR5 (0x080b) /**< Socket 0 destination hardware address 5 */
|
||||
#define REG_S0_DIPR0 (0x080c) /**< Socket 0 destination IP address 0 */
|
||||
#define REG_S0_DIPR1 (0x080d) /**< Socket 0 destination IP address 1 */
|
||||
#define REG_S0_DIPR2 (0x080e) /**< Socket 0 destination IP address 2 */
|
||||
#define REG_S0_DIPR3 (0x080f) /**< Socket 0 destination IP address 3 */
|
||||
#define REG_S0_DPORT0 (0x0810) /**< Socket 0 destination port 0 */
|
||||
#define REG_S0_DPORT1 (0x0811) /**< Socket 0 destination port 1 */
|
||||
#define REG_S0_MSSR0 (0x0812) /**< Socket 0 maximum segment size 0 */
|
||||
#define REG_S0_MSSR1 (0x0813) /**< Socket 0 maximum segment size 1 */
|
||||
#define REG_S0_TOS (0x0815) /**< Socket 0 IP TOS */
|
||||
#define REG_S0_TTL (0x0816) /**< Socket 0 IP TTL */
|
||||
#define REG_S0_RXBUF_SIZE (0x081e) /**< Socket 0 receive buffer size */
|
||||
#define REG_S0_TXBUF_SIZE (0x081f) /**< Socket 0 transmit buffer size */
|
||||
#define REG_S0_TX_FSR0 (0x0820) /**< Socket 0 tx free size 0 */
|
||||
#define REG_S0_TX_FSR1 (0x0821) /**< Socket 0 tx free size 1 */
|
||||
#define REG_S0_TX_RD0 (0x0822) /**< Socket 0 tx read pointer 0 */
|
||||
#define REG_S0_TX_RD1 (0x0823) /**< Socket 0 tx read pointer 1 */
|
||||
#define REG_S0_TX_WR0 (0x0824) /**< Socket 0 tx write pointer 0 */
|
||||
#define REG_S0_TX_WR1 (0x0825) /**< Socket 0 tx write pointer 1 */
|
||||
#define REG_S0_RX_RSR0 (0x0826) /**< Socket 0 rx received size 0 */
|
||||
#define REG_S0_RX_RSR1 (0x0827) /**< Socket 0 rx received size 1 */
|
||||
#define REG_S0_RX_RD0 (0x0828) /**< Socket 0 rx read pointer 0 */
|
||||
#define REG_S0_RX_RD1 (0x0829) /**< Socket 0 rx read pointer 1 */
|
||||
#define REG_S0_RX_WR0 (0x082a) /**< Socket 0 rx write pointer 0 */
|
||||
#define REG_S0_RX_WR1 (0x082b) /**< Socket 0 rx write pointer 1 */
|
||||
#define REG_S0_IMR (0x082c) /**< Socket 0 interrupt mask */
|
||||
#define REG_S0_FRAG0 (0x082d) /**< Socket 0 fragment offset in IP header 0 */
|
||||
#define REG_S0_FRAG1 (0x082e) /**< Socket 0 fragment offset in IP header 1 */
|
||||
#define REG_S0_KPALVTR (0x082f) /**< Socket 0 keep alive timer */
|
||||
/** @} */
|
||||
|
||||
#define Sn_RXBUF_SIZE_BASE (0x001E) /**< Register to configure a sockets RX buffer size */
|
||||
#define Sn_TXBUF_SIZE_BASE (0x001F) /**< Register to configure a sockets TX buffer size */
|
||||
|
||||
/**
|
||||
* @name Some selected bitfield definitions.
|
||||
* @{
|
||||
*/
|
||||
/* Common definitions. */
|
||||
#define MODE_RESET (0x80) /**< Device mode: reset. */
|
||||
#define PHY_LINK_UP (0x01) /**< Link up indication. */
|
||||
#define IMR_S0_INT (0x01) /**< Global Socket 0 interrupt mask. */
|
||||
#define SPI_CONF SPI_MODE_0 /**< Configure SPI MODE 0 */
|
||||
#define CHIP_VERSION (0x04) /**< Chip version we expect to read from the device */
|
||||
|
||||
#define ENABLE_MAC_FILTER (0x80) /**< Enable hardware MAC filter for raw mode */
|
||||
#define ENABLE_BROADCAST_FILTER (0x40) /**< Enable Broadcast blocking */
|
||||
#define ENABLE_MULTICAST_FILTER (0x20) /**< Enable Multicast blocking */
|
||||
#define MR_MACRAW (0x04) /**< Socket mode: raw Ethernet */
|
||||
|
||||
#define CR_OPEN (0x01) /**< Socket command: open */
|
||||
#define CR_SEND (0x20) /**< Socket command: send */
|
||||
#define CR_RECV (0x40) /**< Socket command: receive new data */
|
||||
|
||||
#define IR_RECV (0x04) /**< Socket interrupt: data received */
|
||||
#define IR_SEND_OK (0x10) /**< Socket interrupt: send ok */
|
||||
|
||||
#define CMD_READ (0x00) /**< Define for the read command */
|
||||
#define CMD_WRITE (0x04) /**< Define for the write command */
|
||||
#define SOCKET0_RX_BUFFER (0x18) /**< BSB for Socket 0 Receive Buffer. */
|
||||
#define SOCKET0_TX_BUFFER (0x10) /**< BSB for Socket 0 Transmit Buffer. */
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* W5500_REGS_H */
|
||||
/** @} */
|
446
drivers/w5500/w5500.c
Normal file
446
drivers/w5500/w5500.c
Normal file
@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_w5500
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Device driver implementation for w5500 Ethernet devices
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "iolist.h"
|
||||
#include "net/ethernet.h"
|
||||
#include "net/eui_provider.h"
|
||||
#include "net/netdev/eth.h"
|
||||
#include "net/ethernet/hdr.h"
|
||||
#include "ztimer.h"
|
||||
|
||||
#include "w5500.h"
|
||||
#include "w5500_regs.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
|
||||
/* Socket definitions. */
|
||||
#define BSB_SOCKET_BASE (0x08) /**< Base for Socket n registers. */
|
||||
#define RXBUF_16KB_TO_S0 (0x10) /**< Receive memory size: 16 kB. */
|
||||
#define TXBUF_16KB_TO_S0 (0x10) /**< Transmit memory size: 16 kB. */
|
||||
|
||||
static const netdev_driver_t netdev_driver_w5500;
|
||||
|
||||
static uint8_t read_register(w5500_t *dev, uint16_t reg)
|
||||
{
|
||||
uint16_t address = reg & 0x07ff;
|
||||
uint8_t command = (uint8_t)((reg & 0xf800) >> 8u) | CMD_READ;
|
||||
|
||||
spi_transfer_u16_be(dev->p.spi, dev->p.cs, true, address);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, true, command);
|
||||
return spi_transfer_byte(dev->p.spi, dev->p.cs, false, 0u);
|
||||
}
|
||||
|
||||
static void write_register(w5500_t *dev, uint16_t reg, uint8_t data)
|
||||
{
|
||||
uint16_t address = reg & 0x07ff;
|
||||
uint8_t command = (uint8_t)((reg & 0xf800) >> 8u) | CMD_WRITE;
|
||||
|
||||
spi_transfer_u16_be(dev->p.spi, dev->p.cs, true, address);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, true, command);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, false, data);
|
||||
}
|
||||
|
||||
static uint16_t read_addr(w5500_t *dev, uint16_t addr_high, uint16_t addr_low)
|
||||
{
|
||||
uint16_t res = (read_register(dev, addr_high) << 8);
|
||||
|
||||
res |= read_register(dev, addr_low);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void write_address(w5500_t *dev,
|
||||
uint16_t addr_high, uint16_t addr_low, uint16_t val)
|
||||
{
|
||||
write_register(dev, addr_high, (uint8_t)(val >> 8));
|
||||
write_register(dev, addr_low, (uint8_t)(val & 0xff));
|
||||
}
|
||||
|
||||
static void read_chunk(w5500_t *dev, uint16_t addr, uint8_t *data, size_t len)
|
||||
{
|
||||
uint16_t address = addr & 0x07ff;
|
||||
uint8_t command = (uint8_t)((addr & 0xf800) >> 8u) | CMD_READ;
|
||||
|
||||
spi_transfer_u16_be(dev->p.spi, dev->p.cs, true, address);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, true, command);
|
||||
spi_transfer_bytes(dev->p.spi, dev->p.cs, false, NULL, data, len);
|
||||
}
|
||||
|
||||
static void write_chunk(w5500_t *dev, uint16_t addr, uint8_t *data, size_t len)
|
||||
{
|
||||
uint16_t address = addr & 0x07ff;
|
||||
uint8_t command = (uint8_t)((addr & 0xf800) >> 8u) | CMD_WRITE;
|
||||
|
||||
spi_transfer_u16_be(dev->p.spi, dev->p.cs, true, address);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, true, command);
|
||||
spi_transfer_bytes(dev->p.spi, dev->p.cs, false, data, NULL, len);
|
||||
}
|
||||
|
||||
static void extint(void *arg)
|
||||
{
|
||||
w5500_t *dev = (w5500_t *)arg;
|
||||
|
||||
netdev_trigger_event_isr(&dev->netdev);
|
||||
if (!gpio_is_valid(dev->p.irq)) {
|
||||
/* restart timer if we are polling */
|
||||
ztimer_set(ZTIMER_MSEC, &dev->timerInstance, dev->p.polling_interval_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void w5500_setup(w5500_t *dev, const w5500_params_t *params, uint8_t index)
|
||||
{
|
||||
assert(dev);
|
||||
assert(params);
|
||||
|
||||
/* Initialize netdev structure. */
|
||||
dev->netdev.driver = &netdev_driver_w5500;
|
||||
dev->netdev.event_callback = NULL;
|
||||
dev->netdev.context = dev;
|
||||
/* Initialize the device descriptor. */
|
||||
dev->p = *params;
|
||||
|
||||
dev->frame_size = 0u;
|
||||
dev->link_up = false;
|
||||
dev->frame_sent = false;
|
||||
|
||||
/* Initialize the chip select pin. */
|
||||
spi_init_cs(dev->p.spi, dev->p.cs);
|
||||
if (gpio_is_valid(dev->p.irq)) {
|
||||
/* Initialize the external interrupt pin. */
|
||||
gpio_init_int(dev->p.irq, GPIO_IN, GPIO_FALLING, extint, dev);
|
||||
}
|
||||
netdev_register(&dev->netdev, NETDEV_W5500, index);
|
||||
}
|
||||
|
||||
static int init(netdev_t *netdev)
|
||||
{
|
||||
w5500_t *dev = (w5500_t *)netdev;
|
||||
uint8_t tmp;
|
||||
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
|
||||
/* Reset the device. */
|
||||
write_register(dev, REG_MODE, MODE_RESET);
|
||||
while (read_register(dev, REG_MODE) & MODE_RESET) {}
|
||||
|
||||
/* Test the SPI connection by reading the value of the version register. */
|
||||
tmp = read_register(dev, REG_VERSIONR);
|
||||
if (tmp != CHIP_VERSION) {
|
||||
spi_release(dev->p.spi);
|
||||
LOG_ERROR("[w5500] error: invalid chip ID %x\n", tmp);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Write the MAC address. */
|
||||
eui48_t address;
|
||||
netdev_eui48_get(netdev, &address);
|
||||
write_chunk(dev, REG_SHAR0, (uint8_t*)&address, sizeof(eui48_t));
|
||||
|
||||
/* Configure 16 kB memory to be used by socket 0. */
|
||||
write_register(dev, REG_S0_RXBUF_SIZE, RXBUF_16KB_TO_S0);
|
||||
write_register(dev, REG_S0_TXBUF_SIZE, TXBUF_16KB_TO_S0);
|
||||
|
||||
/* Configure remaining RX/TX buffers to 0 kB. */
|
||||
for (uint8_t socket = 1u; socket < 8u; socket++) {
|
||||
uint16_t bsb = (socket << 5u) | 0x08 | CMD_WRITE;
|
||||
uint16_t Sn_RXBUF_SIZE = Sn_RXBUF_SIZE_BASE | bsb;
|
||||
uint16_t Sn_TXBUF_SIZE = Sn_TXBUF_SIZE_BASE | bsb;
|
||||
write_register(dev, Sn_RXBUF_SIZE, 0u);
|
||||
write_register(dev, Sn_TXBUF_SIZE, 0u);
|
||||
}
|
||||
/* Next we configure socket 0 to work in MACRAW mode with MAC filtering. */
|
||||
write_register(dev, REG_S0_MR, (MR_MACRAW | ENABLE_MAC_FILTER | ENABLE_MULTICAST_FILTER));
|
||||
|
||||
/* Set the source IP address to something random to prevent the device to do
|
||||
* stupid thing (e.g. answering ICMP echo requests on its own). */
|
||||
write_register(dev, REG_SIPR0, 0x00);
|
||||
write_register(dev, REG_SIPR1, 0x00);
|
||||
write_register(dev, REG_SIPR2, 0x00);
|
||||
write_register(dev, REG_SIPR3, 0x00);
|
||||
|
||||
if (!gpio_is_valid(dev->p.irq)) {
|
||||
dev->timerInstance.callback = extint;
|
||||
dev->timerInstance.arg = dev;
|
||||
ztimer_set(ZTIMER_MSEC, &dev->timerInstance, dev->p.polling_interval_ms);
|
||||
}
|
||||
else {
|
||||
/* Configure interrupt pin to trigger on socket 0 events. */
|
||||
write_register(dev, REG_SIMR, IMR_S0_INT);
|
||||
}
|
||||
/* Open socket. */
|
||||
write_register(dev, REG_S0_CR, CR_OPEN);
|
||||
|
||||
spi_release(dev->p.spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void write_tx0_buffer(w5500_t *dev, uint16_t address, uint8_t *data, uint16_t size)
|
||||
{
|
||||
spi_transfer_u16_be(dev->p.spi, dev->p.cs, true, address);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, true, SOCKET0_TX_BUFFER | CMD_WRITE);
|
||||
|
||||
spi_transfer_bytes(dev->p.spi, dev->p.cs, false, data, NULL, size);
|
||||
}
|
||||
|
||||
static uint16_t get_free_size_in_tx_buffer(w5500_t *dev)
|
||||
{
|
||||
uint16_t tx_free = read_addr(dev, REG_S0_TX_FSR0, REG_S0_TX_FSR1);
|
||||
uint16_t tmp = read_addr(dev, REG_S0_TX_FSR0, REG_S0_TX_FSR1);
|
||||
|
||||
/* See Note in the description of Sn_TX_FSR in the datasheet: This is a 16 bit value,
|
||||
so we read it until we get the same value twice. The W5500 will update it
|
||||
while transmitting data. */
|
||||
while (tx_free != tmp) {
|
||||
tx_free = tmp;
|
||||
tmp = read_addr(dev, REG_S0_TX_FSR0, REG_S0_TX_FSR1);
|
||||
}
|
||||
|
||||
return tx_free;
|
||||
}
|
||||
|
||||
static int send(netdev_t *netdev, const iolist_t *iolist)
|
||||
{
|
||||
w5500_t *dev = (w5500_t *)netdev;
|
||||
int result = -ENODEV;
|
||||
|
||||
/* Get access to the SPI bus for the duration of this function. */
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
|
||||
uint8_t tmp = read_register(dev, REG_PHYCFGR);
|
||||
|
||||
if (tmp & PHY_LINK_UP) {
|
||||
uint16_t tx_free = get_free_size_in_tx_buffer(dev);
|
||||
uint16_t data_length = (uint16_t)iolist_size(iolist);
|
||||
|
||||
/* Get the write pointer. */
|
||||
uint16_t socket0_write_pointer = read_addr(dev, REG_S0_TX_WR0, REG_S0_TX_WR1);
|
||||
|
||||
/* Make sure we can write the full packet. */
|
||||
if (data_length <= tx_free) {
|
||||
/* reset the frame size information */
|
||||
dev->frame_size = 0u;
|
||||
|
||||
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
|
||||
size_t len = iol->iol_len;
|
||||
write_tx0_buffer(dev, socket0_write_pointer + dev->frame_size,
|
||||
iol->iol_base, len);
|
||||
dev->frame_size += len;
|
||||
}
|
||||
/* Update the write pointer. */
|
||||
write_address(dev, REG_S0_TX_WR0, REG_S0_TX_WR1,
|
||||
socket0_write_pointer + dev->frame_size);
|
||||
/* Trigger the sending process. */
|
||||
write_register(dev, REG_S0_CR, CR_SEND);
|
||||
|
||||
DEBUG("[w5500] send: transferred %i byte (at 0x%04x)\n", data_length,
|
||||
(int)socket0_write_pointer);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("%s: link is down: PHYCFGR = 0x%02x\n", __func__, tmp);
|
||||
result = -EIO;
|
||||
}
|
||||
|
||||
/* release the SPI bus again */
|
||||
spi_release(dev->p.spi);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int confirm_send(netdev_t *netdev, void *info)
|
||||
{
|
||||
w5500_t *dev = (w5500_t *)netdev;
|
||||
|
||||
(void)info;
|
||||
|
||||
if (dev->frame_sent == false) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
else {
|
||||
return dev->frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_rx0_buffer(w5500_t *dev, uint16_t address, uint8_t *data, uint16_t size)
|
||||
{
|
||||
spi_transfer_u16_be(dev->p.spi, dev->p.cs, true, address);
|
||||
spi_transfer_byte(dev->p.spi, dev->p.cs, true, SOCKET0_RX_BUFFER);
|
||||
|
||||
spi_transfer_bytes(dev->p.spi, dev->p.cs, false, NULL, data, size);
|
||||
}
|
||||
|
||||
static uint16_t get_size_in_rx_buffer(w5500_t *dev)
|
||||
{
|
||||
uint16_t received = read_addr(dev, REG_S0_RX_RSR0, REG_S0_RX_RSR1);
|
||||
uint16_t tmp = read_addr(dev, REG_S0_RX_RSR0, REG_S0_RX_RSR1);
|
||||
|
||||
/* See Note in the description of Sn_RX_RSR in the datasheet: This is a 16 bit value,
|
||||
so we read it until we get the same value twice. The W5500 will update it
|
||||
while receiving data, when we read the same value again we can assume that
|
||||
the current packet is fully received. */
|
||||
while (received != tmp) {
|
||||
received = tmp;
|
||||
tmp = read_addr(dev, REG_S0_RX_RSR0, REG_S0_RX_RSR1);
|
||||
}
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
static int receive(netdev_t *netdev, void *buf, size_t max_len, void *info)
|
||||
{
|
||||
(void)info;
|
||||
w5500_t *dev = (w5500_t *)netdev;
|
||||
uint16_t packet_size = 0u;
|
||||
int ret_value = 0;
|
||||
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
|
||||
uint16_t available_bytes = get_size_in_rx_buffer(dev);
|
||||
|
||||
if (available_bytes > 0u) {
|
||||
uint16_t socket0_read_pointer = read_addr(dev, REG_S0_RX_RD0, REG_S0_RX_RD1);
|
||||
/* I could not find a hint in the documentation of the W5500, but different implementations
|
||||
pointed me to the fact that the W5500 stores the size of the packet right in front of the
|
||||
packet data. */
|
||||
read_rx0_buffer(dev, socket0_read_pointer, (uint8_t*)&packet_size, 2u);
|
||||
packet_size = ntohs(packet_size) - 2;
|
||||
ret_value = packet_size;
|
||||
|
||||
if (max_len > 0u) { /* max_len > 0u: Client wants to read or drop the packet. */
|
||||
if (packet_size > max_len) {
|
||||
buf = NULL; /* Drop the packet. */
|
||||
ret_value = -ENOBUFS;
|
||||
}
|
||||
|
||||
socket0_read_pointer += 2u; /* Add the 2 bytes of the packet_size. */
|
||||
if (buf != NULL) {
|
||||
read_rx0_buffer(dev, socket0_read_pointer, (uint8_t *)buf, packet_size);
|
||||
DEBUG("[w5500] receive: got packet of %i byte (at 0x%04x)\n", packet_size,
|
||||
(int)socket0_read_pointer);
|
||||
}
|
||||
else {
|
||||
DEBUG("[w5500] receive: drop packet of %i byte (at 0x%04x)\n", packet_size,
|
||||
(int)socket0_read_pointer);
|
||||
}
|
||||
socket0_read_pointer += packet_size;
|
||||
}
|
||||
|
||||
/* Update read pointer. */
|
||||
write_address(dev, REG_S0_RX_RD0, REG_S0_RX_RD1, socket0_read_pointer);
|
||||
write_register(dev, REG_S0_CR, CR_RECV);
|
||||
while (read_register(dev, REG_S0_CR)) {}
|
||||
}
|
||||
|
||||
spi_release(dev->p.spi);
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
static void isr(netdev_t *netdev)
|
||||
{
|
||||
w5500_t *dev = (w5500_t *)netdev;
|
||||
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
/* Get phy status register. */
|
||||
uint8_t phy_status = read_register(dev, REG_PHYCFGR);
|
||||
/* Get socket 0 interrupt register. */
|
||||
uint8_t socket0_interrupt_status = read_register(dev, REG_S0_IR);
|
||||
|
||||
/* Clear interrupts. */
|
||||
write_register(dev, REG_S0_IR, socket0_interrupt_status);
|
||||
spi_release(dev->p.spi);
|
||||
|
||||
if ((phy_status & PHY_LINK_UP) && (dev->link_up == false)) {
|
||||
dev->link_up = true;
|
||||
DEBUG("%s: link is up: PHYCFGR = 0x%02x\n", __func__, phy_status);
|
||||
netdev->event_callback(&dev->netdev, NETDEV_EVENT_LINK_UP);
|
||||
}
|
||||
else if (!(phy_status & PHY_LINK_UP) && (dev->link_up == true)) {
|
||||
dev->link_up = false;
|
||||
netdev->event_callback(&dev->netdev, NETDEV_EVENT_LINK_DOWN);
|
||||
DEBUG("%s: link is down: PHYCFGR = 0x%02x\n", __func__, phy_status);
|
||||
}
|
||||
|
||||
while (socket0_interrupt_status & (IR_RECV | IR_SEND_OK)) {
|
||||
if (socket0_interrupt_status & IR_RECV) {
|
||||
DEBUG("[w5500] netdev RX complete\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
|
||||
}
|
||||
if (socket0_interrupt_status & IR_SEND_OK) {
|
||||
DEBUG("[w5500] netdev TX complete\n");
|
||||
dev->frame_sent = true;
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
|
||||
}
|
||||
|
||||
/* Check interrupt status again. */
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
socket0_interrupt_status = read_register(dev, REG_S0_IR);
|
||||
write_register(dev, REG_S0_IR, socket0_interrupt_status);
|
||||
spi_release(dev->p.spi);
|
||||
}
|
||||
}
|
||||
|
||||
static int get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
|
||||
{
|
||||
w5500_t *dev = (w5500_t *)netdev;
|
||||
int res = 0;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_ADDRESS:
|
||||
assert(max_len >= ETHERNET_ADDR_LEN);
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
read_chunk(dev, REG_SHAR0, value, ETHERNET_ADDR_LEN);
|
||||
spi_release(dev->p.spi);
|
||||
res = ETHERNET_ADDR_LEN;
|
||||
break;
|
||||
case NETOPT_LINK:
|
||||
spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk);
|
||||
uint8_t tmp = read_register(dev, REG_PHYCFGR);
|
||||
spi_release(dev->p.spi);
|
||||
dev->link_up = ((tmp & PHY_LINK_UP) != 0u);
|
||||
*((netopt_enable_t *)value) = dev->link_up ? NETOPT_ENABLE
|
||||
: NETOPT_DISABLE;
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
default:
|
||||
res = netdev_eth_get(netdev, opt, value, max_len);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const netdev_driver_t netdev_driver_w5500 = {
|
||||
.send = send,
|
||||
.recv = receive,
|
||||
.confirm_send = confirm_send,
|
||||
.init = init,
|
||||
.isr = isr,
|
||||
.get = get,
|
||||
.set = netdev_eth_set,
|
||||
};
|
56
sys/net/gnrc/netif/init_devs/auto_init_w5500.c
Normal file
56
sys/net/gnrc/netif/init_devs/auto_init_w5500.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_auto_init_gnrc_netif
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Auto initialization for W5500 Ethernet devices
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "w5500.h"
|
||||
#include "w5500_params.h"
|
||||
#include "net/gnrc/netif/ethernet.h"
|
||||
#include "include/init_devs.h"
|
||||
|
||||
/**
|
||||
* @brief Find out how many of these devices we need to care for
|
||||
*/
|
||||
#define W5500_NUM ARRAY_SIZE(w5500_params)
|
||||
|
||||
/**
|
||||
* @brief Allocate memory for the device descriptors
|
||||
* @{
|
||||
*/
|
||||
static w5500_t dev[W5500_NUM];
|
||||
/** @} */
|
||||
|
||||
static gnrc_netif_t _netif[W5500_NUM];
|
||||
|
||||
/**
|
||||
* @brief Stacks for the MAC layer threads
|
||||
*/
|
||||
static char stack[W5500_NUM][GNRC_NETIF_STACKSIZE_DEFAULT];
|
||||
|
||||
void auto_init_w5500(void)
|
||||
{
|
||||
for (unsigned i = 0; i < W5500_NUM; i++) {
|
||||
LOG_DEBUG("[auto_init_netif] initializing w5500 #%u\n", i);
|
||||
|
||||
/* setup netdev device */
|
||||
w5500_setup(&dev[i], &w5500_params[i], i);
|
||||
/* initialize netdev <-> gnrc adapter state */
|
||||
gnrc_netif_ethernet_create(&_netif[i], stack[i], GNRC_NETIF_STACKSIZE_DEFAULT,
|
||||
GNRC_NETIF_PRIO, "w5500", &dev[i].netdev);
|
||||
}
|
||||
}
|
||||
/** @} */
|
@ -177,4 +177,9 @@ void gnrc_netif_init_devs(void)
|
||||
auto_init_tinyusb_netdev();
|
||||
}
|
||||
|
||||
if (IS_USED(MODULE_W5500)) {
|
||||
extern void auto_init_w5500(void);
|
||||
auto_init_w5500();
|
||||
}
|
||||
|
||||
}
|
||||
|
10
tests/drivers/w5500/Makefile
Normal file
10
tests/drivers/w5500/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
include ../Makefile.drivers_common
|
||||
|
||||
USEMODULE += test_utils_netdev_eth_minimal
|
||||
|
||||
# the driver to test
|
||||
USEMODULE += w5500
|
||||
|
||||
INCLUDES += -I$(APPDIR)
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
29
tests/drivers/w5500/Makefile.ci
Normal file
29
tests/drivers/w5500/Makefile.ci
Normal file
@ -0,0 +1,29 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-mega2560 \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
atmega328p-xplained-mini \
|
||||
atmega8 \
|
||||
bluepill-stm32f030c8 \
|
||||
i-nucleo-lrwan1 \
|
||||
msb-430 \
|
||||
msb-430h \
|
||||
nucleo-f030r8 \
|
||||
nucleo-f031k6 \
|
||||
nucleo-f042k6 \
|
||||
nucleo-f303k8 \
|
||||
nucleo-f334r8 \
|
||||
nucleo-l011k4 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
samd10-xmini \
|
||||
slstk3400a \
|
||||
stk3200 \
|
||||
stm32f030f4-demo \
|
||||
stm32f0discovery \
|
||||
stm32l0538-disco \
|
||||
waspmote-pro \
|
||||
#
|
2
tests/drivers/w5500/app.config.test
Normal file
2
tests/drivers/w5500/app.config.test
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_MODULE_TEST_UTILS_NETDEV_ETH_MINIMAL=y
|
||||
CONFIG_MODULE_W5500=y
|
45
tests/drivers/w5500/init_dev.h
Normal file
45
tests/drivers/w5500/init_dev.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Device-specific test header file W5500 ethernet device driver
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*/
|
||||
#ifndef INIT_DEV_H
|
||||
#define INIT_DEV_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "net/netdev.h"
|
||||
|
||||
#include "w5500.h"
|
||||
#include "w5500_params.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define W5500_NUM ARRAY_SIZE(w5500_params)
|
||||
#define NETDEV_ETH_MINIMAL_NUMOF W5500_NUM
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INIT_DEV_H */
|
||||
/** @} */
|
67
tests/drivers/w5500/main.c
Normal file
67
tests/drivers/w5500/main.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Stefan Schmidt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for W5500 ethernet device driver
|
||||
*
|
||||
* @author Stefan Schmidt <stemschmidt@gmail.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "test_utils/netdev_eth_minimal.h"
|
||||
#include "init_dev.h"
|
||||
#include "assert.h"
|
||||
#include "w5500.h"
|
||||
#include "w5500_params.h"
|
||||
|
||||
static w5500_t w5500[W5500_NUM];
|
||||
|
||||
int netdev_eth_minimal_init_devs(netdev_event_cb_t cb) {
|
||||
for (unsigned i = 0; i < W5500_NUM; i++) {
|
||||
netdev_t *device = &w5500[i].netdev;
|
||||
|
||||
/* setup the specific driver */
|
||||
w5500_setup(&w5500[i], &w5500_params[i], i);
|
||||
|
||||
/* set the application-provided callback */
|
||||
device->event_callback = cb;
|
||||
|
||||
/* initialize the device driver */
|
||||
int res = device->driver->init(device);
|
||||
assert(!res);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Test application for W5500 ethernet device driver");
|
||||
|
||||
int res = netdev_eth_minimal_init();
|
||||
if (res) {
|
||||
puts("Error initializing devices");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* start the shell */
|
||||
puts("Initialization successful - starting the shell now");
|
||||
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user