enc28j60: improvements to fix #9043
This commit is contained in:
parent
a0a31120b2
commit
738c1161c0
@ -70,10 +70,18 @@
|
|||||||
* RX must start at buffer address 0x0000 (see errata sheet, section 5)
|
* RX must start at buffer address 0x0000 (see errata sheet, section 5)
|
||||||
*/
|
*/
|
||||||
#define BUF_TX_START ((BUFFER_SIZE / 4) * 3)
|
#define BUF_TX_START ((BUFFER_SIZE / 4) * 3)
|
||||||
#define BUF_TX_END (BUFFER_SIZE - 2)
|
#define BUF_TX_END (BUFFER_SIZE - 1)
|
||||||
#define BUF_RX_START (0)
|
#define BUF_RX_START (0)
|
||||||
#define BUF_RX_END (BUF_TX_START - 2)
|
#define BUF_RX_END (BUF_TX_START - 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum transmission time
|
||||||
|
*
|
||||||
|
* The time in us that is required to send an Ethernet frame of maximum length
|
||||||
|
* (Preamle + SFD + 1518 byte) at 10 Mbps in full duplex mode with a guard
|
||||||
|
* period of 9,6 us. This time is used as time out for send operations.
|
||||||
|
*/
|
||||||
|
#define MAX_TX_TIME (1230U)
|
||||||
|
|
||||||
static void switch_bank(enc28j60_t *dev, int8_t bank)
|
static void switch_bank(enc28j60_t *dev, int8_t bank)
|
||||||
{
|
{
|
||||||
@ -248,6 +256,28 @@ static int nd_send(netdev_t *netdev, const iolist_t *iolist)
|
|||||||
|
|
||||||
mutex_lock(&dev->devlock);
|
mutex_lock(&dev->devlock);
|
||||||
|
|
||||||
|
if (cmd_rcr(dev, REG_ECON1, -1) & ECON1_TXRTS) {
|
||||||
|
/* there is already a transmission in progress */
|
||||||
|
if (xtimer_now_usec() - dev->tx_time > MAX_TX_TIME * 2) {
|
||||||
|
/*
|
||||||
|
* if transmission time exceeds the double of maximum transmission
|
||||||
|
* time, we suppose that TX logic hangs and has to be reset
|
||||||
|
*/
|
||||||
|
cmd_bfs(dev, REG_ECON1, -1, ECON1_TXRST);
|
||||||
|
cmd_bfc(dev, REG_ECON1, -1, ECON1_TXRST);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* otherwise we suppose that the transmission is still in progress
|
||||||
|
* and return EBUSY
|
||||||
|
*/
|
||||||
|
mutex_unlock(&dev->devlock);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set TX start pointer */
|
||||||
|
cmd_w_addr(dev, ADDR_TX_START, BUF_TX_START);
|
||||||
/* set write pointer */
|
/* set write pointer */
|
||||||
cmd_w_addr(dev, ADDR_WRITE_PTR, BUF_TX_START);
|
cmd_w_addr(dev, ADDR_WRITE_PTR, BUF_TX_START);
|
||||||
/* write control byte and the actual data into the buffer */
|
/* write control byte and the actual data into the buffer */
|
||||||
@ -260,6 +290,8 @@ static int nd_send(netdev_t *netdev, const iolist_t *iolist)
|
|||||||
cmd_w_addr(dev, ADDR_TX_END, cmd_r_addr(dev, ADDR_WRITE_PTR) - 1);
|
cmd_w_addr(dev, ADDR_TX_END, cmd_r_addr(dev, ADDR_WRITE_PTR) - 1);
|
||||||
/* trigger the send process */
|
/* trigger the send process */
|
||||||
cmd_bfs(dev, REG_ECON1, -1, ECON1_TXRTS);
|
cmd_bfs(dev, REG_ECON1, -1, ECON1_TXRTS);
|
||||||
|
/* set last transmission time for timeout handling */
|
||||||
|
dev->tx_time = xtimer_now_usec();
|
||||||
|
|
||||||
#ifdef MODULE_NETSTATS_L2
|
#ifdef MODULE_NETSTATS_L2
|
||||||
netdev->stats.tx_bytes += c;
|
netdev->stats.tx_bytes += c;
|
||||||
@ -269,23 +301,34 @@ static int nd_send(netdev_t *netdev, const iolist_t *iolist)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Section 14 of errata sheet: Even values in ERXRDPT may corrupt receive
|
||||||
|
* buffer as well as the next packet pointer. ERXRDPT need to be set always
|
||||||
|
* at odd addresses. Following macros determine odd ERXRDPT from next packet
|
||||||
|
* pointer and vise versa. Next packet pointer is always at even address
|
||||||
|
* because of hardware padding.
|
||||||
|
*/
|
||||||
|
#define NEXT_TO_ERXRDPT(n) ((n == BUF_RX_START || n - 1 > BUF_RX_END) ? BUF_RX_END : n - 1)
|
||||||
|
#define ERXRDPT_TO_NEXT(e) ((e >= BUF_RX_END) ? BUF_RX_START : e + 1)
|
||||||
|
|
||||||
static int nd_recv(netdev_t *netdev, void *buf, size_t max_len, void *info)
|
static int nd_recv(netdev_t *netdev, void *buf, size_t max_len, void *info)
|
||||||
{
|
{
|
||||||
enc28j60_t *dev = (enc28j60_t *)netdev;
|
enc28j60_t *dev = (enc28j60_t *)netdev;
|
||||||
uint8_t head[6];
|
uint8_t head[6];
|
||||||
size_t size;
|
uint16_t size;
|
||||||
uint16_t next;
|
uint16_t next;
|
||||||
|
|
||||||
(void)info;
|
(void)info;
|
||||||
mutex_lock(&dev->devlock);
|
mutex_lock(&dev->devlock);
|
||||||
|
|
||||||
/* set read pointer to RX read address */
|
/* set read pointer to RX read address */
|
||||||
cmd_w_addr(dev, ADDR_READ_PTR, cmd_r_addr(dev, ADDR_RX_READ));
|
uint16_t rx_rd_ptr = cmd_r_addr(dev, ADDR_RX_READ);
|
||||||
|
cmd_w_addr(dev, ADDR_READ_PTR, ERXRDPT_TO_NEXT(rx_rd_ptr));
|
||||||
/* read packet header */
|
/* read packet header */
|
||||||
cmd_rbm(dev, head, 6);
|
cmd_rbm(dev, head, 6);
|
||||||
/* TODO: care for endianess */
|
/* TODO: care for endianess */
|
||||||
next = (uint16_t)((head[1] << 8) | head[0]);
|
next = (uint16_t)((head[1] << 8) | head[0]);
|
||||||
size = (size_t)((head[3] << 8) | head[2]) - 4; /* discard CRC */
|
size = (uint16_t)((head[3] << 8) | head[2]) - 4; /* discard CRC */
|
||||||
|
|
||||||
if (buf != NULL) {
|
if (buf != NULL) {
|
||||||
#ifdef MODULE_NETSTATS_L2
|
#ifdef MODULE_NETSTATS_L2
|
||||||
@ -300,7 +343,7 @@ static int nd_recv(netdev_t *netdev, void *buf, size_t max_len, void *info)
|
|||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
/* release memory */
|
/* release memory */
|
||||||
cmd_w_addr(dev, ADDR_RX_READ, next);
|
cmd_w_addr(dev, ADDR_RX_READ, NEXT_TO_ERXRDPT(next));
|
||||||
cmd_bfs(dev, REG_ECON2, -1, ECON2_PKTDEC);
|
cmd_bfs(dev, REG_ECON2, -1, ECON2_PKTDEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +391,7 @@ static int nd_init(netdev_t *netdev)
|
|||||||
/* configure the RX buffer */
|
/* configure the RX buffer */
|
||||||
cmd_w_addr(dev, ADDR_RX_START, BUF_RX_START);
|
cmd_w_addr(dev, ADDR_RX_START, BUF_RX_START);
|
||||||
cmd_w_addr(dev, ADDR_RX_END, BUF_RX_END);
|
cmd_w_addr(dev, ADDR_RX_END, BUF_RX_END);
|
||||||
cmd_w_addr(dev, ADDR_RX_READ, BUF_RX_START);
|
cmd_w_addr(dev, ADDR_RX_READ, NEXT_TO_ERXRDPT(BUF_RX_START));
|
||||||
/* configure the TX buffer */
|
/* configure the TX buffer */
|
||||||
cmd_w_addr(dev, ADDR_TX_START, BUF_TX_START);
|
cmd_w_addr(dev, ADDR_TX_START, BUF_TX_START);
|
||||||
cmd_w_addr(dev, ADDR_TX_END, BUF_TX_END);
|
cmd_w_addr(dev, ADDR_TX_END, BUF_TX_END);
|
||||||
@ -499,4 +542,5 @@ void enc28j60_setup(enc28j60_t *dev, const enc28j60_params_t *params)
|
|||||||
dev->reset_pin = params->reset_pin;
|
dev->reset_pin = params->reset_pin;
|
||||||
mutex_init(&dev->devlock);
|
mutex_init(&dev->devlock);
|
||||||
dev->bank = 99; /* mark as invalid */
|
dev->bank = 99; /* mark as invalid */
|
||||||
|
dev->tx_time = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ typedef struct {
|
|||||||
gpio_t reset_pin; /**< pin connected to the RESET line */
|
gpio_t reset_pin; /**< pin connected to the RESET line */
|
||||||
mutex_t devlock; /**< lock the device on access */
|
mutex_t devlock; /**< lock the device on access */
|
||||||
int8_t bank; /**< remember the active register bank */
|
int8_t bank; /**< remember the active register bank */
|
||||||
|
uint32_t tx_time; /**< last transmission time for timeout handling */
|
||||||
} enc28j60_t;
|
} enc28j60_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user