summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrobert-hh <robert@hammelrath.com>2022-02-03 15:41:56 +0100
committerDamien George <damien@micropython.org>2022-03-08 23:09:17 +1100
commitb0d460cd7deb6f1cc3393f56c378943aca8d954b (patch)
tree2116405e8510eccbf72a1f8e231fb71c316fccc4
parent5ea85b7a852046783074be8a59534bd7f55d2553 (diff)
mimxrt/eth: Fix an Ethernet transmit error.
Sometimes frames could not be sent immediately because the controller was still busy with previous frames. Then, an error was returned to lwip. This fix adds a limited number of retries for this busy state, waiting 100µs before the next attempt. Typically the transmit succeeds now at the second attempt. Second change: Reset the controller for a clean state after soft reset.
-rw-r--r--ports/mimxrt/eth.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
index af0264d08..08e4dcc09 100644
--- a/ports/mimxrt/eth.c
+++ b/ports/mimxrt/eth.c
@@ -174,7 +174,7 @@ void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event,
}
} while (status != kStatus_ENET_RxFrameEmpty);
} else {
- ENET_ClearInterruptStatus(base, kENET_TxFrameInterrupt);
+ ENET_ClearInterruptStatus(base, ENET_TX_INTERRUPT | ENET_ERR_INTERRUPT);
}
}
@@ -279,6 +279,7 @@ void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Init failed."));
}
+ ENET_Reset(ENET);
ENET_GetDefaultConfig(&enet_config);
enet_config.miiSpeed = (enet_mii_speed_t)speed;
enet_config.miiDuplex = (enet_mii_duplex_t)duplex;
@@ -311,6 +312,22 @@ void eth_set_trace(eth_t *self, uint32_t value) {
/*******************************************************************************/
// ETH-LwIP bindings
+STATIC err_t eth_send_frame_blocking(ENET_Type *base, enet_handle_t *handle, uint8_t *buffer, int len) {
+ status_t status;
+ int i;
+ #define XMIT_LOOP 10
+
+ // Try a few times to send the frame
+ for (i = XMIT_LOOP; i > 0; i--) {
+ status = ENET_SendFrame(base, handle, buffer, len);
+ if (status != kStatus_ENET_TxFrameBusy) {
+ break;
+ }
+ ticks_delay_us64(100);
+ }
+ return status;
+}
+
STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
// This function should always be called from a context where PendSV-level IRQs are disabled
status_t status;
@@ -319,7 +336,7 @@ STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);
if (p->next == NULL) {
- status = ENET_SendFrame(ENET, &g_handle, p->payload, p->len);
+ status = eth_send_frame_blocking(ENET, &g_handle, p->payload, p->len);
} else {
// frame consists of several parts. Copy them together and send them
size_t length = 0;
@@ -330,8 +347,8 @@ STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
length += p->len;
p = p->next;
}
- status = ENET_SendFrame(ENET, &g_handle, tx_frame, length);
- }
+ status = eth_send_frame_blocking(ENET, &g_handle, tx_frame, length);
+ }
return status == kStatus_Success ? ERR_OK : ERR_BUF;
}