基于米联客MA703FA开发板的MicroBlaze LWIP千兆以太网例程

您所在的位置:网站首页 联客app 基于米联客MA703FA开发板的MicroBlaze LWIP千兆以太网例程

基于米联客MA703FA开发板的MicroBlaze LWIP千兆以太网例程

2024-01-15 14:49| 来源: 网络整理| 查看: 265

本文转载自:巨大八爪鱼的博客

Xilinx FPGA MicroBlaze使用AXI 1G/2.5G Ethernet Subsystem(= Tri Mode Ethernet MAC + AXI Ethernet Buffer)以太网IP核驱动RTL8211FD千兆网口,并使用lwip2.1.2协议栈建立http服务器,支持IPv6。

Xilinx Vivado 2020.1工程下载地址:https://pan.baidu.com/s/1QO49qAloPJBvY6XiKGqdxQ(提取码:a4ns)

【开发板】

开发板型号:米联客MA703FA FPGA型号:XC7A35TFGG484-2 晶振频率:50MHz DDR3内存型号:MT41K128M16(容量为256MB) PHY芯片型号:RTL8211FD(RGMII接口,千兆以太网PHY芯片)

XC7A35T只有20800个LUT,资源非常紧张,建议换用XC7A50T或者XC7A100T。

【网口LED灯配置】

插上网线后,绿灯常亮。拔掉网线后,绿灯熄灭。 链路支持EEE节能:有数据传输,黄灯闪烁,否则熄灭 链路不支持EEE节能:有数据传输,黄灯闪烁,否则常亮

具体配置方法见ethernetif.c的low_level_init函数。(https://blog.csdn.net/ZLK1214/article/details/115842136)

【程序功能展示】

1. ping通开发板的NetBIOS设备名,IPv4地址和IPv6地址:

2. 访问开发板上的http服务器(设备名方式、IPv6方式):

3. 在路由器管理页面看到开发板的信息:

4. PHY芯片自动协商网口速率和双工模式,程序带网口热插拔检测:

5. DHCP获取IPv4地址,SLAAC获取IPv6地址:

【开发环境】

Verilog开发环境:Xilinx Vivado 2020.1

从中可以看到,LUT资源占了将近90%。

C语言开发环境:Xilinx Vitis 2020.1

【Block Design连线】

Vitis sleep()函数所用的定时器的设置方法:

【主要程序代码】

hello_world.c:

/****************************************************************************** * * Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/

/* * helloworld.c: simple test application * * This application configures UART 16550 to baud rate 9600. * PS7 UART (Zynq) is not initialized by this application, since * bootrom/bsp configures it to baud rate 115200 * * ------------------------------------------------ * | UART TYPE BAUD RATE | * ------------------------------------------------ * uartns550 9600 * uartlite Configurable only in HW design * ps7_uart 115200 (configured by bootrom/bsp) */

#include #include #include #include #include #include #include #include #include #include #include #include #include #include "platform.h"

XIntc xintc; XTmrCtr xtmrctr; static struct netif netif_rtl8211fd; static uint32_t sys_ticks;

uint32_t sys_now(void) { return sys_ticks; }

static void sys_now_handler(void *CallBackRef, u8 TmrCtrNumber) { if (TmrCtrNumber == 1) sys_ticks++; }

void sys_now_init(void) { int ret;

#ifndef XSLEEP_TIMER_IS_AXI_TIMER // 请在platform工程的platform.spr里面, 将sleep_timer设为axi_timer_0 // 此定时器的Timer 1用于sleep()函数, Timer 2用于sys_now()函数 #error "sleep() function cannot work!" #endif

// 初始化中断控制器 ret = XIntc_Initialize(&xintc, XPAR_INTC_0_DEVICE_ID); LWIP_ASSERT("Intc initialized", ret == XST_SUCCESS); ret = XIntc_Start(&xintc, XIN_REAL_MODE); LWIP_ASSERT("Intc started", ret == XST_SUCCESS);

Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XIntc_InterruptHandler, &xintc); Xil_ExceptionEnable();

// 初始化定时器 ret = XTmrCtr_Initialize(&xtmrctr, XPAR_TMRCTR_0_DEVICE_ID); LWIP_ASSERT("Timer initialized", ret == XST_SUCCESS); ret = XTmrCtr_SelfTest(&xtmrctr, 1); LWIP_ASSERT("Timer self test passed", ret == XST_SUCCESS);

// 启动定时器 // TIMING_INTERVAL = (TLRx + 2) * AXI_CLOCK_PERIOD XTmrCtr_SetOptions(&xtmrctr, 1, XTC_AUTO_RELOAD_OPTION | XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION); XTmrCtr_SetResetValue(&xtmrctr, 1, XPAR_TMRCTR_0_CLOCK_FREQ_HZ / 1000 - 2); // 计时频率为1ms XTmrCtr_SetHandler(&xtmrctr, sys_now_handler, NULL); XTmrCtr_Start(&xtmrctr, 1);

// 开启定时器中断 ret = XIntc_Connect(&xintc, XPAR_INTC_0_TMRCTR_0_VEC_ID, (XInterruptHandler)XTmrCtr_InterruptHandler, &xtmrctr); LWIP_ASSERT("Timer interrupt connected", ret == XST_SUCCESS); XIntc_Enable(&xintc, XPAR_INTC_0_TMRCTR_0_VEC_ID); }

static void display_ip(void) { const ip_addr_t *addr; static uint8_t ip_displayed = 0; static uint8_t ip6_displayed = 0; int i, ip_present; int dns = 0;

if (netif_dhcp_data(&netif_rtl8211fd) == NULL) ip_present = 1; // 使用静态IP地址 else if (dhcp_supplied_address(&netif_rtl8211fd)) ip_present = 2; // 使用DHCP获得IP地址, 且已成功获取到IP地址 else ip_present = 0; // 使用DHCP获得IP地址, 且还没有获取到IP地址

// 显示IPv4地址 if (ip_present) { if (ip_displayed == 0) { ip_displayed = 1;

if (ip_present == 2) printf("DHCP supplied address!\n"); printf("IP address: %s\n", ipaddr_ntoa(&netif_rtl8211fd.ip_addr)); printf("Subnet mask: %s\n", ipaddr_ntoa(&netif_rtl8211fd.netmask)); printf("Default gateway: %s\n", ipaddr_ntoa(&netif_rtl8211fd.gw)); dns = 1; } } else ip_displayed = 0;

// 显示IPv6地址 for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) // 0号地址是本地链路地址, 不需要显示 { if (ip6_addr_isvalid(netif_ip6_addr_state(&netif_rtl8211fd, i))) { if ((ip6_displayed & _BV(i)) == 0) { ip6_displayed |= _BV(i); printf("IPv6 address %d: %s\n", i, ipaddr_ntoa(netif_ip_addr6(&netif_rtl8211fd, i))); dns = 1; } } else ip6_displayed &= ~_BV(i); }

// 显示DNS服务器地址 // 在lwip中, IPv4 DHCP和IPv6 SLAAC获取到的DNS地址会互相覆盖 if (dns) { addr = dns_getserver(0); if (ip_addr_isany(addr)) return; printf("DNS Server: %s", ipaddr_ntoa(addr));

addr = dns_getserver(1); if (!ip_addr_isany(addr)) printf(" %s", ipaddr_ntoa(addr));

printf("\n"); } }

static void net_config(int use_dhcp) { ip4_addr_t ipaddr, netmask, gw; struct netif *netif;

if (use_dhcp) netif_add_noaddr(&netif_rtl8211fd, NULL, ethernetif_init, netif_input); else { IP4_ADDR(&ipaddr, 192, 168, 0, 19); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 0, 1); netif_add(&netif_rtl8211fd, &ipaddr, &netmask, &gw, NULL, ethernetif_init, netif_input); } netif_set_default(&netif_rtl8211fd); netif_set_up(&netif_rtl8211fd);

if (use_dhcp) dhcp_start(&netif_rtl8211fd);

netif_create_ip6_linklocal_address(&netif_rtl8211fd, 1); printf("IPv6 link-local address: %s\n", ipaddr_ntoa(netif_ip_addr6(&netif_rtl8211fd, 0))); netif_set_ip6_autoconfig_enabled((netif = &netif_rtl8211fd), 1); }

int main() { char ch;

init_platform();

printf("Hello World\n"); printf("Successfully ran Hello World application\n"); sys_now_init();

lwip_init(); net_config(1);

httpd_init(); netbiosns_init(); netbiosns_set_name("XC7A35TFGG484-2");

while (1) { ethernetif_check_link(&netif_rtl8211fd); display_ip();

ethernetif_input(&netif_rtl8211fd); sys_check_timeouts();

if (!XUartLite_IsReceiveEmpty(XPAR_UARTLITE_0_BASEADDR)) { ch = getchar(); if (ch == 't') printf("sys_now()=%lu\n", sys_now()); } }

cleanup_platform(); return 0; }

ethernetif.c(网口驱动): 备注:官网lwip2.1版本的压缩包(lwip-2.1.0.zip)中的src/netif文件夹下没有ethernetif.c了,那个文件是被移动到contrib-2.1.0.zip的examples/ethernetif文件夹下去了。

/** * @file * Ethernet Interface Skeleton * */

/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */

/* * This file is a skeleton for developing Ethernet network interface * drivers for lwIP. Add code to the low_level functions and do a * search-and-replace for the word "ethernetif" to replace it with * something that better describes your network interface. */

#include "lwip/opt.h"

#if 1 /* don't build, this is only a skeleton, see previous comment */

#include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/ethip6.h" #include "lwip/etharp.h" #include "netif/ppp/pppoe.h"

#include #include #include

/* Define those to better describe your network interface. */ #define IFNAME0 'e' #define IFNAME1 'n'

/** * Helper struct to hold private data used to operate your ethernet interface. * Keeping the ethernet address of the MAC in this struct is not necessary * as it is already kept in the struct netif. * But this is only an example, anyway... */ struct ethernetif { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */ XAxiDma_Config *xaxidma_cfg; XAxiEthernet_Config *xaxieth_cfg; XAxiDma_BdRing *rxring; XAxiDma_BdRing *txring; int rx_i; int tx_i; };

/* Forward declarations. */ //static void ethernetif_input(struct netif *netif);

XAxiDma xaxidma; XAxiEthernet xaxieth;

// 收发描述符和缓冲区 #define RX_NUM 10 #define TX_NUM 10 static __attribute__((aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT))) uint8_t dma_bdring_rx[RX_NUM][XAXIDMA_BD_MINIMUM_ALIGNMENT]; static __attribute__((aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT))) uint8_t dma_bdring_tx[TX_NUM][XAXIDMA_BD_MINIMUM_ALIGNMENT]; static __attribute__((aligned(4))) uint8_t dma_buffer_rx[RX_NUM][1600]; static __attribute__((aligned(4))) uint8_t dma_buffer_tx[TX_NUM][1600];

// 网口LED灯的序号 #define GREEN_LED 2 // 绿灯是LED2 #define YELLOW_LED 1 // 黄灯是LED1

/** * In this function, the hardware should be initialized. * Called from ethernetif_init(). * * @param netif the already initialized lwip network interface structure * for this ethernetif */ static void low_level_init(struct netif *netif) { struct ethernetif *ethernetif = netif->state; int i, ret; uint16_t temp; XAxiDma_Bd *bd, *p;

/* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN;

/* set MAC hardware address */ // 设置MAC地址 netif->hwaddr[0] = 0x00; netif->hwaddr[1] = 0x0a; netif->hwaddr[2] = 0x35; netif->hwaddr[3] = 0x00; netif->hwaddr[4] = 0x01; netif->hwaddr[5] = 0x02; printf("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]);

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

/* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP/* | NETIF_FLAG_LINK_UP*/; // 初始状态下认为网线还没有插 netif->flags |= NETIF_FLAG_MLD6; // 启用IPv6多播

#if LWIP_IPV6 && LWIP_IPV6_MLD /* * For hardware/netifs that implement MAC filtering. * All-nodes link-local is handled by default, so we must let the hardware know * to allow multicast packets in. * Should set mld_mac_filter previously. */ if (netif->mld_mac_filter != NULL) { ip6_addr_t ip6_allnodes_ll; ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); } #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */

/* Do whatever else is needed to initialize interface. */ // 初始化DMA ethernetif->xaxidma_cfg = XAxiDma_LookupConfig(XPAR_AXIDMA_0_DEVICE_ID); XAxiDma_CfgInitialize(&xaxidma, ethernetif->xaxidma_cfg); ret = XAxiDma_Selftest(&xaxidma); LWIP_ASSERT("DMA self test passed", ret == XST_SUCCESS);

if (!XAxiDma_HasSg(&xaxidma)) { printf("XPAR_AXIDMA_0_INCLUDE_SG=%d\n", XPAR_AXIDMA_0_INCLUDE_SG); printf("Please recreate and build Vitis platform project!\n"); LWIP_ASSERT("DMA has SG", 0); }

// 初始化ETH ethernetif->xaxieth_cfg = XAxiEthernet_LookupConfig(XPAR_AXIETHERNET_0_DEVICE_ID); XAxiEthernet_CfgInitialize(&xaxieth, ethernetif->xaxieth_cfg, ethernetif->xaxieth_cfg->BaseAddress); XAxiEthernet_SetMacAddress(&xaxieth, netif->hwaddr); // 请注意: 必须先初始化DMA, 后初始化ETH, 顺序不能反 // 这是因为DMA在复位的时候, ETH会跟着复位

// 启用IPv4和IPv6多播 XAxiEthernet_SetOptions(&xaxieth, XAE_MULTICAST_OPTION); LWIP_ASSERT("NumTableEntries >= 2", ethernetif->xaxieth_cfg->NumTableEntries >= 2); // IPv4多播MAC地址: 01:00:5E:*:*:* XAxiEthernet_MulticastAdd(&xaxieth, "\x01\x00\x5e\x00\x00\x00", 0); XAxiEthernet_WriteReg(ethernetif->xaxieth_cfg->BaseAddress, 0x750, 0xffffff); XAxiEthernet_WriteReg(ethernetif->xaxieth_cfg->BaseAddress, 0x754, 0); // IPv6多播MAC地址: 33:33:*:*:*:* XAxiEthernet_MulticastAdd(&xaxieth, "\x33\x33\x00\x00\x00\x00", 1); XAxiEthernet_WriteReg(ethernetif->xaxieth_cfg->BaseAddress, 0x750, 0xffff); XAxiEthernet_WriteReg(ethernetif->xaxieth_cfg->BaseAddress, 0x754, 0);

// 配置网口LED灯 XAxiEthernet_PhyWrite(&xaxieth, PHY_ADDR, 31, 0xd04); temp = 0x0b txring = XAxiDma_GetTxRing(&xaxidma); ret = XAxiDma_BdRingCreate(ethernetif->txring, (uintptr_t)dma_bdring_tx, (uintptr_t)dma_bdring_tx, XAXIDMA_BD_MINIMUM_ALIGNMENT, TX_NUM); LWIP_ASSERT("DMA txring created", ret == XST_SUCCESS); ret = XAxiDma_BdRingStart(ethernetif->txring); LWIP_ASSERT("DMA txring started", ret == XST_SUCCESS);

// 配置DMA接收描述符 ethernetif->rx_i = 0; ethernetif->rxring = XAxiDma_GetRxRing(&xaxidma); ret = XAxiDma_BdRingCreate(ethernetif->rxring, (uintptr_t)dma_bdring_rx, (uintptr_t)dma_bdring_rx, XAXIDMA_BD_MINIMUM_ALIGNMENT, RX_NUM); LWIP_ASSERT("DMA rxring created", ret == XST_SUCCESS); ret = XAxiDma_BdRingStart(ethernetif->rxring); LWIP_ASSERT("DMA rxring started", ret == XST_SUCCESS);

// 启用所有的接收描述符 ret = XAxiDma_BdRingAlloc(ethernetif->rxring, RX_NUM, &bd); LWIP_ASSERT("DMA rxring allocated all", ret == XST_SUCCESS); p = bd; for (i = 0; i < RX_NUM; i++) { XAxiDma_BdSetBufAddr(p, (uintptr_t)dma_buffer_rx[i]); XAxiDma_BdSetLength(p, sizeof(dma_buffer_rx[i]), ethernetif->rxring->MaxTransferLen); XAxiDma_BdSetCtrl(bd, 0); XAxiDma_BdSetId(p, i); p = (XAxiDma_Bd *)XAxiDma_BdRingNext(ethernetif->rxring, p); } ret = XAxiDma_BdRingToHw(ethernetif->rxring, RX_NUM, bd); LWIP_ASSERT("DMA rxring brought all", ret == XST_SUCCESS);

printf("DMA Rx descriptor: %p\n", dma_bdring_rx); printf("DMA Tx descriptor: %p\n", dma_bdring_tx); printf("DMA Rx buffer: %p\n", dma_buffer_rx); printf("DMA Tx buffer: %p\n", dma_buffer_tx); }

/** * This function should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * @param netif the lwip network interface structure for this ethernetif * @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 * * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to * strange results. You might consider waiting for space in the DMA queue * to become available since the stack doesn't retry to send a packet * dropped because of memory failure (except for the TCP timers). */

static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct ethernetif *ethernetif = netif->state; struct pbuf *q; int ret; uint8_t *data = dma_buffer_tx[ethernetif->tx_i]; XAxiDma_Bd *bd = NULL;

//initiate transfer(); LWIP_ASSERT("tx packet too big", p->tot_len txring, XAXIDMA_ALL_BDS, &bd); if (ret > 0) { //printf("%d packet(s) have been sent!\n", ret); ret = XAxiDma_BdRingFree(ethernetif->txring, ret, bd); LWIP_ASSERT("DMA txring freed some", ret == XST_SUCCESS); } } while (XAxiDma_BdRingGetFreeCnt(ethernetif->txring) == 0);

// 分配一个新描述符 ret = XAxiDma_BdRingAlloc(ethernetif->txring, 1, &bd); LWIP_ASSERT("DMA txring allocated one", ret == XST_SUCCESS); }

#if ETH_PAD_SIZE pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */ #endif

for (q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ //send data from(q->payload, q->len); memcpy(data, q->payload, q->len); data += q->len; }

//signal that packet should be sent(); if (bd != NULL) { printf("[Send] len=%d, id=%d\n", p->tot_len, ethernetif->tx_i); XAxiDma_BdSetBufAddr(bd, (uintptr_t)dma_buffer_tx[ethernetif->tx_i]); XAxiDma_BdSetLength(bd, p->tot_len, ethernetif->txring->MaxTransferLen); XAxiDma_BdSetCtrl(bd, XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); XAxiDma_BdSetId(bd, ethernetif->tx_i); ret = XAxiDma_BdRingToHw(ethernetif->txring, 1, bd); LWIP_ASSERT("DMA txring brought one", ret == XST_SUCCESS); ethernetif->tx_i = (ethernetif->tx_i + 1) % TX_NUM; } else printf("[Send] len=%d (failed)\n", p->tot_len);

MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); if (((u8_t *)p->payload)[0] & 1) { /* broadcast or multicast packet*/ MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); } else { /* unicast packet */ MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); } /* increase ifoutdiscards or ifouterrors on error */

#if ETH_PAD_SIZE pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif

LINK_STATS_INC(link.xmit);

return ERR_OK; }

/** * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * * @param netif the lwip network interface structure for this ethernetif * @return a pbuf filled with the received packet (including MAC header) * NULL on memory error */ static struct pbuf * low_level_input(struct netif *netif) { struct ethernetif *ethernetif = netif->state; struct pbuf *p, *q; u16_t len; int ret; uint8_t *data; uint32_t id; XAxiDma_Bd *bd;

/* Obtain the size of the packet and put it into the "len" variable. */ ret = XAxiDma_BdRingFromHw(ethernetif->rxring, 1, &bd); if (ret rxring->MaxTransferLen); LWIP_ASSERT("rx packet too big", len next) { /* Read enough bytes to fill this pbuf in the chain. The * available data in the pbuf is given by the q->len * variable. * This does not necessarily have to be a memcpy, you can also preallocate * pbufs for a DMA-enabled MAC and after receiving truncate it to the * actually received size. In this case, ensure the tot_len member of the * pbuf is the sum of the chained pbuf len members. */ memcpy(q->payload, data, q->len); data += q->len; } //acknowledge that packet has been read();

MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); if (((u8_t *)p->payload)[0] & 1) { /* broadcast or multicast packet*/ MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); } else { /* unicast packet*/ MIB2_STATS_NETIF_INC(netif, ifinucastpkts); } #if ETH_PAD_SIZE pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif

LINK_STATS_INC(link.recv); } else { //drop packet(); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); MIB2_STATS_NETIF_INC(netif, ifindiscards); }

// 继续接收后续数据包 ret = XAxiDma_BdRingFree(ethernetif->rxring, 1, bd); LWIP_ASSERT("DMA rxring freed one", ret == XST_SUCCESS); ret = XAxiDma_BdRingAlloc(ethernetif->rxring, 1, &bd); LWIP_ASSERT("DMA rxring allocated one", ret == XST_SUCCESS); XAxiDma_BdSetBufAddr(bd, (uintptr_t)dma_buffer_rx[ethernetif->rx_i]); XAxiDma_BdSetLength(bd, sizeof(dma_buffer_rx[ethernetif->rx_i]), ethernetif->rxring->MaxTransferLen); XAxiDma_BdSetCtrl(bd, 0); XAxiDma_BdSetId(bd, ethernetif->rx_i); ret = XAxiDma_BdRingToHw(ethernetif->rxring, 1, bd); LWIP_ASSERT("DMA rxring brought one", ret == XST_SUCCESS); ethernetif->rx_i = (ethernetif->rx_i + 1) % RX_NUM;

return p; }

/** * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * * @param netif the lwip network interface structure for this ethernetif */ /*static */void ethernetif_input(struct netif *netif) { //struct ethernetif *ethernetif; //struct eth_hdr *ethhdr; struct pbuf *p;

//ethernetif = netif->state;

/* move received packet into a new pbuf */ p = low_level_input(netif); /* if no packet could be read, silently ignore this */ if (p != NULL) { /* pass all packets to ethernet_input, which decides what packets it supports */ if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } } }

/** * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * * This function should be passed as a parameter to netif_add(). * * @param netif the lwip network interface structure for this ethernetif * @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 ethernetif_init(struct netif *netif) { struct ethernetif *ethernetif;

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

ethernetif = mem_malloc(sizeof(struct ethernetif)); if (ethernetif == NULL) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); return ERR_MEM; }

#if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif->hostname = "XC7A35TFGG484-2_ETH"; // 路由器里面看到的设备名称 #endif /* LWIP_NETIF_HOSTNAME */

/* * Initialize the snmp variables and counters inside the struct netif. * The last argument should be replaced with your link speed, in units * of bits per second. */ MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);

netif->state = ethernetif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; /* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ #if LWIP_IPV4 netif->output = etharp_output; #endif /* LWIP_IPV4 */ #if LWIP_IPV6 netif->output_ip6 = ethip6_output; #endif /* LWIP_IPV6 */ netif->linkoutput = low_level_output;

ethernetif->ethaddr = (struct eth_addr *) & (netif->hwaddr[0]);

/* initialize the hardware */ low_level_init(netif);

return ERR_OK; }

/* 网线插拔检测 */ void ethernetif_check_link(struct netif *netif) { uint16_t value;

XAxiEthernet_PhyRead(&xaxieth, PHY_ADDR, PHY_BMSR, &value); if (value & PHY_LINKED_STATUS) { /* 已插入网线 */ if (!netif_is_link_up(netif)) { if (value & PHY_AUTONEGO_COMPLETE) // 自动协商完毕 { // 配置速率和双工模式 printf("Link is up!\n"); XAxiEthernet_PhyRead(&xaxieth, PHY_ADDR, PHY_PHYSR, &value); if (value & PHY_SPEED1_STATUS) { printf("Speed: 1000Mbps\n"); XAxiEthernet_SetOperatingSpeed(&xaxieth, XAE_SPEED_1000_MBPS); } else if (value & PHY_SPEED0_STATUS) { printf("Speed: 100Mbps\n"); XAxiEthernet_SetOperatingSpeed(&xaxieth, XAE_SPEED_100_MBPS); } else { printf("Speed: 10Mbps\n"); XAxiEthernet_SetOperatingSpeed(&xaxieth, XAE_SPEED_10_MBPS); }

// AXI 1G/2.5G Ethernet Subsystem IP核不支持半双工模式, 所以这里不做设置 if (value & PHY_DUPLEX_STATUS) printf("Duplex: full\n"); else printf("Duplex: half\n");

XAxiEthernet_Start(&xaxieth); netif_set_link_up(netif); } } } else { /* 已拔出网线 */ if (netif_is_link_up(netif)) { printf("Link is down!\n"); XAxiEthernet_Stop(&xaxieth); netif_set_link_down(netif); } } }

#endif /* 0 */

ethernetif.h:

#ifndef ETHERNETIF_H #define ETHERNETIF_H

#ifndef _BV #define _BV(n) (1ull



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3