mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers: added driver for W5100 Ethernet chips
This commit is contained in:
parent
a74f429fc5
commit
d7dbac7c61
@ -21,6 +21,7 @@ endif
|
|||||||
|
|
||||||
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE)))
|
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE)))
|
||||||
USEMODULE += gnrc_netif
|
USEMODULE += gnrc_netif
|
||||||
|
USEMODULE += gnrc_netdev2
|
||||||
USEMODULE += netdev_default
|
USEMODULE += netdev_default
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -136,6 +136,10 @@ ifneq (,$(filter srf08,$(USEMODULE)))
|
|||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter w5100,$(USEMODULE)))
|
||||||
|
USEMODULE += netdev2_eth
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter xbee,$(USEMODULE)))
|
ifneq (,$(filter xbee,$(USEMODULE)))
|
||||||
USEMODULE += ieee802154
|
USEMODULE += ieee802154
|
||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
|
@ -70,3 +70,6 @@ endif
|
|||||||
ifneq (,$(filter lpd8808,$(USEMODULE)))
|
ifneq (,$(filter lpd8808,$(USEMODULE)))
|
||||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lpd8808/include
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lpd8808/include
|
||||||
endif
|
endif
|
||||||
|
ifneq (,$(filter w5100,$(USEMODULE)))
|
||||||
|
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/w5100/include
|
||||||
|
endif
|
||||||
|
85
drivers/include/w5100.h
Normal file
85
drivers/include/w5100.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* 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_w5100 W5100
|
||||||
|
* @ingroup drivers_netdev_netdev2
|
||||||
|
* @brief Driver for W5100 ethernet devices
|
||||||
|
*
|
||||||
|
* This device driver only exposes the MACRAW mode of W5100 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 netdev2 with any software network
|
||||||
|
* stack provided by RIOT (e.g. GNRC). This enables W5100 devices to communicate
|
||||||
|
* via IPv6, enables unlimited connections, and more...
|
||||||
|
*
|
||||||
|
* @note This driver expects to be triggered by the external interrupt
|
||||||
|
* line of the W5100 device. On some Arduino shields this is not
|
||||||
|
* enabled by default, you have to close the corresponding solder
|
||||||
|
* bridge to make it work...
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Interface definition for the W5100 device driver
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef W5100_H
|
||||||
|
#define W5100_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "periph/spi.h"
|
||||||
|
#include "periph/gpio.h"
|
||||||
|
#include "net/netdev2.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief W5100 error codes
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
W5100_ERR_BUS = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief W5100 device descriptor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
spi_t spi; /**< SPI bus used */
|
||||||
|
spi_speed_t spi_speed; /**< clock speed used on the selected SPI bus */
|
||||||
|
gpio_t cs; /**< pin connected to the chip select line */
|
||||||
|
gpio_t evt; /**< pin connected to the INT line */
|
||||||
|
} w5100_params_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device descriptor for W5100 devices
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
netdev2_t nd; /**< extends the netdev2 structure */
|
||||||
|
w5100_params_t p; /**< device configuration parameters */
|
||||||
|
} w5100_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief So the initial device setup
|
||||||
|
*
|
||||||
|
* This function pre-initializes the netdev2 structure, saves the configuration
|
||||||
|
* parameters and finally initializes the SPI bus and the used GPIO pins.
|
||||||
|
*/
|
||||||
|
void w5100_setup(w5100_t *dev, const w5100_params_t *params);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* W5100_h */
|
||||||
|
/* @} */
|
1
drivers/w5100/Makefile
Normal file
1
drivers/w5100/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include $(RIOTBASE)/Makefile.base
|
62
drivers/w5100/include/w5100_params.h
Normal file
62
drivers/w5100/include/w5100_params.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* 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_w5100
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Default parameters for W5100 Ethernet devices
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef W5100_PARAMS_H
|
||||||
|
#define W5100_PARAMS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set default configuration parameters for the W5100 driver
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef W5100_PARAM_SPI
|
||||||
|
#define W5100_PARAM_SPI (SPI_0)
|
||||||
|
#endif
|
||||||
|
#ifndef W5100_PARAM_SPI_SPEED
|
||||||
|
#define W5100_PARAM_SPI_SPEED (SPI_SPEED_5MHZ)
|
||||||
|
#endif
|
||||||
|
#ifndef W5100_PARAM_CS
|
||||||
|
#define W5100_PARAM_CS (GPIO_PIN(0, 0))
|
||||||
|
#endif
|
||||||
|
#ifndef W5100_PARAM_EVT
|
||||||
|
#define W5100_PARAM_EVT (GPIO_PIN(0, 1))
|
||||||
|
#endif
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief W5100 configuration
|
||||||
|
*/
|
||||||
|
static const w5100_params_t w5100_params[] = {
|
||||||
|
{
|
||||||
|
.spi = W5100_PARAM_SPI,
|
||||||
|
.spi_speed = W5100_PARAM_SPI_SPEED,
|
||||||
|
.cs = W5100_PARAM_CS,
|
||||||
|
.evt = W5100_PARAM_EVT
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* W5100_PARAMS_H */
|
||||||
|
/** @} */
|
140
drivers/w5100/include/w5100_regs.h
Normal file
140
drivers/w5100/include/w5100_regs.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* 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_w5100
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Register definitions for W5100 devices
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef W5100_REGS_H
|
||||||
|
#define W5100_REGS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SPI commands
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define CMD_READ (0x0f)
|
||||||
|
#define CMD_WRITE (0xf0)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Common registers
|
||||||
|
*/
|
||||||
|
#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_SUB0 (0x0005) /**< subnet mask 0 */
|
||||||
|
#define REG_SUB1 (0x0006) /**< subnet mask 1 */
|
||||||
|
#define REG_SUB2 (0x0007) /**< subnet mask 2 */
|
||||||
|
#define REG_SUB3 (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_IR (0x0015) /**< interrupt flags */
|
||||||
|
#define REG_IMR (0x0016) /**< interrupt masks */
|
||||||
|
#define REG_RTR0 (0x0017) /**< retry time 0 */
|
||||||
|
#define REG_RTR1 (0x0018) /**< retry time 1 */
|
||||||
|
#define REG_RCR (0x0019) /**< retry count */
|
||||||
|
#define REG_RMSR (0x001a) /**< RX memory size */
|
||||||
|
#define REG_TMSR (0x001b) /**< TX memory size */
|
||||||
|
#define REG_PATR0 (0x001c) /**< PPPoE auth type 0 */
|
||||||
|
#define REG_PATR1 (0x001d) /**< PPPoE auth type 1 */
|
||||||
|
#define REG_PTIMER (0x0028) /**< PPP LCP request timer */
|
||||||
|
#define REG_PMAGIC (0x0029) /**< PPP LCP magic number */
|
||||||
|
#define REG_UIPR0 (0x002a) /**< unreachable IP address 0 */
|
||||||
|
#define REG_UIPR1 (0x002b) /**< unreachable IP address 1 */
|
||||||
|
#define REG_UIPR2 (0x002c) /**< unreachable IP address 2 */
|
||||||
|
#define REG_UIPR3 (0x002d) /**< unreachable IP address 3 */
|
||||||
|
#define REG_UPORT0 (0x00fe) /**< unreachable port 0 */
|
||||||
|
#define REG_UPORT1 (0x002f) /**< unreachable port 1 */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Socket 0 registers
|
||||||
|
*
|
||||||
|
* As we are using the device in MACRAW mode, we only need socket 0.
|
||||||
|
*/
|
||||||
|
#define S0_MR (0x0400) /**< mode */
|
||||||
|
#define S0_CR (0x0401) /**< control */
|
||||||
|
#define S0_IR (0x0402) /**< interrupt flags */
|
||||||
|
#define S0_SR (0x0403) /**< state */
|
||||||
|
#define S0_DHAR0 (0x0406) /**< destination hardware address 0 */
|
||||||
|
#define S0_DHAR1 (0x0407) /**< destination hardware address 1 */
|
||||||
|
#define S0_DHAR2 (0x0408) /**< destination hardware address 2 */
|
||||||
|
#define S0_DHAR3 (0x0409) /**< destination hardware address 3 */
|
||||||
|
#define S0_DHAR4 (0x040a) /**< destination hardware address 4 */
|
||||||
|
#define S0_DHAR5 (0x040b) /**< destination hardware address 5 */
|
||||||
|
#define S0_DIPR0 (0x040c) /**< destination IP address 0 */
|
||||||
|
#define S0_DIPR1 (0x040d) /**< destination IP address 1 */
|
||||||
|
#define S0_DIPR2 (0x040e) /**< destination IP address 2 */
|
||||||
|
#define S0_DIPR3 (0x040f) /**< destination IP address 3 */
|
||||||
|
#define S0_DPORT0 (0x0410) /**< destination port 0 */
|
||||||
|
#define S0_DPORT1 (0x0411) /**< destination port 1 */
|
||||||
|
#define S0_MSSR0 (0x0412) /**< maximum segment size 0 */
|
||||||
|
#define S0_MSSR1 (0x0413) /**< maximum segment size 1 */
|
||||||
|
#define S0_PROTO (0x0414) /**< protocol in IP raw mode */
|
||||||
|
#define S0_TOS (0x0415) /**< IP TOS */
|
||||||
|
#define S0_TTL (0x0416) /**< IP TTL */
|
||||||
|
#define S0_TX_FSR0 (0x0420) /**< TX free size 0 */
|
||||||
|
#define S0_TX_FSR1 (0x0421) /**< TX free size 1 */
|
||||||
|
#define S0_TX_RD0 (0x0422) /**< TX read pointer 0 */
|
||||||
|
#define S0_TX_RD1 (0x0423) /**< TX read pointer 1 */
|
||||||
|
#define S0_TX_WR0 (0x0424) /**< TX write pointer 0 */
|
||||||
|
#define S0_TX_WR1 (0x0425) /**< TX write pointer 1 */
|
||||||
|
#define S0_RX_RSR0 (0x0426) /**< RX receive size 0 */
|
||||||
|
#define S0_RX_RSR1 (0x0427) /**< RX receive size 1 */
|
||||||
|
#define S0_RX_RD0 (0x0428) /**< RX read pointer 0 */
|
||||||
|
#define S0_RX_RD1 (0x0429) /**< RX read pointer 1 */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Some selected bitfield definitions
|
||||||
|
*/
|
||||||
|
#define MODE_RESET (0x80) /**< device mode: reset */
|
||||||
|
|
||||||
|
#define RMSR_8KB_TO_S0 (0x03) /**< receive memory size: 8kib */
|
||||||
|
#define TMSR_8KB_TO_S0 (0x03) /**< transmit memory size: 8kib */
|
||||||
|
|
||||||
|
#define IMR_S0_INT (0x01) /**< global socket 0 interrupt mask */
|
||||||
|
|
||||||
|
#define MR_UDP (0x02) /**< socket mode: UDP */
|
||||||
|
#define MR_MACRAW (0x04) /**< socket mode: raw Ethernet */
|
||||||
|
|
||||||
|
#define CR_OPEN (0x01) /**< socket command: open */
|
||||||
|
#define CR_CLOSE (0x10) /**< socket command: close */
|
||||||
|
#define CR_SEND_MAC (0x21) /**< socket command: send raw */
|
||||||
|
#define CR_RECV (0x40) /**< socket command: receive new data */
|
||||||
|
|
||||||
|
#define IR_SEND_OK (0x10) /**< socket interrupt: send ok */
|
||||||
|
#define IR_RECV (0x04) /**< socket interrupt: data received */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* W5100_REGS_H */
|
||||||
|
/** @} */
|
313
drivers/w5100/w5100.c
Normal file
313
drivers/w5100/w5100.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* 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_w5100
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Device driver implementation for w5100 Ethernet devices
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "assert.h"
|
||||||
|
#include "periph/cpuid.h"
|
||||||
|
|
||||||
|
#include "net/ethernet.h"
|
||||||
|
#include "net/netdev2/eth.h"
|
||||||
|
|
||||||
|
#include "w5100.h"
|
||||||
|
#include "w5100_regs.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SPI_CONF SPI_CONF_FIRST_RISING
|
||||||
|
#define RMSR_DEFAULT_VALUE (0x55)
|
||||||
|
#define MAC_SEED (0x23)
|
||||||
|
|
||||||
|
#define S0_MEMSIZE (0x2000)
|
||||||
|
#define S0_MASK (S0_MEMSIZE - 1)
|
||||||
|
#define S0_TX_BASE (0x4000)
|
||||||
|
#define S0_RX_BASE (0x6000)
|
||||||
|
|
||||||
|
static const netdev2_driver_t netdev2_driver_w5100;
|
||||||
|
|
||||||
|
static inline void send_addr(w5100_t *dev, uint16_t addr)
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
spi_transfer_byte(dev->p.spi, (addr >> 8), NULL);
|
||||||
|
spi_transfer_byte(dev->p.spi, (addr & 0xff), NULL);
|
||||||
|
#else
|
||||||
|
spi_transfer_byte(dev->p.spi, (addr & 0xff), NULL);
|
||||||
|
spi_transfer_byte(dev->p.spi, (addr >> 8), NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t rreg(w5100_t *dev, uint16_t reg)
|
||||||
|
{
|
||||||
|
uint8_t data;
|
||||||
|
|
||||||
|
gpio_clear(dev->p.cs);
|
||||||
|
spi_transfer_byte(dev->p.spi, CMD_READ, NULL);
|
||||||
|
send_addr(dev, reg++);
|
||||||
|
spi_transfer_byte(dev->p.spi, 0, (char *)&data);
|
||||||
|
gpio_set(dev->p.cs);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t raddr(w5100_t *dev, uint16_t addr_high, uint16_t addr_low)
|
||||||
|
{
|
||||||
|
uint16_t res = (rreg(dev, addr_high) << 8);
|
||||||
|
res |= rreg(dev, addr_low);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
/* reading a chunk must be split in multiple single byte reads, as the
|
||||||
|
* device does not support auto address increment via SPI */
|
||||||
|
for (int i = 0; i < (int)len; i++) {
|
||||||
|
data[i] = rreg(dev, addr++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wreg(w5100_t *dev, uint16_t reg, uint8_t data)
|
||||||
|
{
|
||||||
|
gpio_clear(dev->p.cs);
|
||||||
|
spi_transfer_byte(dev->p.spi, CMD_WRITE, NULL);
|
||||||
|
send_addr(dev, reg);
|
||||||
|
spi_transfer_byte(dev->p.spi, data, NULL);
|
||||||
|
gpio_set(dev->p.cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waddr(w5100_t *dev,
|
||||||
|
uint16_t addr_high, uint16_t addr_low, uint16_t val)
|
||||||
|
{
|
||||||
|
wreg(dev, addr_high, (uint8_t)(val >> 8));
|
||||||
|
wreg(dev, addr_low, (uint8_t)(val & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
/* writing a chunk must be split in multiple single byte writes, as the
|
||||||
|
* device does not support auto address increment via SPI */
|
||||||
|
for (int i = 0; i < (int)len; i++) {
|
||||||
|
wreg(dev, addr++, data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void extint(void *arg)
|
||||||
|
{
|
||||||
|
w5100_t *dev = (w5100_t *)arg;
|
||||||
|
|
||||||
|
if (dev->nd.event_callback) {
|
||||||
|
dev->nd.event_callback(&dev->nd, NETDEV2_EVENT_ISR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void w5100_setup(w5100_t *dev, const w5100_params_t *params)
|
||||||
|
{
|
||||||
|
/* initialize netdev structure */
|
||||||
|
dev->nd.driver = &netdev2_driver_w5100;
|
||||||
|
dev->nd.event_callback = NULL;
|
||||||
|
dev->nd.context = dev;
|
||||||
|
|
||||||
|
/* initialize the device descriptor */
|
||||||
|
memcpy(&dev->p, params, sizeof(w5100_params_t));
|
||||||
|
|
||||||
|
/* initialize pins and SPI */
|
||||||
|
gpio_init(dev->p.cs, GPIO_OUT);
|
||||||
|
gpio_set(dev->p.cs);
|
||||||
|
spi_init_master(dev->p.spi, SPI_CONF, dev->p.spi_speed);
|
||||||
|
|
||||||
|
gpio_init_int(dev->p.evt, GPIO_IN, GPIO_FALLING, extint, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init(netdev2_t *netdev)
|
||||||
|
{
|
||||||
|
w5100_t *dev = (w5100_t *)netdev;
|
||||||
|
uint8_t tmp;
|
||||||
|
uint8_t hwaddr[ETHERNET_ADDR_LEN];
|
||||||
|
#if CPUID_LEN
|
||||||
|
uint8_t cpuid[CPUID_LEN];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* test the SPI connection by reading the value of the RMSR register */
|
||||||
|
tmp = rreg(dev, REG_TMSR);
|
||||||
|
if (tmp != RMSR_DEFAULT_VALUE) {
|
||||||
|
LOG_ERROR("[w5100] error: no SPI connection\n");
|
||||||
|
return W5100_ERR_BUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset the device */
|
||||||
|
wreg(dev, REG_MODE, MODE_RESET);
|
||||||
|
while (rreg(dev, REG_MODE) & MODE_RESET) {};
|
||||||
|
|
||||||
|
/* initialize the device, start with writing the MAC address */
|
||||||
|
memset(hwaddr, MAC_SEED, ETHERNET_ADDR_LEN);
|
||||||
|
#if CPUID_LEN
|
||||||
|
cpuid_get(cpuid);
|
||||||
|
for (int i = 0; i < CPUID_LEN; i++) {
|
||||||
|
hwaddr[i % ETHERNET_ADDR_LEN] ^= cpuid[i];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
hwaddr[0] &= ~0x03; /* no group address and not globally unique */
|
||||||
|
wchunk(dev, REG_SHAR0, hwaddr, ETHERNET_ADDR_LEN);
|
||||||
|
|
||||||
|
/* configure all memory to be used by socket 0 */
|
||||||
|
wreg(dev, REG_RMSR, RMSR_8KB_TO_S0);
|
||||||
|
wreg(dev, REG_TMSR, TMSR_8KB_TO_S0);
|
||||||
|
|
||||||
|
/* configure interrupt pin to trigger on socket 0 events */
|
||||||
|
wreg(dev, REG_IMR, IMR_S0_INT);
|
||||||
|
|
||||||
|
/* next we configure socket 0 to work in MACRAW mode */
|
||||||
|
wreg(dev, S0_MR, MR_MACRAW);
|
||||||
|
wreg(dev, S0_CR, CR_OPEN);
|
||||||
|
|
||||||
|
/* start receiving packets */
|
||||||
|
wreg(dev, S0_CR, CR_RECV);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t tx_upload(w5100_t *dev, uint16_t start, void *data, size_t len)
|
||||||
|
{
|
||||||
|
if ((start + len) >= (S0_TX_BASE + S0_MEMSIZE)) {
|
||||||
|
size_t limit = ((S0_TX_BASE + S0_MEMSIZE) - start);
|
||||||
|
wchunk(dev, start, data, limit);
|
||||||
|
wchunk(dev, S0_TX_BASE, &((uint8_t *)data)[limit], len - limit);
|
||||||
|
return (S0_TX_BASE + limit);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wchunk(dev, start, data, len);
|
||||||
|
waddr(dev, S0_TX_WR0, S0_TX_WR1, start + len);
|
||||||
|
return (start + len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send(netdev2_t *netdev, const struct iovec *vector, int count)
|
||||||
|
{
|
||||||
|
w5100_t *dev = (w5100_t *)netdev;
|
||||||
|
int sum = 0;
|
||||||
|
|
||||||
|
uint16_t pos = raddr(dev, S0_TX_WR0, S0_TX_WR1);
|
||||||
|
|
||||||
|
/* the register is only set correctly after the first send pkt, so we need
|
||||||
|
* this fix here */
|
||||||
|
if (pos == 0) {
|
||||||
|
pos = S0_TX_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
pos = tx_upload(dev, pos, vector[i].iov_base, vector[i].iov_len);
|
||||||
|
sum += vector[i].iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
waddr(dev, S0_TX_WR0, S0_TX_WR1, pos);
|
||||||
|
|
||||||
|
/* trigger the sending process */
|
||||||
|
wreg(dev, S0_CR, CR_SEND_MAC);
|
||||||
|
while (!(rreg(dev, S0_IR) & IR_SEND_OK)) {};
|
||||||
|
wreg(dev, S0_IR, IR_SEND_OK);
|
||||||
|
|
||||||
|
DEBUG("[w5100] send: transferred %i byte (at 0x%04x)\n", sum, (int)pos);
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int recv(netdev2_t *netdev, char *buf, int len, void *info)
|
||||||
|
{
|
||||||
|
w5100_t *dev = (w5100_t *)netdev;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
uint16_t num = raddr(dev, S0_RX_RSR0, S0_RX_RSR1);
|
||||||
|
|
||||||
|
if (num > 0) {
|
||||||
|
/* find the size of the next packet in the RX buffer */
|
||||||
|
uint16_t rp = raddr(dev, S0_RX_RD0, S0_RX_RD1);
|
||||||
|
uint16_t psize = raddr(dev, (S0_RX_BASE + (rp & S0_MASK)),
|
||||||
|
(S0_RX_BASE + ((rp + 1) & S0_MASK)));
|
||||||
|
n = psize - 2;
|
||||||
|
|
||||||
|
DEBUG("[w5100] recv: got packet of %i byte (at 0x%04x)\n", n, (int)rp);
|
||||||
|
|
||||||
|
/* read the actual data into the given buffer if wanted */
|
||||||
|
if (buf != NULL) {
|
||||||
|
uint16_t pos = rp + 2;
|
||||||
|
len = (n <= len) ? n : len;
|
||||||
|
for (int i = 0; i < (int)len; i++) {
|
||||||
|
buf[i] = rreg(dev, (S0_RX_BASE + ((pos++) & S0_MASK)));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("[w5100] recv: read %i byte from device (at 0x%04x)\n",
|
||||||
|
n, (int)rp);
|
||||||
|
|
||||||
|
/* set the new read pointer address */
|
||||||
|
waddr(dev, S0_RX_RD0, S0_RX_RD1, rp += psize);
|
||||||
|
wreg(dev, S0_CR, CR_RECV);
|
||||||
|
|
||||||
|
/* if RX buffer now empty, clear RECV interrupt flag */
|
||||||
|
if ((num - psize) == 0) {
|
||||||
|
wreg(dev, S0_IR, IR_RECV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isr(netdev2_t *netdev)
|
||||||
|
{
|
||||||
|
w5100_t *dev = (w5100_t *)netdev;
|
||||||
|
|
||||||
|
/* we only react on RX events, and if we see one, we read from the RX buffer
|
||||||
|
* until it is empty */
|
||||||
|
while (rreg(dev, S0_IR) & IR_RECV) {
|
||||||
|
DEBUG("[w5100] netdev2 RX complete\n");
|
||||||
|
netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get(netdev2_t *netdev, netopt_t opt, void *value, size_t max_len)
|
||||||
|
{
|
||||||
|
w5100_t *dev = (w5100_t *)netdev;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
switch (opt) {
|
||||||
|
case NETOPT_ADDRESS:
|
||||||
|
assert(max_len >= ETHERNET_ADDR_LEN);
|
||||||
|
rchunk(dev, REG_SHAR0, value, ETHERNET_ADDR_LEN);
|
||||||
|
res = ETHERNET_ADDR_LEN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = netdev2_eth_get(netdev, opt, value, max_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const netdev2_driver_t netdev2_driver_w5100 = {
|
||||||
|
.send = send,
|
||||||
|
.recv = recv,
|
||||||
|
.init = init,
|
||||||
|
.isr = isr,
|
||||||
|
.get = get,
|
||||||
|
.set = netdev2_eth_set,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user