RT-Thread论坛
直播中

HTSX

11年用户 894经验值
擅长:可编程逻辑
私信 关注
[问答]

studio建立f429工程使用 lwip运行错误的原因?

1.studio建立f429工程使能 lwip ,按照 board.h 文件中的描述添加了 eth 驱动,RMII 模式 phy为lan8720, 运行时出现 tcpip 线程崩溃,调节了 tcpip线程栈大小还是崩溃,一直没找到原因



2.如果同时使能 lwip 和 at(4G) ,应用程序中该如何切换 网卡 呢?


回帖(1)

艾玛

2025-9-23 17:00:24

问题1:LwIP 运行 TCPIP 线程崩溃的可能原因及解决方案


常见原因分析:




  1. 内存不足(最常见)



    • LwIP 的缓冲区(PBUF)或堆内存不足

    • 线程栈溢出(即使调整后仍可能不足)




  2. PHY 初始化问题



    • LAN8720 复位/配置时序不符合要求

    • RMII 时钟未稳定(需 50MHz 参考时钟)

    • PHY 地址错误(默认地址 0/1,需与硬件匹配)




  3. 中断冲突



    • 以太网中断(ETH_IRQHandler)与其他高优先级中断冲突

    • 未及时处理接收中断导致数据溢出




  4. 时钟配置错误



    • HCLK 时钟未配置为 180MHz(F429 以太网要求)

    • RMII 参考时钟未启用(通过 HAL_ETH_SetMDIOClockRange() 检查)




  5. 驱动适配层问题



    • ethernetif.c 中的底层驱动未正确移植

    • 接收/发送函数未正确处理






逐步排查方案:


步骤1:确认内存配置

// lwipopts.h
#define MEM_SIZE (16 * 1024)  // 至少 12KB 推荐 16KB
#define PBUF_POOL_SIZE 16     // 推荐值
#define PBUF_POOL_BUFSIZE 1536 // 必须 ≥1528
#define TCP_WND (4 * TCP_MSS) // 减小TCP窗口节省内存

// 启动文件 (startup_stm32f429xx.s)
Heap_Size EQU 0x1000 → 0x2000  // 增大堆空间

步骤2:检查 LAN8720 初始化

// board.h 确认配置
#define ETH_PHY_ADDR     0x01     // 根据硬件调整(0/1)
#define ETH_PHY_LAN8720  1
#define ETH_PHY_RMII     1

// 添加硬件复位代码(在初始化前)
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET); // 假设PE2控制复位
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE, GPIO_PING_2, GPIO_PIN_SET);
HAL_Delay(100);

步骤3:验证时序和时钟

// main.c 中时钟检查
SystemClock_Config();
// 确认输出:
// - HCLK = 180MHz
// - RMII_REF_CLK = 50MHz (来自PHY或MCU)

// 启用时钟范围配置
__HAL_RCC_ETH_CLK_ENABLE();
HAL_ETH_SetMDIOClockRange(&heth);

步骤4:调试线程配置

// FreeRTOSConfig.h
#define configTOTAL_HEAP_SIZE  (30 * 1024) // ≥30KB

// tcpip_thread 栈大小调整(至少 1.5KB)
#define TCPIP_THREAD_STACKSIZE 1536

步骤5:启用 LwIP 调试

// lwipopts.h
#define LWIP_DEBUG 1
#define ETHARP_DEBUG LWIP_DBG_ON
#define NETIF_DEBUG LWIP_DBG_ON
#define PBUF_DEBUG LWIP_DBG_ON



问题2:LwIP 与 AT(4G) 双网卡切换方案


核心步骤:




  1. 初始化双网卡接口



    • 以太网接口:netif_add(ð_netif, ...)

    • 4G 接口:netif_add(&at_netif, ...) (需实现 PPPoS 或自定义驱动)




  2. 设置默认网卡


    netif_set_default(ð_netif); // 默认使用以太网



  3. 动态切换 API


    // 切换到4G
    netif_set_default(&at_netif);
    netif_set_link_up(&at_netif);

    // 切换回以太网
    netif_set_default(ð_netif);
    netif_set_link_up(ð_netif);



  4. 指定网卡发送数据


    // 创建PCB时绑定网卡
    struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
    tcp_bind_netif(pcb, &at_netif); // 绑定到4G

    // UDP同理
    udp_bind_netif(upcb, ð_netif);



完整示例代码:


// 定义双网卡
struct netif eth_netif; // 以太网
struct netif ppp_netif; // 4G-PPP

// 初始化以太网
netif_add(ð_netif, &ipaddr, &netmask, &gw, NULL, ðernet_init, &tcpip_input);
netif_set_up(ð_netif);

// 初始化4G(PPP示例)
ppp_netif = ppp_netif_init(&ppp_settings,
                           ppp_link_status_cb, // 状态回调
                           NULL);

// 网卡切换函数
void switch_to_4g(void) {
    netif_set_default(&ppp_netif);
    netif_set_up(&ppp_netif);
    printf("切换到4G网络n");
}

// 链路状态回调(自动切换)
void ppp_link_status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
    if(err_code == PPPERR_NONE) { // 4G连接成功
        netif_set_default(&ppp_netif);
    } else if(netif_is_up(ð_netif)) { // 回退到以太网
        netif_set_default(ð_netif);
    }
}

关键配置:




  1. LwIP 多网卡支持


    // lwipopts.h
    #define LWIP_NUM_NETIF_CLIENT_DATA 1 // 启用多网卡
    #define LWIP_NETIF_STATUS_CALLBACK 1 // 启用状态回调



  2. 路由表管理(可选)


    // 添加静态路由
    ip4_addr_t target;
    IP4_ADDR(&target, 192, 168, 10, 0);
    netif_add_route(&target, 24, &ppp_netif); // 指定目标走4G




注意:使用 AT 模块时:



  • 需实现 PPP 协议栈(通过 pppos.c

  • 或自定义 netif->input/output 驱动

  • 推荐使用 LwIP PPPoS 方案



通过上述方案,可实现基于网络状态(如断开事件)或手动命令的动态网卡切换。

举报

更多回帖

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