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

Raspberry Pi Pico+ENC28J60+lwIP跨路由TCP无法连接求助

排查Raspberry Pi Pico+ENC28J60跨路由器TCP连接失败问题

环境说明

  • 硬件:Raspberry Pi Pico 通过SPI接口连接ENC28J60网卡
  • 软件:2023-11-29版本pico-sdk、同日获取的pico-enc28j60库;因lwIP从Pico Extras迁移至Pico SDK,已修改项目CMakeLists.txt

初始化代码

static bool ethernet_init()
{
    err_t err;

    lwip_init();
    queue_init( &R.rx_queue, sizeof(struct pbuf *), ENC28J60_RX_QUEUE_SIZE );
    critical_section_init( &R.spi_cs );

    // initialize modbus clients
    for( int i=0; i<MODBUS_CLIENTS_MAX; i++ )
    {
        R.modbus_clients[i].tcp = 0;
        R.modbus_clients[i].state = ST_UNUSED;
        R.modbus_clients[i].seq_nr = (i << 12) | ((i << 8) ^ 0x0F00);
    }

    R.enc28j60.spi = spi1;
    R.enc28j60.cs_pin = SPI1_CSn_PIN;
    R.enc28j60.mac_address[0] = R.cfg.mac_addr[0];
    R.enc28j60.mac_address[1] = R.cfg.mac_addr[1];
    R.enc28j60.mac_address[2] = R.cfg.mac_addr[2];
    R.enc28j60.mac_address[3] = R.cfg.mac_addr[3];
    R.enc28j60.mac_address[4] = R.cfg.mac_addr[4];
    R.enc28j60.mac_address[5] = R.cfg.mac_addr[5];
    R.enc28j60.next_packet = 0;
    R.enc28j60.critical_section = &R.spi_cs;
    R.netif.name[0] = 'e';
    R.netif.name[1] = 'n';

    gpio_set_function( SPI1_SCK_PIN, GPIO_FUNC_SPI );
    gpio_set_function( SPI1_MOSI_PIN, GPIO_FUNC_SPI );
    gpio_set_function( SPI1_MISO_PIN, GPIO_FUNC_SPI );
    gpio_init( SPI1_CSn_PIN );
    gpio_put( SPI1_CSn_PIN, true );
    gpio_set_dir( SPI1_CSn_PIN, true );
    gpio_init( ETH_INT_PIN );
    gpio_init( ETH_RST_PIN );
    // reset the chip
    gpio_put( ETH_RST_PIN, false );
    gpio_set_dir( ETH_RST_PIN, true );
    sleep_ms( 1 );
    gpio_put( ETH_RST_PIN, true );
    spi_init( R.enc28j60.spi, SPI1_SPEED );

    netif_add( &R.netif, &R.cfg.ip_addr, &R.cfg.netmask, &R.cfg.gateway,
            &R.enc28j60, ethernetif_init, netif_input );
    netif_set_up( &R.netif );
    netif_set_link_up( &R.netif ); // +++ should check the enc if the link is up

    gpio_set_irq_enabled_with_callback( ETH_INT_PIN, GPIO_IRQ_EDGE_FALL,
                true, eth_irq );
    enc28j60_interrupts( &R.enc28j60,
                ENC28J60_PKTIE | ENC28J60_TXERIE | ENC28J60_RXERIE );

    R.tcp_modbus = tcp_new_ip_type( IPADDR_TYPE_V4 );
    err = tcp_bind( R.tcp_modbus, IP4_ADDR_ANY, TCP_PORT_MODBUS );
    if( err != ERR_OK )
    {
        return false;
    }
    R.tcp_modbus = tcp_listen_with_backlog( R.tcp_modbus, BACKLOG_MODBUS );
    if( !R.tcp_modbus )
    {
        return false;
    }
    tcp_accept( R.tcp_modbus, modbus_accept );
    return true;
}

问题描述

本地直连电脑与Pico时,网络功能完全正常:可ping通设备,能正常建立TCP连接并进行Modbus查询。但在电脑与Pico之间加入路由器后,出现异常:

  • ping仍能正常通
  • TCP无法建立连接:抓包可见电脑发送的SYN包已到达Pico所在网络,但Pico无SYN/ACK响应,modbus_accept回调函数从未被调用

怀疑问题出在自身代码或lwIP配置中,求排查线索。

排查线索

1. lwIP核心配置检查

  • 确认lwipopts.h中TCP_MSS设置:路由器环境下MTU可能存在限制,建议将TCP_MSS设为1460(标准以太网MTU 1500减去IP+TCP头部40字节),避免因MSS过大导致SYN/ACK被丢弃。同时检查IP_FRAG是否开启,确保分片包能被正确处理。
  • 检查TCP超时与队列参数:确认TCP_SYNACK_DELAY、TCP_LISTEN_BACKLOG是否合理,BACKLOG_MODBUS值需与lwIP配置的TCP_LISTEN_BACKLOG匹配,防止连接队列溢出。

2. 网络链路与ARP缓存验证

  • 替换硬编码的netif_set_link_up:当前代码直接标记链路为up,需改为读取ENC28J60的PHY状态(调用enc28j60_phy_read读取PHCON1寄存器),确认物理链路真的连通后再设置链路up。
  • 检查ARP缓存有效性:在路由器环境下,Pico可能未正确获取电脑或路由器的MAC地址。添加ARP缓存调试输出,确认目标IP对应的MAC是否存在,必要时手动触发ARP请求(比如提前ping电脑)。

3. 中断与数据包接收逻辑排查

  • 验证ETH_INT中断触发:在eth_irq回调中添加调试动作(如LED闪烁),确认SYN包到达时中断是否被触发,排除中断电平配置错误或硬件干扰导致的中断丢失。
  • 检查RX队列状态:若ENC28J60_RX_QUEUE_SIZE过小,路由器环境下的广播包、ARP包可能占满队列,导致SYN包无法被处理。增大队列大小,并添加队列溢出检测逻辑。
  • 确认ethernetif_input函数正确性:检查该函数是否将接收到的pbuf完整传递给netif_input,是否存在丢包或错误处理逻辑导致SYN包被丢弃。

4. TCP监听逻辑验证

  • 尝试绑定具体IP而非IP4_ADDR_ANY:若Pico存在多IP配置(如静态IP+DHCP),IP4_ADDR_ANY可能未绑定到路由器分配的有效IP上,改为绑定Pico的实际局域网IP再测试。
  • 检查TCP监听PCB的正确性:代码中tcp_listen_with_backlog会返回新的PCB并覆盖R.tcp_modbus,需确认新PCB未被错误释放,且tcp_accept回调已正确注册到该PCB上。

5. 抓包与调试输出

  • 在路由器LAN端口抓包:确认SYN包是否真的转发到Pico,以及Pico是否发出SYN/ACK(可能被路由器ACL规则过滤)。
  • 开启lwIP调试:打开LWIP_DEBUG、TCP_DEBUG等宏,输出TCP层状态变化,确认SYN包是否被lwIP接收,以及是否尝试生成SYN/ACK响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:38:13