You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F407VEt6+DP83848适配uIP栈实现Ping及UDP通信求助

STM32F407VEt6 + DP83848 适配uIP栈的实现指导

问题背景

基于STM32F407VEt6开发以太网与上位机通信项目,此前使用LWIP栈存在首次启动失败、Ping成功率低的问题,计划改用轻量型uIP栈,但适配步骤不明确,且针对DP83848的适配资料极少,需要最简现成项目或具体步骤指导。

核心疑问

以太网底层数据发送如何实现?例如其他物理层芯片有enc28j60_send_packet((uint8_t *) uip_buf, uip_lan);这类专用发送函数,但DP83848没有,如何正确实现以太网帧的发送及初始化?

现有代码

int main(void)
{
    uip_ip4addr_t addrm;
    uip_ip4addr_t addrt;
    struct uip_udp_conn *c;
    uip_ipaddr(&addrt, 192,168,1,1);
    uip_ipaddr(&addrm, 1192,168,1,123); // 此处IP地址错误,应为192开头
    
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_ETH_Init();
    MX_TIM6_Init();
    hello_world_init();
    
    c = uip_udp_new(&addrt, HTONS(12345));
    uip_connect(&addrt, HTONS(12345));
    HAL_TIM_Base_Start_IT(&htim6);
 
    while (1)
    {
        uip_udp_conn = c;
        uip_appdata = &my_udp_buf;
        uip_udp_packet_send(c, uip_appdata, strlen(uip_appdata));
        uip_send(uip_appdata, my_udp_buf_len);
        uip_udp_packet_send(c,uip_appdata, 8);
        uip_udp_packet_sendto(c,uip_appdata, 8 , &addrm, 12345);
    }
}

void uip_udp_packet_sendto(struct uip_udp_conn *c, const void *data, int len,
                          const uip_ipaddr_t *toaddr, uint16_t toport)
{
    uip_ipaddr_t curaddr;
    uint16_t curport;

    if(toaddr != NULL) {
        /* Save current IP addr/port. */
        uip_ipaddr_copy(&curaddr, &c->ripaddr);
        curport = c->rport;

        /* Load new IP addr/port */
        uip_ipaddr_copy(&c->ripaddr, toaddr);
        c->rport = toport;

        uip_udp_packet_send(c, data, len);

        /* Restore old IP addr/port */
        uip_ipaddr_copy(&c->ripaddr, &curaddr);
        c->rport = curport;
    }
}

void uip_udp_packet_send(struct uip_udp_conn *c, const void *data, int len)
{ 
    if(data != NULL && len <= (UIP_BUFSIZE - (UIP_LLH_LEN + UIP_IPUDPH_LEN))) {
        uip_udp_conn = c;
        uip_len = len;
        memmove(&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN], data, len);
        uip_process(UIP_UDP_SEND_CONN);
    }
}

适配步骤与底层实现

1. 核心适配逻辑

STM32F4的ETH外设是MAC层,DP83848是PHY层,二者通过RMII接口通信,无需像SPI型PHY芯片那样的专用收发函数,而是通过STM32 ETH外设的DMA完成帧的收发,uIP栈只需对接ETH外设的HAL接口即可。

2. 初始化流程

  • CubeMX配置:
    • 选择ETH外设,接口类型设为RMII,PHY地址设为0x01(DP83848默认地址)
    • 配置RMII对应的GPIO引脚:REF_CLK、MDIO、MDC、CRS_DV、RXD0、RXD1、TX_EN、TXD0、TXD1
    • 开启ETH外设时钟,配置TIM6为定时中断(建议100ms周期,用于uIP的ARP维护、超时处理)
  • uIP栈初始化:
    在MX_ETH_Init()之后添加uIP初始化代码:
    uip_init();
    uip_ipaddr_t ipaddr, netmask, gw;
    uip_ipaddr(&ipaddr, 192, 168, 1, 123); // 本地IP
    uip_ipaddr(&netmask, 255, 255, 255, 0); // 子网掩码
    uip_ipaddr(&gw, 192, 168, 1, 1); // 网关
    uip_sethostaddr(&ipaddr);
    uip_setnetmask(&netmask);
    uip_setdraddr(&gw);
    uip_arp_init();
    

3. 底层发送实现

uIP处理完协议栈后,uip_buf中已包含完整的以太网帧(MAC头+IP头+UDP头+应用数据),只需调用STM32 HAL的ETH发送函数即可:

  • 修正uip_udp_packet_send函数,在uip_process之后添加发送逻辑:
    void uip_udp_packet_send(struct uip_udp_conn *c, const void *data, int len)
    { 
        if(data != NULL && len <= (UIP_BUFSIZE - (UIP_LLH_LEN + UIP_IPUDPH_LEN))) {
            uip_udp_conn = c;
            uip_len = len;
            memmove(&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN], data, len);
            uip_process(UIP_UDP_SEND_CONN);
            // 发送完整以太网帧:uip_len是应用层+IP+UDP长度,加上UIP_LLH_LEN(14字节)为总帧长
            HAL_ETH_Transmit(&heth, (uint8_t*)uip_buf, uip_len + UIP_LLH_LEN, HAL_MAX_DELAY);
        }
    }
    

4. 底层接收实现

在TIM6中断或主循环中轮询ETH接收状态,处理收到的帧:

// 示例:在TIM6中断回调函数中处理接收
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM6) {
        uint32_t frame_len = 0;
        // 检查是否有收到的帧
        if(HAL_ETH_GetReceivedFrame(&heth, &frame_len) == HAL_OK) {
            if(frame_len > 0 && frame_len <= UIP_BUFSIZE) {
                // 将帧数据读取到uip_buf
                HAL_ETH_ReadData(&heth, (uint8_t*)uip_buf, frame_len);
                // 交给uIP处理
                uip_input();
                // 如果处理后有需要发送的响应,调用发送
                if(uip_len > 0) {
                    HAL_ETH_Transmit(&heth, (uint8_t*)uip_buf, uip_len, HAL_MAX_DELAY);
                }
            }
        }
        // uIP定时处理(ARP超时、UDP超时等)
        uip_periodic(0);
        if(uip_len > 0) {
            HAL_ETH_Transmit(&heth, (uint8_t*)uip_buf, uip_len, HAL_MAX_DELAY);
        }
    }
}

代码修正建议

  • 修正main函数中的错误IP地址:uip_ipaddr(&addrm, 192,168,1,123)
  • 主循环中不要反复调用发送函数,会导致频繁发包,建议放在事件触发(如按键)或定时触发逻辑中
  • 确保my_udp_buf已正确初始化,且my_udp_buf_len为有效长度

内容的提问来源于stack exchange,提问作者Alleftinna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 21:15:53