LwIP 之二 网络接口 netif(netif.c、ethernetif( 四 )

< IAR Compiler */#pragma location=0x2007c000ETH_DMADescTypeDefDMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */#pragma location=0x2007c0a0ETH_DMADescTypeDefDMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */#elif defined ( __CC_ARM )/* MDK ARM Compiler */__attribute__((at(0x2007c000))) ETH_DMADescTypeDefDMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */__attribute__((at(0x2007c0a0))) ETH_DMADescTypeDefDMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */#elif defined ( __GNUC__ ) /* GNU Compiler */ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection")));/* Ethernet Tx DMA Descriptors */#endif/*@Note: This interface is implemented to operate in zero-copy mode only:- Rx buffers will be allocated from LwIP stack memory heap,then passed to ETH HAL driver.- Tx buffers will be allocated from LwIP stack memory heap,then passed to ETH HAL driver.@Notes:1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4,to customize it please redefine ETH_RX_DESC_CNT in ETH GUI (Rx Descriptor Length)so that updated value will be generated in stm32xxxx_hal_conf.h1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4,to customize it please redefine ETH_TX_DESC_CNT in ETH GUI (Tx Descriptor Length)so that updated value will be generated in stm32xxxx_hal_conf.h2.a. Rx Buffers number must be between ETH_RX_DESC_CNT and 2*ETH_RX_DESC_CNT2.b. Rx Buffers must have the same size: ETH_RX_BUF_SIZE, this value mustpassed to ETH DMA in the init field (heth.Init.RxBuffLen)2.cThe RX Ruffers addresses and sizes must be properly defined to be alignedto L1-CACHE line size (32 bytes).*//* Data Type Definitions */typedef enum{RX_ALLOC_OK= 0x00,RX_ALLOC_ERROR = 0x01} RxAllocStatusTypeDef;/* Variable Definitions */static uint8_t RxAllocStatus;typedef struct{struct pbuf_custom pbuf_custom;uint8_t buff[(ETH_RX_BUF_SIZE + 31) & ~31] __ALIGNED(32);} RxBuff_t;/* Memory Pool Declaration */#define ETH_RX_BUFFER_CNT12ULWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool");/*** @brief Semaphore to signal incoming packets*/sys_sem_t sem_netif_rx;sys_sem_t sem_netif_tx;/*** @brief Global Ethernet handle*/ETH_HandleTypeDef heth;ETH_TxPacketConfig TxConfig;/*** @brief PHY*/dp83848_Object_t DP83848;dp83848_IOCtx_tDP83848_IOCtx = {ETH_PHY_IO_Init,ETH_PHY_IO_DeInit,ETH_PHY_IO_WriteReg,ETH_PHY_IO_ReadReg,ETH_PHY_IO_GetTick};/* Private functions ---------------------------------------------------------*//** @defgroup ETH Initialization functions *@briefInitialization and Configuration functions *@verbatim==============================================================================##### Initialization functions #####==============================================================================[..]@endverbatim* @{*//*** @briefInitializes the ETH MSP.* @paramheth pointer to a ETH_HandleTypeDef structure that contains*the configuration information for ETHERNET module* @retval None*/void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle){GPIO_InitTypeDef GPIO_InitStruct = {0};if (ethHandle->Instance == ETH){/* Enable Peripheral clock */__HAL_RCC_ETH_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOG_CLK_ENABLE();__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**ETH GPIO ConfigurationPE2------> ETH_TXD3PG14------> ETH_TXD1PG13------> ETH_TXD0PG11------> ETH_TX_ENPH3------> ETH_COLPH2------> ETH_CRSPC3------> ETH_TX_CLKPC1------> ETH_MDCPC2------> ETH_TXD2PA1------> ETH_RX_CLKPC4------> ETH_RXD0PH7------> ETH_RXD3PA2------> ETH_MDIOPC5------> ETH_RXD1PH6------> ETH_RXD2PA7------> ETH_RX_DV*/GPIO_InitStruct.Pin= GPIO_PIN_2;GPIO_InitStruct.Mode= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull= GPIO_NOPULL;GPIO_InitStruct.Speed= GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);GPIO_InitStruct.Pin= GPIO_PIN_14 | GPIO_PIN_13 | GPIO_PIN_11;GPIO_InitStruct.Mode= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull= GPIO_NOPULL;GPIO_InitStruct.Speed= GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_7 | GPIO_PIN_6;GPIO_InitStruct.Mode= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull= GPIO_NOPULL;GPIO_InitStruct.Speed= GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);GPIO_InitStruct.Pin =GPIO_PIN_3 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5;GPIO_InitStruct.Mode= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull= GPIO_NOPULL;GPIO_InitStruct.Speed= GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin= GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;GPIO_InitStruct.Mode= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull= GPIO_NOPULL;GPIO_InitStruct.Speed= GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* Peripheral interrupt init */HAL_NVIC_SetPriority(ETH_IRQn, 5, 0);HAL_NVIC_EnableIRQ(ETH_IRQn);}}/*** @briefDeInitializes ETH MSP.* @paramheth pointer to a ETH_HandleTypeDef structure that contains*the configuration information for ETHERNET module* @retval None*/void HAL_ETH_MspDeInit(ETH_HandleTypeDef *ethHandle){if (ethHandle->Instance == ETH){/* Peripheral clock disable */__HAL_RCC_ETH_CLK_DISABLE();/**ETH GPIO ConfigurationPE2------> ETH_TXD3PG14------> ETH_TXD1PG13------> ETH_TXD0PG11------> ETH_TX_ENPH3------> ETH_COLPH2------> ETH_CRSPC3------> ETH_TX_CLKPC1------> ETH_MDCPC2------> ETH_TXD2PA1------> ETH_RX_CLKPC4------> ETH_RXD0PH7------> ETH_RXD3PA2------> ETH_MDIOPC5------> ETH_RXD1PH6------> ETH_RXD2PA7------> ETH_RX_DV*/HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2);HAL_GPIO_DeInit(GPIOG, GPIO_PIN_14 | GPIO_PIN_13 | GPIO_PIN_11);HAL_GPIO_DeInit(GPIOH,GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_7 | GPIO_PIN_6);HAL_GPIO_DeInit(GPIOC, GPIO_PIN_3 | GPIO_PIN_1 | GPIO_PIN_2 |GPIO_PIN_4 | GPIO_PIN_5);HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7);/* Peripheral interrupt Deinit*/HAL_NVIC_DisableIRQ(ETH_IRQn);}}/*** @briefThis function handles Ethernet global interrupt.* @paramNone* @retval None*/void ETH_IRQHandler(void){HAL_ETH_IRQHandler(&heth);}/*** @briefEthernet Rx Transfer completed callback* @paramhandlerEth: ETH handler* @retval None*/void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef* handlerEth){BaseType_t yield = pdFALSE;xSemaphoreGiveFromISR(sem_netif_rx.sem, &yield);}/*** @briefEthernet Tx Transfer completed callback* @paramhandlerEth: ETH handler* @retval None*/void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef* handlerEth){BaseType_t yield = pdFALSE;xSemaphoreGiveFromISR(sem_netif_tx.sem, &yield);}/*** @briefEthernet DMA transfer error callback* @paramhandlerEth: ETH handler* @retval None*/void HAL_ETH_ErrorCallback(ETH_HandleTypeDef* handlerEth){if ((HAL_ETH_GetDMAError(handlerEth) & ETH_DMASR_RBUS) == ETH_DMASR_RBUS){BaseType_t yield = pdFALSE;xSemaphoreGiveFromISR(sem_netif_rx.sem, &yield);}}/*** @briefCustom Rx pbuf free callback* @parampbuf: pbuf to be freed* @retval None*/void pbuf_free_custom(struct pbuf *p){BaseType_t yield = pdFALSE;struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p;LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf);/* If the Rx Buffer Pool was exhausted, signal the ethernetif_input task to* call HAL_ETH_GetRxDataBuffer to rebuild the Rx descriptors. */if (RxAllocStatus == RX_ALLOC_ERROR){RxAllocStatus = RX_ALLOC_OK;xSemaphoreGiveFromISR(sem_netif_rx.sem, &yield);}}/*** @briefRx Allocate callback.* @parambuff: pointer to allocated buffer* @retval None*/void HAL_ETH_RxAllocateCallback(uint8_t** buff){struct pbuf_custom* p = LWIP_MEMPOOL_ALLOC(RX_POOL);if (p){/* Get the buff from the struct pbuf address. */*buff= (uint8_t*)p + offsetof(RxBuff_t, buff);p->custom_free_function = pbuf_free_custom;/* Initialize the struct pbuf.* This must be performed whenever a buffer's allocated because it may* be changed by lwIP or the app, e.g., pbuf_free decrements ref. */pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, p, *buff, ETH_RX_BUF_SIZE);}else{RxAllocStatus = RX_ALLOC_ERROR;*buff= NULL;}}/*** @briefRx Link callback.* @parampStart: pointer to packet start* @parampStart: pointer to packet end* @parambuff: pointer to received data* @paramLength: received data length* @retval None*/void HAL_ETH_RxLinkCallback(void** pStart, void** pEnd, uint8_t* buff,uint16_t Length){struct pbuf** ppStart = (struct pbuf**)pStart;struct pbuf** ppEnd= (struct pbuf**)pEnd;struct pbuf* p= NULL;/* Get the struct pbuf from the buff address. */p= (struct pbuf*)(buff - offsetof(RxBuff_t, buff));p->next= NULL;p->tot_len = 0;p->len= Length;/* Chain the buffer. */if (!*ppStart){/* The first buffer of the packet. */*ppStart = p;}else{/* Chain the buffer to the end of the packet. */(*ppEnd)->next = p;}*ppEnd = p;/* Update the total length of all the buffers of the chain. Each pbuf in the* chain should have its tot_len set to its own length, plus the length of* all the following pbufs in the chain. */for (p = *ppStart; p != NULL; p = p->next){p->tot_len += Length;}/* Invalidate data cache because Rx DMA's writing to physical memory makes* it stale. */SCB_InvalidateDCache_by_Addr((uint32_t*)buff, Length);}/*** @briefTx Free callback.* @parambuff: pointer to buffer to free* @retval None*/void HAL_ETH_TxFreeCallback(uint32_t* buff){pbuf_free((struct pbuf*)buff);}/*** @briefInitializes the MDIO interface GPIO and clocks.* @paramNone* @retval 0 if OK, -1 if ERROR*/int32_t ETH_PHY_IO_Init(void){/* We assume that MDIO GPIO configuration is already donein the ETH_MspInit() else it should be done here*//* Configure the MDIO Clock */HAL_ETH_SetMDIOClockRange(&heth);return 0;}/*** @briefDe-Initializes the MDIO interface .* @paramNone* @retval 0 if OK, -1 if ERROR*/int32_t ETH_PHY_IO_DeInit(void){return 0;}/*** @briefRead a PHY register through the MDIO interface.* @paramDevAddr: PHY port address* @paramRegAddr: PHY register address* @parampRegVal: pointer to hold the register value* @retval 0 if OK -1 if Error*/int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr,uint32_t* pRegVal){if (HAL_ETH_ReadPHYRegister(&heth, DevAddr, RegAddr, pRegVal) != HAL_OK){return -1;}return 0;}/*** @briefWrite a value to a PHY register through the MDIO interface.* @paramDevAddr: PHY port address* @paramRegAddr: PHY register address* @paramRegVal: Value to be written* @retval 0 if OK -1 if Error*/int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal){if (HAL_ETH_WritePHYRegister(&heth, DevAddr, RegAddr, RegVal) != HAL_OK){return -1;}return 0;}/*** @briefGet the time in millisecons used for internal PHY driver process.* @retval Time value*/int32_t ETH_PHY_IO_GetTick(void){return HAL_GetTick();}/*** @}*//** @defgroup lwip ethernet interface low level send and receive functions *@briefethernet interface low level send and receive functions *@verbatim==============================================================================##### ethernet interface low level send and receive functions #####==============================================================================[..]@endverbatim* @{*//*** 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){uint32_t i= 0U;struct pbuf* q= NULL;err_t errval= ERR_OK;ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT] = {0};memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));for (q = p; q != NULL; q = q->next){if (i >= ETH_TX_DESC_CNT){return ERR_IF;}Txbuffer[i].buffer = q->payload;Txbuffer[i].len= q->len;if (i > 0){Txbuffer[i - 1].next = &Txbuffer[i];}if (q->next == NULL){Txbuffer[i].next = NULL;}i++;}TxConfig.Length= p->tot_len;TxConfig.TxBuffer = Txbuffer;TxConfig.pData= http://www.kingceram.com/post/p;pbuf_ref(p);HAL_ETH_Transmit_IT(&heth, &TxConfig);while(xSemaphoreTake(sem_netif_tx.sem, NETIF_OUTPUT_TIMEOUT) != pdPASS);HAL_ETH_ReleaseTxPacket(&heth);return errval;}/*** 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 pbuf* p = NULL;if (RxAllocStatus == RX_ALLOC_OK){HAL_ETH_ReadData(&heth, (void**)&p);}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(void *argument){struct pbuf *p;struct netif *netif = (struct netif *)argument;for (;;){if (sys_arch_sem_wait(&sem_netif_rx, NETIF_INPUT_TIMEOUT) == pdTRUE){do{p = low_level_input(netif);if (p != NULL){if (netif->input(p, netif) != ERR_OK){pbuf_free(p);}}} while (p != NULL);}}}/*** @}*//** @defgroup lwip ethernet interface low level init functions *@briefethernet interface low level init functions *@verbatim==============================================================================##### ethernet interface low level init functions #####==============================================================================[..]@endverbatim* @{*//*** 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){HAL_StatusTypeDef hal_eth_init_status = HAL_OK;uint32_t duplex, speed = 0;int32_t PHYLinkState = 0;ETH_MACConfigTypeDef MACConf = {0};uint8_t MACAddr[6];MACAddr[0]= 0x00;MACAddr[1]= 0x80;MACAddr[2]= 0xE1;MACAddr[3]= 0x00;MACAddr[4]= 0x00;MACAddr[5]= 0x00;heth.Instance= ETH;heth.Init.MACAddr= &MACAddr[0];heth.Init.MediaInterface = HAL_ETH_MII_MODE;heth.Init.TxDesc= DMATxDscrTab;heth.Init.RxDesc= DMARxDscrTab;heth.Init.RxBuffLen= 1536;hal_eth_init_status = HAL_ETH_Init(&heth);memset(&TxConfig, 0, sizeof(ETH_TxPacketConfig));TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;TxConfig.CRCPadCtrl= ETH_CRC_PAD_INSERT;/* Initialize the RX POOL */LWIP_MEMPOOL_INIT(RX_POOL);#if LWIP_ARP || LWIP_ETHERNET/* set MAC hardware address length */netif->hwaddr_len = ETH_HWADDR_LEN;/* set MAC hardware address */netif->hwaddr[0] = heth.Init.MACAddr[0];netif->hwaddr[1] = heth.Init.MACAddr[1];netif->hwaddr[2] = heth.Init.MACAddr[2];netif->hwaddr[3] = heth.Init.MACAddr[3];netif->hwaddr[4] = heth.Init.MACAddr[4];netif->hwaddr[5] = heth.Init.MACAddr[5];/* maximum transfer unit */netif->mtu = ETH_MAX_PAYLOAD;/* Accept broadcast address and ARP traffic *//* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */#if LWIP_ARPnetif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;#elsenetif->flags |= NETIF_FLAG_BROADCAST;#endif /* LWIP_ARP *//* create a binary semaphore used for informing ethernetif of frame reception */sys_sem_new(&sem_netif_rx, 0);sys_sem_new(&sem_netif_tx, 0);/* create the task that handles the ETH_MAC */sys_thread_new("Eth_input", ethernetif_input, netif, NETIF_INPUT_STACK_SIZE, NETIF_INPUT_PRIO);/* Set PHY IO functions */DP83848_RegisterBusIO(&DP83848, &DP83848_IOCtx);/* Initialize the DP83848 ETH PHY */DP83848_Init(&DP83848);if (hal_eth_init_status == HAL_OK){PHYLinkState = DP83848_GetLinkState(&DP83848);/* Get link state */if (PHYLinkState