diff options
| author | robert-hh <robert@hammelrath.com> | 2022-02-03 15:41:56 +0100 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2022-03-08 23:09:17 +1100 |
| commit | b0d460cd7deb6f1cc3393f56c378943aca8d954b (patch) | |
| tree | 2116405e8510eccbf72a1f8e231fb71c316fccc4 | |
| parent | 5ea85b7a852046783074be8a59534bd7f55d2553 (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.c | 25 |
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; } |
