初始化和收发函数是按官方例子enet_lwip、enet_uip改的,代码如下:
/* ****************************************************************************************************** ** 标志位定义 ** ****************************************************************************************************** */ uint8_t ETH_FLAG_RXPKT; //->0:没收到数据包 1:接收到数据包 uint8_t ETH_FLAG_TXPKT; //->0:数据包发送完成 1:数据包等待发送 /* ****************************************************************************************************** ** 描述和状态定义以及EMAC内存分配 ** ****************************************************************************************************** */ #define NUM_RX_DESCRIPTORS 3 #define NUM_TX_DESCRIPTORS 3 #define RX_BUFFER_SIZE 1536 #define TX_BUFFER_SIZE 1536 tEMACDMADescriptor RxDescriptor[NUM_TX_DESCRIPTORS]; tEMACDMADescriptor TxDescriptor[NUM_RX_DESCRIPTORS]; uint8_t RxBuffer[NUM_RX_DESCRIPTORS][RX_BUFFER_SIZE]; uint8_t TxBuffer[NUM_TX_DESCRIPTORS][TX_BUFFER_SIZE]; static uint32_t RxDescIndex; static uint32_t TxDescIndex; /* ****************************************************************************************************** ** 设备信息定义 ** ****************************************************************************************************** */ typedef struct { uint8_t mac[6]; //MAC地址. uint8_t ip[4]; //IP地址. uint8_t mark[4]; //子网掩码. uint8_t gate[4]; //默认网关. }device_t; device_t Device; static const uint8_t IP[4] ={192,168,1,88}; //本机IP地址. static const uint8_t MARK[4] ={255,255,255,0}; //子网掩码. static const uint8_t GATE[4] ={192,168,1,1}; //默认网关. /* ****************************************************************************************************** **函数名称: void InitDescriptors(void) ** **函数描述: 初始化发送、接收描述相关参量(OWN = 1:owned by the DMA OWN = 0:owned by the CPU) ** **参 数: 无 ** **返 回: 无 ** ****************************************************************************************************** */ void InitDescriptors(void) { uint32_t ui32Loop; // Initialize each of the receive descriptors. for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) { RxDescriptor[ui32Loop].ui32CtrlStatus = 0; RxDescriptor[ui32Loop].ui32Count = (DES1_RX_CTRL_CHAINED | (RX_BUFFER_SIZE << DES1_RX_CTRL_BUFF1_SIZE_S)); RxDescriptor[ui32Loop].pvBuffer1 = RxBuffer[ui32Loop]; RxDescriptor[ui32Loop].DES3.pLink = (ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ? &RxDescriptor[0] : &RxDescriptor[ui32Loop + 1]; } // Initialize each of the transmit descriptors. Note that we leave the OWN bit clear here since we have not set up any transmissions yet. for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++) { TxDescriptor[ui32Loop].ui32CtrlStatus = (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_IP_ALL_CKHSUMS); TxDescriptor[ui32Loop].ui32Count = (DES1_TX_CTRL_SADDR_INSERT | (TX_BUFFER_SIZE << DES1_TX_CTRL_BUFF1_SIZE_S)); TxDescriptor[ui32Loop].pvBuffer1 = TxBuffer[ui32Loop]; TxDescriptor[ui32Loop].DES3.pLink = (ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ? &TxDescriptor[0] : &TxDescriptor[ui32Loop + 1]; } // Set the descriptor pointers in the hardware. EMACRxDMADescriptorListSet(EMAC0_BASE, RxDescriptor); EMACTxDMADescriptorListSet(EMAC0_BASE, TxDescriptor); // Start from the beginning of both descriptor chains. We actually set the transmit descriptor index to the last descriptor in the chain // since it will be incremented before use and this means the first transmission we perform will use the correct descriptor. RxDescIndex = 0; TxDescIndex = NUM_TX_DESCRIPTORS - 1; // Mark the first receive descriptor as available to the DMA to start the receive processing. RxDescriptor[RxDescIndex].ui32CtrlStatus |= DES0_RX_CTRL_OWN; } /* ****************************************************************************************************** **函数名称: uint32_t PacketReceive(uint8_t *pui8Buf) ** **函数描述: 从DMA接收缓冲区读取一个数据包 ** **参 数: pui8Buf-------数据包存储缓冲区指针 ** **返 回: i32FrameLen---数据长度 ** ****************************************************************************************************** */ uint32_t PacketReceive(uint8_t *pui8Buf) { uint32_t i32FrameLen, i32Loop; // Check the arguments. ASSERT(pui8Buf != 0); // By default, we assume we got a bad frame. i32FrameLen = 0; // Make sure that CPU own the receive descriptor. if(!(RxDescriptor[RxDescIndex].ui32CtrlStatus & DES0_RX_CTRL_OWN)) { // We own the receive descriptor so check to see if it contains a valid frame. Look for a descriptor error, // indicating that the incoming packet was truncated or, if this is the last frame in a packet, the receive error bit. if(!(RxDescriptor[RxDescIndex].ui32CtrlStatus & DES0_RX_STAT_ERR)) { // We have a valid frame so copy the content to the supplied buffer. First check that the "last descriptor" flag is set. // We sized the receive buffer such that it can always hold a valid frame so this flag should never be clear at this point but... if(RxDescriptor[RxDescIndex].ui32CtrlStatus & DES0_RX_STAT_LAST_DESC) { i32FrameLen = ((RxDescriptor[RxDescIndex].ui32CtrlStatus & DES0_RX_STAT_FRAME_LENGTH_M) >> DES0_RX_STAT_FRAME_LENGTH_S); // Sanity check. if(i32FrameLen > RX_BUFFER_SIZE) { i32FrameLen = RX_BUFFER_SIZE; } // Copy the data from the DMA receive buffer into the provided frame buffer. for(i32Loop = 0; i32Loop < i32FrameLen; i32Loop++) { pui8Buf[i32Loop] = RxBuffer[RxDescIndex][i32Loop]; } } } // Move on to the next descriptor in the chain. RxDescIndex++; if(RxDescIndex == NUM_RX_DESCRIPTORS) { RxDescIndex = 0; } // Give this descriptor back to the DMA. RxDescriptor[RxDescIndex].ui32CtrlStatus = DES0_RX_CTRL_OWN; } // Return the Frame Length. return(i32FrameLen); } /* ****************************************************************************************************** **函数名称: uint32_t PacketTransmit(uint8_t *pui8Buf, uint32_t i32BufLen) ** **函数描述: 发送数据包 ** **参 数: pui8Buf-----待发送数据包缓冲区指针 ** ** i32BufLen---待发送数据包的长度 ** **返 回: i32BufLen---实际发送数据的长度 ** ****************************************************************************************************** */ uint32_t PacketTransmit(uint8_t *pui8Buf, uint32_t i32BufLen) { uint32_t i32Loop; // Indicate that a packet is being sent. ETH_FLAG_TXPKT = 1; printf("ETH_FLAG_TXPKT = 1;\r\n"); // Wait for the previous packet to be transmitted. while(TxDescriptor[TxDescIndex].ui32CtrlStatus & DES0_TX_CTRL_OWN); printf("ETH_FLAG_TXPKT = 2;\r\n"); // Sanity check. if(i32BufLen > TX_BUFFER_SIZE) { i32BufLen = TX_BUFFER_SIZE; } // Copy the packet data into the transmit buffer. for(i32Loop = 0; i32Loop < i32BufLen; i32Loop++) { TxBuffer[TxDescIndex][i32Loop] = pui8Buf[i32Loop]; printf("pui8Buf[%d] = %02X\r\n", i32Loop, pui8Buf[i32Loop]); } // Move to the next descriptor. TxDescIndex++; if(TxDescIndex == NUM_TX_DESCRIPTORS) { TxDescIndex = 0; } // Fill in the packet size and tell the transmitter to start work. TxDescriptor[TxDescIndex].ui32Count = (uint32_t)i32BufLen; TxDescriptor[TxDescIndex].ui32CtrlStatus = ( DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_OWN); // Tell the DMA to reacquire the descriptor now that we've filled it in. EMACTxDMAPollDemand(EMAC0_BASE); printf("ETH_FLAG_TXPKT = 3;\r\n"); // Return the number of bytes sent. return(i32BufLen); } /* ****************************************************************************************************** **函数名称: void HAL_EMAC_Init(void) ** **函数描述: 网口初始化 ** **参 数: 无 ** **返 回: 无 ** ****************************************************************************************************** */ void HAL_EMAC_Init(void) { // PF0/PF1/PF4 are used for Ethernet LEDs. GPIOPinConfigure(GPIO_PF0_EN0LED0); GPIOPinConfigure(GPIO_PF4_EN0LED1); GPIOPinConfigure(GPIO_PF1_EN0LED2); GPIOPinTypeEthernetLED(GPIOF_AHB_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4); // Wait for the MAC to be ready. while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)); // Configure for use with the internal PHY. EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | EMAC_PHY_AN_100B_T_FULL_DUPLEX); // Reset the MAC. EMACReset(EMAC0_BASE); // Initialize the MAC and set the DMA mode. EMACInit(EMAC0_BASE, SystemCoreClock, EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0); // Set MAC configuration options. EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD | EMAC_CONFIG_7BYTE_PREAMBLE | EMAC_CONFIG_IF_GAP_96BITS | EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR | EMAC_CONFIG_BO_LIMIT_1024), (EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD | EMAC_MODE_TX_THRESHOLD_64_BYTES | EMAC_MODE_RX_THRESHOLD_64_BYTES), 0); // Initialize the Ethernet DMA descriptors. InitDescriptors(); // Program the hardware with its MAC address (for filtering). EMACAddrSet(EMAC0_BASE, 0, Device.mac); // Wait for the link to become active. //while((EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & EPHY_BMSR_LINKSTAT) == 0); // Set MAC filtering options. We receive all broadcast and multicast packets along with those addressed specifically for us. EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_SADDR | EMAC_FRMFILTER_PASS_MULTICAST | EMAC_FRMFILTER_PASS_NO_CTRL)); // Clear any pending interrupts. EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false)); // Enable the Ethernet MAC transmitter and receiver. EMACTxEnable(EMAC0_BASE); EMACRxEnable(EMAC0_BASE); // Enable the Ethernet interrupt. IntEnable(INT_EMAC0); // Enable the Ethernet RX Packet interrupt source. EMACIntEnable(EMAC0_BASE, EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT); } /* ****************************************************************************************************** **函数名称: void ENET_IRQHandler(void) ** **函数描述: 以太网中断服务程序 ** **参 数: 无 ** **返 回: 无 ** ****************************************************************************************************** */ void ETH_Handler(void) { uint32_t IntStatus; // Read and Clear the interrupt. IntStatus = EMACIntStatus(EMAC0_BASE, true); MAP_EMACIntClear(EMAC0_BASE, IntStatus); // Check to see if an RX Interrupt has occurred. if(IntStatus & EMAC_INT_RECEIVE) { // Indicate that a packet has been received. ETH_FLAG_RXPKT = 1; } // Has the DMA finished transferring a packet to the transmitter? if(IntStatus & EMAC_INT_TRANSMIT) { // Indicate that a packet has been sent. ETH_FLAG_TXPKT = 0; } } /* ****************************************************************************************************** **函数名称: void Config(void) ** **函数描述: 参数配置函数 ** **参 数: 无 ** **返 回: 无 ** ****************************************************************************************************** */ void Config(void) { uint32_t ui32User0, ui32User1; FlashUserGet(&ui32User0, &ui32User1); if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff)) { // // We should never get here. This is an error if the MAC address has // not been programmed into the device. Exit the program. // Let the user know there is no MAC address // printf("No MAC programmed!\n"); while(1) { } } Device.mac[0] = ((ui32User0 >> 0) & 0xff); Device.mac[1] = ((ui32User0 >> 8) & 0xff); Device.mac[2] = ((ui32User0 >> 16) & 0xff); Device.mac[3] = ((ui32User1 >> 0) & 0xff); Device.mac[4] = ((ui32User1 >> 8) & 0xff); Device.mac[5] = ((ui32User1 >> 16) & 0xff); memcpy(Device.ip, IP, 4); //IP memcpy(Device.mark, MARK, 4); //MARK memcpy(Device.gate, GATE, 4); //GATEWAY } /* ****************************************************************************************************** **函数名称: void APP_LWIP_Init(void) ** **函数描述: 初始化LWIP所有相关信息 ** **参 数: 无 ** **返 回: 无 ** ****************************************************************************************************** */ void APP_LWIP_Init(void) { Config(); HAL_EMAC_Init(); //初始化EMAC. lwip_init(); //LwIP协议栈初始化. // add the network interface. netif_add(&my_netif, (ip4_addr_t *)&Device.ip, (ip4_addr_t *)&Device.mark, (ip4_addr_t *)&Device.gate, NULL, ethernetif_init, ethernet_input); // Registers the default network interface. netif_set_default(&my_netif); netif_set_up(&my_netif); //HTTP应用层初始化 //httpd_init(); //初始化HTTP服务器监听端口. //httpd_cgi_ssi_init(); //CGI、SSI相关初始化. //TCP应用层初始化 //tcp_server_init(); //初始化TCP服务器. //UDP应用层初始化 //udp_server_init(); //初始化UDP服务器. }
ethernetif.c代码如下:
/** * @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 <adam@sics.se> * */ /* * 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/sys.h" #include <lwip/stats.h> #include <lwip/snmp.h> #include "netif/etharp.h" #include "netif/ppp/pppoe.h" #include "includes.h" // add by eBoy---2012-10-20 /* 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. */ }; /* Forward declarations. */ err_t ethernetif_input(struct netif *netif); /** * 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; /* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* set MAC hardware address */ netif->hwaddr[0] = Device.mac[0]; netif->hwaddr[1] = Device.mac[1]; netif->hwaddr[2] = Device.mac[2]; netif->hwaddr[3] = Device.mac[3]; netif->hwaddr[4] = Device.mac[4]; netif->hwaddr[5] = Device.mac[5]; /* printf("netif->hwaddr[0] = %02X\r\n",netif->hwaddr[0]); printf("netif->hwaddr[1] = %02X\r\n",netif->hwaddr[1]); printf("netif->hwaddr[2] = %02X\r\n",netif->hwaddr[2]); printf("netif->hwaddr[3] = %02X\r\n",netif->hwaddr[3]); printf("netif->hwaddr[4] = %02X\r\n",netif->hwaddr[4]); printf("netif->hwaddr[5] = %02X\r\n",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; /* Do whatever else is needed to initialize interface. */ } /** * 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 availale 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; u16_t len=0; u8_t buffer[1536]; 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. */ memcpy((u8_t*)&buffer[len], (u8_t*)q->payload, q->len); len = len + q->len; } PacketTransmit(buffer, len); 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=0,i=0; u8_t buffer[1536]; /* Obtain the size of the packet and put it into the "len" variable. */ len = PacketReceive(buffer); /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { /* We iterate over the pbuf chain until we have read the entire * packet into the pbuf. */ for(q = p; q != NULL; q = q->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((u8_t*)q->payload, (u8_t*)&buffer[i], q->len); i = i + q->len; } } 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 */ err_t ethernetif_input(struct netif *netif) { //struct ethernetif *ethernetif = netif->state; struct pbuf *p; err_t err; /* move received packet into a new pbuf */ p = low_level_input(netif); /* no packet could be read, silently ignore this */ if (p == NULL) return ERR_MEM; err = netif->input(p, netif); if (err != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } return err; } /** * 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 = "lwip"; #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. */ NETIF_INIT_SNMP(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...) */ netif->output = etharp_output; netif->linkoutput = low_level_output; ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); /* initialize the hardware */ low_level_init(netif); return ERR_OK; } #endif /* 0 */
ping 192.168.1.88时,串口输出如下:
通过串口打印的信息看,回复的是ARP帧,可电脑好像收不到,导致后面的ICMP一直Ping不通。
求大神帮忙~!谢谢!