STM32+LWIP实现ping功能问题

LWIP使用问题,在STM32F407上移植FreeRTOS+LWIP后,利用ICMP实现PING外部设备的功能。如果将校验模式设为硬件校验方式,在PC上ping设备能ping通,但是设备pingPC则ping不通,如果使用软件校验方式则能双向ping通。求答疑解惑。

硬件平台:STM32F407ZGT6+LAN8720A

以下是使用硬件校验的代码:

lwipopts.h中Checksum配置

/*
    --------------------------------------
    ---------- Checksum options ----------
    --------------------------------------
*/

/*
 * The STM32F4xx allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
 * - To use this feature let the following define uncommented.
 * - To disable it and process by CPU comment the  the checksum.
 */
#define CHECKSUM_BY_HARDWARE 


#ifdef CHECKSUM_BY_HARDWARE
  /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
#define CHECKSUM_GEN_IP                 0
/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP                0
/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP                0 
/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
#define CHECKSUM_CHECK_IP               0
/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP              0
/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP              0
/* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/
#define CHECKSUM_GEN_ICMP               0

#else
  /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
#define CHECKSUM_GEN_IP                 1
/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP                1
/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP                1
/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
#define CHECKSUM_CHECK_IP               1
/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP              1
/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP              1
/* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/
#define CHECKSUM_GEN_ICMP               1
#endif

STM32_ETH初始化代码:

/**
  * @brief In this function, the hardware should be initialized.
  * Called from ethernetif_init().
  *
  * @param netif the already initialized lwip network interface structure
  *        for this ethernetif
  */
static err_t low_level_init(struct netif *netif)
{
    uint8_t MACAddr[6] = { MAC_ADDR0, MAC_ADDR1, MAC_ADDR2, MAC_ADDR3, MAC_ADDR4, MAC_ADDR5 };

    HAL_ETH_DeInit(&EthHandle);

    eth_phy_reeset();

    ETH->DMABMR |= ETH_DMABMR_SR;
    
    EthHandle.Instance = ETH;
    EthHandle.Init.MACAddr = &MACAddr[0];
    EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
    EthHandle.Init.Speed = ETH_SPEED_100M;
    EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
    EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
    EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE; 
    EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
    //EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
    EthHandle.Init.PhyAddress = LAN8720A_PHY_ADDRESS;

    /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
    if (HAL_ETH_Init(&EthHandle) != HAL_OK)
    {
        logError("ETH init failed\r\n");
        return -1;
    }
    
    /* Set netif link flag */
    netif->flags |= NETIF_FLAG_LINK_UP;    

    /* Initialize Tx Descriptors list: Chain Mode */
    HAL_ETH_DMATxDescListInit(&EthHandle, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
        
    /* Initialize Rx Descriptors list: Chain Mode  */
    HAL_ETH_DMARxDescListInit(&EthHandle, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);

    /* set netif MAC hardware address length */
    netif->hwaddr_len = ETH_HWADDR_LEN;

    /* set netif MAC hardware address */
    netif->hwaddr[0] =  MAC_ADDR0;
    netif->hwaddr[1] =  MAC_ADDR1;
    netif->hwaddr[2] =  MAC_ADDR2;
    netif->hwaddr[3] =  MAC_ADDR3;
    netif->hwaddr[4] =  MAC_ADDR4;
    netif->hwaddr[5] =  MAC_ADDR5;

    /* set netif maximum transfer unit */
    // netif->mtu = 1500;    
    netif->mtu = ETH_MAX_PACKET_SIZE;
    
    /* Accept broadcast address and ARP traffic */
    netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;

    /* create a binary semaphore used for informing ethernetif of frame reception */
    xSemaphore = xSemaphoreCreateBinary();

    /* create the task that handles the ETH_MAC */
    if (xTaskCreate(ethernetif_input, "EthInput", INTERFACE_THREAD_STACK_SIZE, netif, 10, NULL) != pdPASS)
    {
        logError("create Ethif task failed\r\n");
        HAL_ETH_DeInit(&EthHandle);
        return -1;
    }

    /* Enable MAC and DMA transmission and reception */
    if (HAL_ETH_Start(&EthHandle) != HAL_OK)
    {
        logError("ETH start failed\r\n");
        HAL_ETH_DeInit(&EthHandle);
        return -1;
    }

    return 0;
}

以上配置在运行时,如果在PC端ping设备,没有问题,如果在设备上pingPC则超时。根据wireshark抓包的结果来看,PC端并未收到设备发送的ICMP报文,不知道是哪个环节出了问题。
如果将以上配置中CHECKSUM_BY_HARDWARE注释掉,LWIP使用软件校验,且ETH初始化时配置为EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE,设备和PC就能双向ping通了。
烦请了解的朋友解答一下出现上述问题的原因,不胜感激。

这个我遇到过,大概知道点,部分芯片有个小小的bug,就是ICMP要使用硬件校验和的话,需要把校验和预先填成0.
但是我遇到的情况和你的不一样,就是PC能抓到包,只是校验和错误。有一种可能是你的电脑网卡硬件上直接过滤掉了,如果网卡的高级设置里可以暂时关掉硬件校验和,暂时关掉一下试试看。