#include #include #include #include #include "lwip/tcpip.h" #include "netif/etharp.h" #include "ethernetif.h" #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "NetworkSettings.h" #include "Log.h" #include "Lan8742.h" #include "Watchdog.h" #include "Stm32Tools.h" #include "CacheTools.h" #define IFNAME0 's' #define IFNAME1 't' #define ETH_RX_BUFFER_SIZE 1000 #define ETH_RX_BUFFER_CNT 12U #define HOSTNAME_BUFFER_SIZE 100 static char hostname[HOSTNAME_BUFFER_SIZE] = ""; typedef enum { RX_ALLOC_OK = 0x00, RX_ALLOC_ERROR = 0x01 } RxAllocStatusTypeDef; typedef struct { struct pbuf_custom pbuf_custom; uint8_t buff[(ETH_RX_BUFFER_SIZE + 31) & ~31] __ALIGNED(32); } RxBuff_t; // Ethernet Rx DMA Descriptors ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDescripSection"))); // Ethernet Tx DMA Descriptors ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDescripSection"))); LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool"); __attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[]; static uint8_t RxAllocStatus; static SemaphoreHandle_t tx_semaphore; static SemaphoreHandle_t rx_semaphore; typedef struct { PtpTime_t timestamp; } TxTimestampRecord_t; static QueueHandle_t timestamp_queue; static ETH_TxPacketConfig TxConfig; static ETH_HandleTypeDef EthHandle; static int32_t ETH_PHY_IO_Init(void); static int32_t ETH_PHY_IO_DeInit (void); static int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal); static int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal); static int32_t ETH_PHY_IO_GetTick(void); static lan8742_IOCtx_t LAN8742_IOCtx = { ETH_PHY_IO_Init, ETH_PHY_IO_DeInit, ETH_PHY_IO_WriteReg, ETH_PHY_IO_ReadReg, ETH_PHY_IO_GetTick }; static lan8742_Object_t LAN8742; #define ETH_LINK_PERIOD_MS 50 /* Examples of subsecond increment and addend values using SysClk = 275 MHz Addend * Increment = 2^63 / SysClk ptp_tick = Increment * 10^9 / 2^31 PTP tick: 20 ns Increment: 43 Addend: 0x2E84B2F4 */ #define PTP_ADDEND 0x2E84B2F4 LOG_TAG("ETH"); static void EthernetLinkTask(void* argument); static void ethernetif_input(void* argument); static void AssertPhyReset(const bool reset); static uint32_t SubsecondToNanosecond(const uint32_t subsecond_value); static uint32_t NanosecondToSubsecond(const uint32_t nanosecond_value); static void InitMac1588v2(void); static uint32_t SubsecondToNanosecond(const uint32_t subsecond_value) { uint64_t val = subsecond_value * 1000000000ll; val >>= 31; return val; } uint32_t NanosecondToSubsecond(const uint32_t nanosecond_value) { uint64_t val = nanosecond_value * 0x80000000ll; val /= 1000000000; return val; } bool ethernetif_GetTxTimestamp(PtpTime_t* const timestamp, const TickType_t block_time) { TxTimestampRecord_t record; if (xQueueReceive(timestamp_queue, &record, 0) != pdTRUE) { return false; } memcpy((void*)timestamp, (void*)&record.timestamp, sizeof(TxTimestampRecord_t)); return true; } void ethernetif_SetTime(const PtpTime_t* ptp_time) { EthHandle.Instance->MACSTSUR = ptp_time->tv_sec; EthHandle.Instance->MACSTNUR = NanosecondToSubsecond(ptp_time->tv_nsec); // This is a clock overwrite operation (as opposed to an offset), so we need to re-init SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSINIT); // The Time stamp counter starts operation as soon as it is initialized // with the value written in the Time stamp update register. while (EthHandle.Instance->MACTSCR & ETH_MACTSCR_TSINIT) { } } void ethernetif_GetTime(PtpTime_t* const ptp_time) { int32_t hi_reg; int32_t lo_reg; int32_t hi_reg_after; // The problem is we are reading two 32-bit registers that form // a 64-bit value, but it's possible the high 32-bits of the value // rolls over before we read the low 32-bits of the value. To avoid // this situation we read the high 32-bits twice and determine which // high 32-bits the low 32-bit are associated with. __disable_irq(); hi_reg = READ_REG(EthHandle.Instance->MACSTSR); lo_reg = READ_REG(EthHandle.Instance->MACSTNR); hi_reg_after = READ_REG(EthHandle.Instance->MACSTSR); __enable_irq(); // Did a roll over occur while reading? if (hi_reg != hi_reg_after) { // We now know a roll over occurred. If the rollover occured before // the reading of the low 32-bits we move the substitute the second // 32-bit high value for the first 32-bit high value. if (lo_reg < (INT_MAX / 2)) hi_reg = hi_reg_after; } // Now convert the raw registers values into timestamp values. ptp_time->tv_nsec = SubsecondToNanosecond(lo_reg); ptp_time->tv_sec = hi_reg; } void ethernetif_PtpFxAdjust(const int32_t adjustment_ppb) { uint32_t addend; // Adjust the fixed base frequency by parts-per-billion. // addend = base + ((base * adjustment_ppb) / 1000000000); addend = PTP_ADDEND + (int32_t)((((int64_t) PTP_ADDEND) * adjustment_ppb) / 1000000000); // Set the time stamp addend register with new rate value and set ETH_MACTSCR_TSADDREG WRITE_REG(EthHandle.Instance->MACTSAR, addend); SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSADDREG); } void ETH_IRQHandler(void) { HAL_ETH_IRQHandler(&EthHandle); } static void InitMac1588v2(void) { // RM0468 Rev 3 2925/3357 // 1. Mask the Timestamp Trigger interrupt by clearing bit 12 of Interrupt enable register (ETH_MACIER). //__HAL_ETH_MAC_DISABLE_IT(&EthHandle, ETH_MAC_TIMESTAMP_IT); CLEAR_BIT(EthHandle.Instance->MACIER, ETH_MACIER_TSIE); // 2. Set bit 0 of Timestamp control Register (ETH_MACTSCR) to enable timestamping. SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSENA); // Enable timestamping of all packets //SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSENALL); /*CLEAR_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSMSTRENA); SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSEVNTENA); //CLEAR_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_SNAPTYPSEL); //SET_BIT(EthHandle.Instance->MACTSCR, (1 << 16)); //SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSIPENA); //SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSIPV4ENA); //SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSIPV6ENA); //CLEAR_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSIPV4ENA);*/ SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSVER2ENA); // 3. Program Subsecond increment register (ETH_MACSSIR) based on the PTP clock frequency. WRITE_REG(EthHandle.Instance->MACSSIR, 43 << 16); // 4. If you use the Fine Correction method, // program Timestamp addend register (ETH_MACTSAR) and set bit 5 of Timestamp control Register (ETH_MACTSCR) WRITE_REG(EthHandle.Instance->MACTSAR, PTP_ADDEND); SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSADDREG); // 5. Poll the Timestamp control Register (ETH_MACTSCR) until bit 5 is cleared. while (READ_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSADDREG)) { } // 6. Program bit 1 of Timestamp control Register (ETH_MACTSCR) to select the Fine Update method (if required). SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSCFUPDT); // 7. Program System time seconds update register (ETH_MACSTSUR) and System time // nanoseconds update register (ETH_MACSTNUR) with the appropriate time value. EthHandle.Instance->MACSTSUR = 0; EthHandle.Instance->MACSTNUR = 0; // 8. Set bit 2 in Timestamp control Register (ETH_MACTSCR). SET_BIT(EthHandle.Instance->MACTSCR, ETH_MACTSCR_TSINIT); EthHandle.IsPtpConfigured = HAL_ETH_PTP_CONFIGURED; } static void low_level_init(struct netif *netif) { GPIO_InitTypeDef GPIO_InitStructure; uint8_t mac_address[6]; ETH_DMAConfigTypeDef dma_config = {0}; ETH_MACFilterConfigTypeDef pFilterConfig = {0}; Stm32Tools_GenerateMac(mac_address); tx_semaphore = xSemaphoreCreateBinary(); rx_semaphore = xSemaphoreCreateBinary(); timestamp_queue = xQueueCreate(1, sizeof(TxTimestampRecord_t)); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_ETH1MAC_CLK_ENABLE(); __HAL_RCC_ETH1TX_CLK_ENABLE(); __HAL_RCC_ETH1RX_CLK_ENABLE(); /* RMII_REF_CLK ----------------------> PA1 RMII_MDIO -------------------------> PA2 RMII_MDC --------------------------> PC1 RMII_MII_CRS_DV -------------------> PA7 RMII_MII_RXD0 ---------------------> PC4 RMII_MII_RXD1 ---------------------> PC5 RMII_MII_RXER ---------------------> PB10 RMII_MII_TX_EN --------------------> PB11 RMII_MII_TXD0 ---------------------> PB12 RMII_MII_TXD1 ---------------------> PB13 */ // Configure PA1, PA2 and PA7 GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Alternate = GPIO_AF11_ETH; GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // Configure PC1, PC4 and PC5 GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); // Configure PB11, PB12 and PB13 GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); // Init Eth Phy reset // PE1 PHY_RST GPIO_InitStructure.Pull = GPIO_PULLDOWN; GPIO_InitStructure.Speed = GPIO_SPEED_LOW; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pin = GPIO_PIN_1; GPIO_InitStructure.Alternate = 0; HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); // Bring PHY out of reset AssertPhyReset(true); HAL_Delay(2); AssertPhyReset(false); HAL_Delay(2); EthHandle.Instance = ETH; EthHandle.Init.MACAddr = mac_address; EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE; EthHandle.Init.RxDesc = DMARxDscrTab; EthHandle.Init.TxDesc = DMATxDscrTab; EthHandle.Init.RxBuffLen = ETH_RX_BUFFER_SIZE; HAL_ETH_Init(&EthHandle); netif->hwaddr_len = ETH_HWADDR_LEN; memcpy(netif->hwaddr, mac_address, 6); netif->mtu = ETH_MAX_PAYLOAD; netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; LWIP_MEMPOOL_INIT(RX_POOL); // Configure MAC filter pFilterConfig.PromiscuousMode = ENABLE; pFilterConfig.ReceiveAllMode = ENABLE; pFilterConfig.HachOrPerfectFilter = DISABLE; pFilterConfig.HashUnicast = DISABLE; pFilterConfig.HashMulticast = DISABLE; pFilterConfig.PassAllMulticast = ENABLE; pFilterConfig.SrcAddrFiltering = DISABLE; pFilterConfig.SrcAddrInverseFiltering = DISABLE; pFilterConfig.DestAddrInverseFiltering = DISABLE; pFilterConfig.BroadcastFilter = DISABLE; pFilterConfig.ControlPacketsFilter = 0; HAL_ETH_SetMACFilterConfig(&EthHandle, &pFilterConfig); InitMac1588v2(); // Enable enhanced descriptors for timestamp reception dma_config.DMAArbitration = ETH_DMAARBITRATION_TX1_RX1; dma_config.AddressAlignedBeats = ENABLE; dma_config.BurstMode = ETH_BURSTLENGTH_UNSPECIFIED; dma_config.RebuildINCRxBurst = ENABLE; /// ??? dma_config.PBLx8Mode = DISABLE; dma_config.TxDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT; dma_config.SecondPacketOperate = ENABLE; dma_config.RxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT; dma_config.FlushRxPacket = ENABLE; dma_config.TCPSegmentation = DISABLE; dma_config.MaximumSegmentSize = 0; HAL_ETH_SetDMAConfig(&EthHandle, &dma_config); 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; LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx); // Init the PHY ahead of the MAC if (LAN8742_Init(&LAN8742) != LAN8742_STATUS_OK) { LOG_E(TAG, "LAN8742_Init"); return; } HAL_NVIC_SetPriority(ETH_IRQn, 7, 0); HAL_NVIC_EnableIRQ(ETH_IRQn); xTaskCreate(ethernetif_input, "ethifin", 800, netif, 0, NULL); xTaskCreate(EthernetLinkTask, "ethiflink", 400, netif, 0, NULL); } static void AssertPhyReset(const bool reset) { HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, !reset); } static err_t low_level_output(struct netif *netif, struct pbuf *p) { uint32_t i = 0U; struct pbuf *q = NULL; ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT]; TxTimestampRecord_t new_timestamp_record; bool is_timestamp_requested = false; if (p->timestamp_sec == PTP_TIMESTAMP_RECORD_MAGIC) { is_timestamp_requested = true; } 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; // In the case of a ref pbuf, we need to clean the cache if the pbuf ref point // comes from a cached region of memory if (CacheTools_IsCachedRegion(q->payload)) { SCB_CleanDCache_by_Addr((uint32_t*)q->payload, CACHE_ALIGNED_SIZE(q->len)); } 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 = p; pbuf_ref(p); HAL_ETH_PTP_InsertTxTimestamp(&EthHandle); HAL_ETH_Transmit_IT(&EthHandle, &TxConfig); if (xSemaphoreTake(tx_semaphore, pdMS_TO_TICKS(10)) != pdTRUE) { HAL_ETH_ReleaseTxPacket(&EthHandle); return ERR_TIMEOUT; } HAL_ETH_ReleaseTxPacket(&EthHandle); if (is_timestamp_requested) { new_timestamp_record.timestamp.tv_sec = EthHandle.TxTimestamp.TimeStampHigh; new_timestamp_record.timestamp.tv_nsec = SubsecondToNanosecond(EthHandle.TxTimestamp.TimeStampLow); xQueueOverwrite(timestamp_queue, &new_timestamp_record); } return ERR_OK; } static struct pbuf * low_level_input(struct netif *netif) { struct pbuf *p = NULL; if(RxAllocStatus == RX_ALLOC_OK) { HAL_ETH_ReadData(&EthHandle, (void **)&p); } return p; } void ethernetif_input(void* argument) { struct pbuf *p; struct netif *netif = (struct netif *)argument; ETH_TimeStampTypeDef eth_timestamp; while (true) { if (xSemaphoreTake(rx_semaphore, pdMS_TO_TICKS(10)) == pdTRUE) { do { p = low_level_input(netif); if (p != NULL) { // Collect the timestamp of the new packet HAL_ETH_PTP_GetRxTimestamp(&EthHandle, ð_timestamp); p->timestamp_sec = eth_timestamp.TimeStampHigh; p->timestamp_nsec = SubsecondToNanosecond(eth_timestamp.TimeStampLow); if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } } } while (p != NULL); } if (ETH->DMACSR & ETH_DMACSR_RBU) { // Clear RBUS ETHERNET DMA flag ETH->DMACSR = ETH_DMACSR_RBU; // Resume DMA reception ETH->DMACRDTPR = 0; } if (ETH->DMACSR & ETH_DMACSR_TBU) { // Clear RBUS ETHERNET DMA flag ETH->DMACSR = ETH_DMACSR_TBU; // Resume DMA reception ETH->DMACTDTPR = 0; } } } err_t ethernetif_init(struct netif *netif) { const BoardIdentity_t* board_identity; const AppCodeBuildMeta_t* build_meta; LWIP_ASSERT("netif != NULL", (netif != NULL)); netif->hostname = "MyBoard"; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output; netif->linkoutput = low_level_output; /* initialize the hardware */ low_level_init(netif); return ERR_OK; } void pbuf_free_custom(struct pbuf *p) { BaseType_t woken = 0; struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p; LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf); if (RxAllocStatus == RX_ALLOC_ERROR) { RxAllocStatus = RX_ALLOC_OK; xSemaphoreGiveFromISR(rx_semaphore, &woken); } portYIELD_FROM_ISR(woken); } void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) { BaseType_t woken = 0; LOG_F("RX\r\n"); xSemaphoreGiveFromISR(rx_semaphore, &woken); portYIELD_FROM_ISR(woken); } void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) { BaseType_t woken = 0; xSemaphoreGiveFromISR(tx_semaphore, &woken); portYIELD_FROM_ISR(woken); } void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) { BaseType_t woken = 0; uint32_t error_flags; error_flags = HAL_ETH_GetDMAError(heth); LOG_F("Ex %lx\r\n", error_flags); if (error_flags & ETH_DMACSR_RBU) { LOG_F("RBU\r\n"); xSemaphoreGiveFromISR(rx_semaphore, &woken); } if (error_flags & ETH_DMACSR_TBU) { LOG_F("TBU\r\n"); xSemaphoreGiveFromISR(tx_semaphore, &woken); } portYIELD_FROM_ISR(woken); } int32_t ETH_PHY_IO_Init(void) { HAL_ETH_SetMDIOClockRange(&EthHandle); return 0; } int32_t ETH_PHY_IO_DeInit(void) { return 0; } int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal) { if (HAL_ETH_ReadPHYRegister(&EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK) { return -1; } return 0; } int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal) { if (HAL_ETH_WritePHYRegister(&EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK) { return -1; } return 0; } int32_t ETH_PHY_IO_GetTick(void) { return HAL_GetTick(); } static void EthernetLinkTask(void* argument) { ETH_MACConfigTypeDef MACConf = {0}; int32_t PHYLinkState = 0; bool linkchanged = false; uint32_t speed = 0; uint32_t duplex = 0; struct netif *netif = (struct netif *) argument; while (true) { PHYLinkState = LAN8742_GetLinkState(&LAN8742); LOCK_TCPIP_CORE(); if (netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN)) { LOG_W(TAG, "Link down"); HAL_ETH_Stop_IT(&EthHandle); netif_set_link_down(netif); } else if (!netif_is_link_up(netif) && PHYLinkState > LAN8742_STATUS_LINK_DOWN) { switch (PHYLinkState) { case LAN8742_STATUS_100MBITS_FULLDUPLEX: duplex = ETH_FULLDUPLEX_MODE; speed = ETH_SPEED_100M; linkchanged = true; break; case LAN8742_STATUS_100MBITS_HALFDUPLEX: duplex = ETH_HALFDUPLEX_MODE; speed = ETH_SPEED_100M; linkchanged = true; break; case LAN8742_STATUS_10MBITS_FULLDUPLEX: duplex = ETH_FULLDUPLEX_MODE; speed = ETH_SPEED_10M; linkchanged = true; break; case LAN8742_STATUS_10MBITS_HALFDUPLEX: duplex = ETH_HALFDUPLEX_MODE; speed = ETH_SPEED_10M; linkchanged = true; break; default: break; } if (linkchanged) { HAL_ETH_GetMACConfig(&EthHandle, &MACConf); MACConf.DuplexMode = duplex; MACConf.Speed = speed; HAL_ETH_SetMACConfig(&EthHandle, &MACConf); HAL_ETH_Start_IT(&EthHandle); netif_set_link_up(netif); LOG_W(TAG, "Link up"); } } UNLOCK_TCPIP_CORE(); vTaskDelay(pdMS_TO_TICKS(ETH_LINK_PERIOD_MS)); } } 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_BUFFER_SIZE); } else { RxAllocStatus = RX_ALLOC_ERROR; *buff = NULL; } } 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); } void HAL_ETH_TxFreeCallback(uint32_t * buff) { pbuf_free((struct pbuf *)buff); }