RT-Thread论坛
直播中

hxjq

13年用户 927经验值
私信 关注
[问答]

stm32f407 以太网 长时间运行 modbustcp 数据,网络接口挂死怎么解决?

硬件配置:正点原子F407开发板
软件环境:env rtthread 5.2
问题描述:使用modbus slave tcp进行数据通信,长时间运行后,发现上位机客户端无法连接开发板,拔掉网线后,查看日志判断网络热插拔功能是正常的,

但是无法通知应用层接口(netif),使用ifconfig 查到网络的状态依然是linkup,

大概率是eth_rx_thread_entry线程出现了问题无法通知应用层状态,线程状态一直是running,但是具体原因无法锁定

重启设备后可恢复正常


回帖(1)

张秀兰

2025-9-15 17:50:18

针对STM32F407长时间运行Modbus TCP后网络接口挂死的问题,结合您的硬件环境和软件配置,以下是系统性的解决方案:


1. 检查驱动层中断处理


问题分析:  




  • 当以太网DMA接收中断未正常清除时,会导致后续中断被屏蔽,表现为eth_rx_thread线程持续运行但无数据流。


    解决方案:  



  • stm32xx_eth.c中断服务函数中强制清除未处理中断标志,添加以下代码:
     void ETH_IRQHandler(void)
    {
         // 原有逻辑...
         if (__HAL_ETH_DMA_GET_FLAG(&heth, ETH_DMA_FLAG_RBUS))
         {
             __HAL_ETH_DMA_CLEAR_FLAG(&heth, ETH_DMA_FLAG_RBUS);
             // 添加错误计数日志
             rt_kprintf("ETH DMA RBUS error detected! Cleared.n");
         }
         // 其他错误标志类似处理
    }

  • 确保所有中断标志(如接收错误ETH_DMA_FLAG_RE、总线错误ETH_DMA_FLAG_RBUS)被主动清除。


2. 优化接收线程稳健性


问题分析:  




  • eth_rx_thread线程可能因DMA描述符锁死导致永久阻塞。


    解决方案:  



  • 在接收线程中添加超时恢复机制,当长时间无数据时重启DMA:
     static void eth_rx_thread_entry(void *param)
    {
         while (1)
         {
             if (rt_sem_take(&rx_sem, RT_TICK_PER_SECOND * 5) == RT_EOK)
             {
                 // 正常处理数据
             }
             else
             {
                 // 超时处理:检查物理连接状态
                 if (phy_link_status() == PHY_LINK_UP)
                 {
                     rt_kprintf("ETH RX timeout! Restarting DMA.n");
                     HAL_ETH_Stop(&heth);
                     HAL_ETH_Start(&heth); // 重启DMA
                 }
             }
         }
    }


3. 修复PHY状态检测逻辑


问题分析:  




  • 网络热插拔日志正常但应用层无通知,表明PHY状态检测与LwIP联动失效。


    解决方案:  



  • 手动同步PHY状态到LwIP,在热插拔中断中调用:
     void phy_link_change_notify(void)
    {
         if (phy_link_status() == PHY_LINK_UP)
         {
             netif_set_link_up(netif_default);
             rt_kprintf("netif link UP notified.n");
         }
         else
         {
             netif_set_link_down(netif_default);
             rt_kprintf("netif link DOWN notified.n");
         }
    }


4. 防止内存泄漏


问题分析:  




  • LwIP的pbuf未正确释放会导致内存耗尽。


    解决方案:  



  • 在数据接收路径中严格检查pbuf释放
     err_t eth_arch_ethernetif_input(struct netif *netif)
    {
         struct pbuf *p;
         while ((p = low_level_input(netif)) != NULL)
         {
             if (netif->input(p, netif) != ERR_OK)
             {
                 pbuf_free(p); // 确保输入失败时释放pbuf
                 rt_kprintf("pbuf dropped!n");
             }
         }
    }


5. 启用硬件看门狗


配置步骤

在RT-Thread Env中开启硬件看门狗:


   CONFIG_BSP_USING_WDT=y


  • 在应用线程中定期喂狗(例如2秒):
     static void wdt_feed_thread(void *param)
    {
         rt_device_t wdt = rt_device_find("wdt");
         rt_device_init(wdt);
         while (1)
         {
             rt_device_control(wdt, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
             rt_thread_mdelay(2000);
         }
    }


6. 关键调试增强




  • 启用LwIP统计:在lwipopts.h中配置:


     #define LWIP_STATS 1
    #define LWIP_STATS_DISPLAY 1

    挂死后通过netstat()命令查看丢包统计。




  • Dump寄存器状态:挂死时通过调试器读取以下寄存器:


     ETH_DMASR  // DMA状态寄存器
    ETH_DMACTXDR // 发送描述符指针
    ETH_DMACRXDR // 接收描述符指针



7. 硬件稳定性措施



  • 在RMII接口的50MHz时钟线上串联22Ω电阻。

  • 调整PHY(如DP83848)的LED模式,禁用非必要闪烁:
     phy_write_reg(0x19, 0x4100); // 关闭LED闪烁


验证流程




  1. 压力测试

    使用iperf进行连续12小时带宽测试,观察是否出现挂死。


    iperf -s -u -i 60 # 开发板端
    iperf -c -u -b 10M -t 43200 # PC端



  2. 故障注入测试

    人工制造网络中断:


    ifconfig eth0 down
    sleep 10
    ifconfig eth0 up
    # 检查LwIP是否同步状态




关键提示:优先实施中断标志清除(方案1)和PHY状态同步(方案3),这两项修复可直接解决您描述的"应用层无通知"和"接收线程卡死"现象。硬件看门狗(方案5)作为最后保障机制防止系统彻底死锁。



通过以上方法综合处理,可显著提升以太网接口在Modbus TCP长运行下的稳定性。如问题仍出现,建议结合ETH_DMASR寄存器分析具体硬件错误类型。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分