#include "drv_eth.h" #include "lwip/opt.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/timeouts.h" #include "netif/etharp.h" #include "lwip/ethip6.h" #include "osal.h" #include /* Ethernet Handle */ ETH_HandleTypeDef heth; static uint32_t g_phy_address = 0; /* Stored PHY Address */ static uint32_t g_last_link_check_time = 0; /* 上次链接状态检测时间 */ static uint32_t g_link_check_interval = 1000; /* 链接状态检测间隔 (ms) */ static uint8_t g_link_state_stable = 0; /* 链接状态稳定性标志 */ static uint8_t g_link_state_counter = 0; /* 链接状态计数器,用于防抖 */ /* DMA Descriptors and Buffers */ /* 优化缓冲区对齐方式,提高内存访问效率 */ __attribute__((section(".RxDecripSection"))) __attribute__((aligned(32))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB]; __attribute__((section(".TxDecripSection"))) __attribute__((aligned(32))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB]; __attribute__((section(".RxArraySection"))) __attribute__((aligned(32))) uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; __attribute__((section(".TxArraySection"))) __attribute__((aligned(32))) uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* 缓冲区管理优化:可以根据实际网络流量调整缓冲区大小和数量 */ /* 建议值: * - 高流量场景:ETH_RXBUFNB = 8, ETH_TXBUFNB = 8 * - 低内存场景:ETH_RXBUFNB = 2, ETH_TXBUFNB = 2 */ /* Semaphore for Ethernet */ static osal_sem_t s_xSemaphore = NULL; /* 函数声明 */ static HAL_StatusTypeDef detect_and_configure_phy(void); static void configure_mac(ETH_MACConfigTypeDef *macConf); /* MSP Init - Implemented in board.c */ // void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) // { // (void)heth; // GPIO_InitTypeDef GPIO_InitStructure; // __HAL_RCC_GPIOA_CLK_ENABLE(); // __HAL_RCC_GPIOB_CLK_ENABLE(); // __HAL_RCC_GPIOC_CLK_ENABLE(); // __HAL_RCC_SYSCFG_CLK_ENABLE(); // __HAL_RCC_ETH_CLK_ENABLE(); // /* PA1, PA2, PA7 */ // GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; // GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; // GPIO_InitStructure.Pull = GPIO_NOPULL; // GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // GPIO_InitStructure.Alternate = GPIO_AF11_ETH; // HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // /* PC1, PC4, PC5 */ // GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; // HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); // /* PB11, PB12, PB13 */ // GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; // HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); // // HAL_NVIC_SetPriority(ETH_IRQn, 0x07, 0); // HAL_NVIC_EnableIRQ(ETH_IRQn); // } void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) { (void)heth; if (s_xSemaphore != NULL) { osal_sem_release(s_xSemaphore); } } void HAL_ETH_RxAllocateCallback(uint8_t **buff) { static int rx_idx = 0; *buff = Rx_Buff[rx_idx]; rx_idx = (rx_idx + 1) % ETH_RXBUFNB; } void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length) { (void)Length; *pStart = (void *)buff; *pEnd = (void *)buff; } void ETH_IRQHandler(void) { /* 直接调用 HAL 中断处理函数,不使用全局临界区 * HAL_ETH_IRQHandler 内部已经有适当的中断保护机制 */ HAL_ETH_IRQHandler(&heth); } /** * @brief 以太网硬件初始化函数 * @param netif: 网络接口结构体指针 * @return 无 * @note 负责初始化以太网硬件,包括MAC、DMA、PHY等 */ static void low_level_init(struct netif *netif) { /* Use a fixed MAC address to avoid conflicts/filtering */ uint8_t macaddress[6] = { 0x00, 0x80, 0xE1, 0x00, 0x00, 0x55 }; ETH_MACConfigTypeDef macConf; HAL_StatusTypeDef hal_eth_init_status; /* Generate MAC address from UID */ /* uint32_t uid0 = HAL_GetUIDw0(); uint32_t uid1 = HAL_GetUIDw1(); uint32_t uid2 = HAL_GetUIDw2(); macaddress[0] = 0x02; macaddress[1] = 0x80; macaddress[2] = 0xE1; macaddress[3] = (uid0 >> 16) & 0xFF; macaddress[4] = (uid1 >> 8) & 0xFF; macaddress[5] = uid2 & 0xFF; */ osal_log_i("MAC: %02x:%02x:%02x:%02x:%02x:%02x", macaddress[0], macaddress[1], macaddress[2], macaddress[3], macaddress[4], macaddress[5]); /* 初始化 ETH 句柄 */ heth.Instance = ETH; heth.Init.MACAddr = macaddress; heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; heth.Init.TxDesc = DMATxDscrTab; heth.Init.RxDesc = DMARxDscrTab; heth.Init.RxBuffLen = ETH_RX_BUF_SIZE; /* Initialize ETH (MAC, DMA, GPIOs via MSP) first to enable MDC/MDIO */ hal_eth_init_status = HAL_ETH_Init(&heth); if (hal_eth_init_status == HAL_OK) { /* 检测并配置 PHY */ if (detect_and_configure_phy() == HAL_OK) { netif->flags |= NETIF_FLAG_LINK_UP; } } else { osal_log_e("HAL_ETH_Init failed"); } /* 配置 MAC */ configure_mac(&macConf); /* Enable Promiscuous Mode manually as it's not in the struct */ heth.Instance->MACFFR |= ETH_MACFFR_PM; /* 启动 ETH 中断 */ HAL_ETH_Start_IT(&heth); /* 创建信号量 */ s_xSemaphore = osal_sem_create("eth_sem", 0); /* 配置网络接口 */ netif->hwaddr_len = 6; memcpy(netif->hwaddr, macaddress, 6); netif->mtu = 1500; netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; #if LWIP_IPV6 netif->flags |= NETIF_FLAG_IGMP; #endif } /** * @brief 检测并配置 PHY * @return HAL_StatusTypeDef: 操作结果 * @note 负责检测 PHY 地址并进行配置 */ static HAL_StatusTypeDef detect_and_configure_phy(void) { uint32_t phy_id1 = 0, phy_id2 = 0; uint8_t detected_phy_addr = 0xFF; /* Invalid initial value */ uint32_t regvalue; /* Step 1: PHY address detection */ osal_log_i("Detecting PHY Address..."); /* 优先检查常见的 PHY 地址,减少遍历次数 */ uint8_t common_phy_addresses[] = {0, 1, 2, 3, 16, 17, 18, 19, 20}; uint8_t common_phy_count = sizeof(common_phy_addresses) / sizeof(common_phy_addresses[0]); /* 先检查常见地址 */ for(uint8_t i = 0; i < common_phy_count; i++) { uint8_t addr = common_phy_addresses[i]; /* Read PHY ID registers (typically Reg 2 and 3) */ if(HAL_ETH_ReadPHYRegister(&heth, addr, 2, &phy_id1) == HAL_OK && HAL_ETH_ReadPHYRegister(&heth, addr, 3, &phy_id2) == HAL_OK) { if((phy_id1 != 0xFFFF) && (phy_id1 != 0x0000) && (phy_id1 != 0)) { detected_phy_addr = addr; osal_log_i("Found PHY at Address %d (ID: %04x %04x)", addr, phy_id1, phy_id2); goto phy_found; } } } /* 如果常见地址没找到,再遍历所有可能的地址 */ for(uint8_t addr = 0; addr <= 31; addr++) { /* 跳过已经检查过的常见地址 */ uint8_t skip = 0; for(uint8_t i = 0; i < common_phy_count; i++) { if(addr == common_phy_addresses[i]) { skip = 1; break; } } if(skip) continue; /* Read PHY ID registers (typically Reg 2 and 3) */ if(HAL_ETH_ReadPHYRegister(&heth, addr, 2, &phy_id1) == HAL_OK && HAL_ETH_ReadPHYRegister(&heth, addr, 3, &phy_id2) == HAL_OK) { if((phy_id1 != 0xFFFF) && (phy_id1 != 0x0000) && (phy_id1 != 0)) { detected_phy_addr = addr; osal_log_i("Found PHY at Address %d (ID: %04x %04x)", addr, phy_id1, phy_id2); goto phy_found; } } } phy_found: if (detected_phy_addr != 0xFF) { g_phy_address = detected_phy_addr; /* Step 2: PHY Soft Reset */ osal_log_i("Resetting PHY..."); /* Write Reset Bit */ HAL_ETH_WritePHYRegister(&heth, g_phy_address, PHY_BCR, PHY_RESET); /* Wait for Reset to clear */ uint32_t tickstart = osal_tick_get(); uint32_t reset_timeout = 200; // 优化为 200ms 超时 do { HAL_ETH_ReadPHYRegister(&heth, g_phy_address, PHY_BCR, ®value); if((regvalue & PHY_RESET) == 0) break; } while ((osal_tick_get() - tickstart) < reset_timeout); // 200ms timeout /* Add a delay to ensure PHY is stable */ osal_thread_mdelay(50); // 优化为 50ms 延迟 return HAL_OK; } else { osal_log_e("No PHY found!"); return HAL_ERROR; } } /** * @brief 配置 MAC * @param macConf: MAC 配置结构体指针 * @return 无 * @note 负责配置 MAC 的双工模式、速度和校验和等 */ static void configure_mac(ETH_MACConfigTypeDef *macConf) { HAL_ETH_GetMACConfig(&heth, macConf); macConf->DuplexMode = ETH_FULLDUPLEX_MODE; macConf->Speed = ETH_SPEED_100M; macConf->ChecksumOffload = ENABLE; /* Enable HW Checksum */ HAL_ETH_SetMACConfig(&heth, macConf); } static err_t low_level_output(struct netif *netif, struct pbuf *p) { (void)netif; err_t errval; struct pbuf *q; ETH_TxPacketConfigTypeDef txConfig; ETH_BufferTypeDef txBuffers[16]; memset(&txConfig, 0, sizeof(ETH_TxPacketConfigTypeDef)); /* Enable Hardware Checksum Insertion */ 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; int i = 0; for(q = p; q != NULL; q = q->next) { if (i >= 16) break; txBuffers[i].buffer = (uint8_t*)q->payload; txBuffers[i].len = q->len; if (q->next != NULL) { txBuffers[i].next = &txBuffers[i+1]; } else { txBuffers[i].next = NULL; } i++; } txConfig.Length = p->tot_len; txConfig.TxBuffer = &txBuffers[0]; if (HAL_ETH_Transmit(&heth, &txConfig, 10) == HAL_OK) { errval = ERR_OK; } else { errval = ERR_IF; } return errval; } static struct pbuf * low_level_input(struct netif *netif) { (void)netif; struct pbuf *p = NULL; uint8_t *buffer = NULL; uint32_t rxLength = 0; if (HAL_ETH_ReadData(&heth, (void**)&buffer) == HAL_OK) { rxLength = heth.RxDescList.RxDataLength; // osal_log_i("Rx: rxLength=%d", rxLength); if (rxLength > 0 && buffer != NULL) { /* 尝试使用 PBUF_REF 模式创建 pbuf,实现零拷贝 * 注意:需要确保缓冲区在 pbuf 使用期间有效 */ p = pbuf_alloc(PBUF_RAW, rxLength, PBUF_REF); if (p != NULL) { /* 直接设置 pbuf 的 payload 指针,避免数据拷贝 */ p->payload = buffer; p->len = rxLength; p->tot_len = rxLength; // osal_log_i("Rx: p->tot_len=%d", p->tot_len); } else { /* 如果 PBUF_REF 失败,回退到传统方式 */ p = pbuf_alloc(PBUF_RAW, rxLength, PBUF_POOL); if (p != NULL) { pbuf_take(p, buffer, rxLength); } else { osal_log_e("pbuf_alloc failed"); } } /* HAL_ETH_ReadData internally calls ETH_UpdateDescriptor, so descriptors are rebuilt automatically */ } } else { /* ReadData failed, maybe no data available */ } return p; } void ethernetif_input(struct netif *netif) { struct pbuf *p; if (s_xSemaphore == NULL) { osal_thread_mdelay(100); return; } if (osal_sem_take(s_xSemaphore, 100) == OSAL_OK) { do { p = low_level_input(netif); if (p != NULL) { // osal_log_i("Rx: len=%d", p->tot_len); // Debug print if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } } } while(p != NULL); } } err_t ethernetif_init(struct netif *netif) { LWIP_ASSERT("netif != NULL", (netif != NULL)); #if LWIP_NETIF_HOSTNAME netif->hostname = "lwip"; #endif netif->name[0] = 'e'; netif->name[1] = 't'; netif->output = etharp_output; netif->linkoutput = low_level_output; low_level_init(netif); return ERR_OK; } void ethernet_link_check_state(struct netif *netif) { uint32_t regvalue = 0; uint32_t current_time = osal_tick_get(); /* 实现时间间隔控制,减少 PHY 寄存器读取 */ if ((current_time - g_last_link_check_time) < g_link_check_interval) { return; } g_last_link_check_time = current_time; /* Use configured PHY Address */ HAL_ETH_ReadPHYRegister(&heth, g_phy_address, PHY_BSR, ®value); if ((regvalue & PHY_LINKED_STATUS) != (uint16_t)RESET) { /* 链接状态防抖 */ g_link_state_counter++; if (g_link_state_counter >= 3) /* 连续 3 次检测到链接状态为 up */ { if (!netif_is_link_up(netif)) { netif_set_link_up(netif); osal_log_i("Ethernet Link Up"); } g_link_state_stable = 1; } } else { /* 链接状态防抖 */ g_link_state_counter--; if (g_link_state_counter <= 0) /* 连续 3 次检测到链接状态为 down */ { g_link_state_counter = 0; if (netif_is_link_up(netif)) { netif_set_link_down(netif); osal_log_i("Ethernet Link Down"); } g_link_state_stable = 0; } } }