1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

enc28j60: improvements to fix #9043

This commit is contained in:
Gunar Schorcht 2018-05-04 14:55:36 +02:00
parent a0a31120b2
commit 738c1161c0
2 changed files with 52 additions and 7 deletions

View File

@ -70,10 +70,18 @@
* RX must start at buffer address 0x0000 (see errata sheet, section 5)
*/
#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_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)
{
@ -248,6 +256,28 @@ static int nd_send(netdev_t *netdev, const iolist_t *iolist)
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 */
cmd_w_addr(dev, ADDR_WRITE_PTR, BUF_TX_START);
/* 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);
/* trigger the send process */
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
netdev->stats.tx_bytes += c;
@ -269,23 +301,34 @@ static int nd_send(netdev_t *netdev, const iolist_t *iolist)
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)
{
enc28j60_t *dev = (enc28j60_t *)netdev;
uint8_t head[6];
size_t size;
uint16_t size;
uint16_t next;
(void)info;
mutex_lock(&dev->devlock);
/* 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 */
cmd_rbm(dev, head, 6);
/* TODO: care for endianess */
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) {
#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;
}
/* 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);
}
@ -348,7 +391,7 @@ static int nd_init(netdev_t *netdev)
/* configure the RX buffer */
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_READ, BUF_RX_START);
cmd_w_addr(dev, ADDR_RX_READ, NEXT_TO_ERXRDPT(BUF_RX_START));
/* configure the TX buffer */
cmd_w_addr(dev, ADDR_TX_START, BUF_TX_START);
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;
mutex_init(&dev->devlock);
dev->bank = 99; /* mark as invalid */
dev->tx_time = 0;
}

View File

@ -53,6 +53,7 @@ typedef struct {
gpio_t reset_pin; /**< pin connected to the RESET line */
mutex_t devlock; /**< lock the device on access */
int8_t bank; /**< remember the active register bank */
uint32_t tx_time; /**< last transmission time for timeout handling */
} enc28j60_t;
/**