⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpc17_emac.c

📁 NXPl788上lwip的无操作系统移植,基于Embest开发板
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* use the new buffer for descrptor queueing. The original pbuf will
		   be de-allocated outsuide this driver. */
		p = np;
		dn = 1;
	}
#else
	if (notdmasafe)
		LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
			(notdmasafe == 0));
#endif

	/* Wait until enough descriptors are available for the transfer. */
	/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
	while (dn > lpc_tx_ready(netif));

	/* Get free TX buffer index */
	idx = LPC_EMAC->TxProduceIndex;

	/* Setup transfers */
	q = p;
	while (dn > 0) {
		dn--;

		lpc_enetdata->txb[idx] = q;

		/* Only save pointer to free on last descriptor */
		if (dn == 0) {
			/* Save size of packet and signal it's ready */
			lpc_enetdata->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT |
				EMAC_TCTRL_LAST;
		}
		else {
			/* Save size of packet, descriptor is not last */
			lpc_enetdata->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT;
		}

		LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
			("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
			" size = %d (index=%d)\n", q->payload, dn, q->len, idx));

		lpc_enetdata->ptxd[idx].packet = (u32_t) q->payload;

		/* Increment packet reference to prevent de-allocation only if buffers
		   are zero-copy - the TX cleanup task will de-allocate it once the
		   hardware is done with it. */
		if (!notdmasafe)
			pbuf_ref(q);
		q = q->next;

		idx++;
		if (idx >= LPC_NUM_BUFF_TXDESCS)
			idx = 0;
	}

	LPC_EMAC->TxProduceIndex = idx;

	LINK_STATS_INC(link.xmit);

	return ERR_OK;
}

#else /* Start of copied pbuf transmit driver */
/** \brief  Sets up the TX descriptor ring buffers.

    This function sets up the descriptor list used for transmit packets.

    \param [in]      lpc_enetdata_def  Pointer to driver data structure
 */
static err_t lpc_tx_setup(struct lpc_enetdata_def *lpc_enetdata)
{
	s32_t idx;

	/* Setup pointers to TX structures */
	LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetdata->ptxd[0];
	LPC_EMAC->TxStatus = (u32_t) &lpc_enetdata->ptxs[0];
	LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1;

	/* Build TX descriptors for local buffers */
	for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
		lpc_enetdata->ptxd[idx].packet = (u32_t) &lpc_enetdata->lpc_tx_buffs[idx][0];
		lpc_enetdata->ptxd[idx].control = 0;
		lpc_enetdata->ptxs[idx].statusinfo = 0xFFFFFFFF;
	}

	return ERR_OK;
}

 /** \brief  Polls if an available TX descriptor is ready. Can be used to
             determine if the low level transmit function will block.

    \param netif the lwip network interface structure for this lpc_enetif
    \return 0 if no descriptors are read, or >0
 */
s32_t lpc_tx_ready(struct netif *netif)
{
	s32_t fb;
	u32_t idx, cidx;

	cidx = LPC_EMAC->TxConsumeIndex;
	idx = LPC_EMAC->TxProduceIndex;

	/* Determine number of free buffers */
	if (idx == cidx)
		fb = LPC_NUM_BUFF_TXDESCS;
	else if (cidx > idx)
		fb = (LPC_NUM_BUFF_TXDESCS - 1) -
			((idx + LPC_NUM_BUFF_TXDESCS) - cidx);
	else
		fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx);

	return fb;
}

/** \brief  Low level output of a packet. Never call this from an
            interrupt context, as it may block until TX descriptors
			become available.

    \param netif the lwip network interface structure for this lpc_enetif
    \param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
    \return ERR_OK if the packet could be sent
           an err_t value if the packet couldn't be sent
 */
static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
{
	struct lpc_enetdata_def *lpc_enetdata = netif->state;
	struct pbuf *q;
	u8_t *dst;
	u32_t idx, sz = 0;
	err_t err = ERR_OK;

	/* Error handling for TX underruns. This should never happen unless
	   something is holding the bus or the clocks are going too slow. It
	   can probably be safely removed. */
 	if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
		LINK_STATS_INC(link.err);
		LINK_STATS_INC(link.drop);

		/* Reset the TX side */
		LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
		LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;

		/* Start TX side again */
		lpc_tx_setup(lpc_enetdata);
	}

	/* Wait for a single buffer to become available */
	while (lpc_tx_ready(netif) == 0);

	/* Get free TX buffer index */
	idx = LPC_EMAC->TxProduceIndex;

	/* Copy pbuf to ethernet send buffer */
	dst = (u8_t *) lpc_enetdata->ptxd[idx].packet;
 	for(q = p; q != NULL; q = q->next) {
		/* Copy the buffer to the descriptor's buffer */
	  MEMCPY(dst, (u8_t *) q->payload, q->len);
	  dst += q->len;
	  sz += q->len;
	}

	/* Save size of packet and signal it's ready */
	lpc_enetdata->ptxd[idx].control = (sz - 1) | EMAC_TCTRL_INT |
		EMAC_TCTRL_LAST;

	/*SGet next index for transmit descriptor */
	idx++;
	if (idx >= LPC_NUM_BUFF_TXDESCS)
		idx = 0;
	LPC_EMAC->TxProduceIndex = idx;

	LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
		("lpc_low_level_output: pbuf packet(%p) sent, chains = %d,"
		" size = %d\n", p, (u32_t) pbuf_clen(p), p->tot_len));

	LINK_STATS_INC(link.xmit);

	return ERR_OK;
}
#endif  /* End of TX copied or zero-copy driver section */

/** \brief  LPC EMAC interrupt handler.

    This function handles the transmit, receive, and error interrupt of
	the LPC177x_8x. This is meant to be used when NO_SYS=0. It is not
	implemented here and is just a spotholder for RTOS support.
 */
void ENET_IRQHandler(void)
{
	;
}

/** \brief  Low level init of the MAC and PHY.

    \param [in]      netif  Pointer to LWIP netif structure
 */
static err_t low_level_init(struct netif *netif)
{
	struct lpc_enetdata_def *lpc_enetdata = netif->state;
	err_t err = ERR_OK;

	/* Enable MII clocking */
	CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCENET, ENABLE);

	/* Reset all MAC logic */
	LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX |
		EMAC_MAC1_RES_RX | EMAC_MAC1_RES_MCS_RX |
		EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;
	LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES;
	msDelay(10);

	/* Initial MAC initialization */
	LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
	LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | EMAC_MAC2_VLAN_PAD_EN;
	LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;

	/* Set RMII management clock rate to lowest speed */
	LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(8) | EMAC_MCFG_RES_MII;
	LPC_EMAC->MCFG &= ~EMAC_MCFG_RES_MII;

	/* Maximum number of retries, 0x37 collision window, gap */
	LPC_EMAC->CLRT = EMAC_CLRT_DEF;
	LPC_EMAC->IPGR = EMAC_IPGR_P1_DEF | EMAC_IPGR_P2_DEF;

#if LPC_EMAC_RMII
	/* RMII setup */
	LPC_EMAC->Command = EMAC_CR_PASS_RUNT_FRM | EMAC_CR_RMII;
#else
	/* MII setup */
	LPC_EMAC->CR = EMAC_CR_PASS_RUNT_FRM;
#endif

	/* Initialize the PHY and reset */
	err = lpc_phy_init(netif);
	if (err != ERR_OK)
 		return err;

	/* Save station address */
	LPC_EMAC->SA2 = (u32_t) netif->hwaddr[0] |
		(((u32_t) netif->hwaddr[1]) << 8);
	LPC_EMAC->SA1 = (u32_t) netif->hwaddr[2] |
		(((u32_t) netif->hwaddr[3]) << 8);
	LPC_EMAC->SA0 = (u32_t) netif->hwaddr[4] |
		(((u32_t) netif->hwaddr[5]) << 8);

	/* Setup transmit and receive descriptors */
	if (lpc_tx_setup(lpc_enetdata) != ERR_OK)
		return ERR_BUF;
	if (lpc_rx_setup(lpc_enetdata) != ERR_OK)
		return ERR_BUF;

	/* Enable packet reception */
#if IP_SOF_BROADCAST_RECV
	LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_MCAST_EN;
#else
	LPC_EMAC->RxFilterCtrl = EMAC_RFC_PERFECT_EN;
#endif

	/* Clear and enable rx/tx interrupts */
	LPC_EMAC->IntClear = 0xFFFF;
	LPC_EMAC->IntEnable =
#if NO_SYS
		0;
#else
		EMAC_INT_TX_DONE | EMAC_INT_RX_DONE |
		EMAC_INT_RX_OVERRUN | EMAC_INT_TX_UNDERRUN;
#endif

	/* Not all interrupts are used, only descriptor completion
	   and some error interrupts are needed. RX status errors
	   are handled at packet reception time. */
	LPC_EMAC->Command |= EMAC_CR_RX_EN | EMAC_CR_TX_EN;
	LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;

	return err;
}

/**
 * This function provides a method for the PHY to setup the EMAC
 * for the PHY negotiated duplex mode.
 *
 * @param[in] full_duplex 0 = half duplex, 1 = full duplex
 */
void lpc_emac_set_duplex(int full_duplex)
{
	if (full_duplex) {
		LPC_EMAC->MAC2    |= EMAC_MAC2_FULL_DUP;
		LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
		LPC_EMAC->IPGT     = EMAC_IPGT_FULL_DUP;
	} else {
		LPC_EMAC->MAC2    &= ~EMAC_MAC2_FULL_DUP;
		LPC_EMAC->Command &= ~EMAC_CR_FULL_DUP;
		LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
	}
}

/**
 * This function provides a method for the PHY to setup the EMAC
 * for the PHY negotiated bit rate.
 *
 * @param[in] mbs_100     0 = 10mbs mode, 1 = 100mbs mode
 */
void lpc_emac_set_speed(int mbs_100)
{
	if (mbs_100)
		LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
	else
		LPC_EMAC->SUPP = 0;
}

/**
 * Should be called at the beginning of the program to set up the
 * network interface.
 *
 * This function should be passed as a parameter to netif_add().
 *
 * @param[in] netif the lwip network interface structure for this lpc_enetif
 * @return ERR_OK if the loopif is initialized
 *         ERR_MEM if private data couldn't be allocated
 *         any other err_t on error
 */
err_t lpc_enetif_init(struct netif *netif)
{
	err_t err;

	LWIP_ASSERT("netif != NULL", (netif != NULL));
    
	lpc_enetdata.netif = netif;

	/* set MAC hardware address */
	board_get_macaddr(netif->hwaddr);
	netif->hwaddr_len = ETHARP_HWADDR_LEN;

 	/* maximum transfer unit */
	netif->mtu = 1500;

	/* device capabilities */
	netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_UP |
		NETIF_FLAG_ETHERNET;

	/* Initialize the hardware */
	netif->state = &lpc_enetdata;
	err = low_level_init(netif);
	if (err != ERR_OK)
		return err;

#if LWIP_NETIF_HOSTNAME
	/* Initialize interface hostname */
	netif->hostname = "lwiplpc";
#endif /* LWIP_NETIF_HOSTNAME */

	netif->name[0] = 'e';
	netif->name[1] = 'n';

	netif->output = etharp_output;
	netif->linkoutput = lpc_low_level_output;

	return ERR_OK;
}

/**
 * @}
 */

/* --------------------------------- End Of File ------------------------------ */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -