全部例程

W6300 使用 SOCKET-less 指令实现 ping 功能

W6300

更新于 2026年10月10日

本篇总结

基于 W6300 的 SOCKET-less Command(SLCR)PING4 指令实现 ping 功能,通过 SLIR 判断结果,并统计请求、回复与丢包数量。

🔑 MH2457、QSPI、UART调试、硬件TOE引擎、PING、SOCKET-less

硬件平台:本例程基于 W6300-EVB-M4 开发板运行。

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W6300-EVB-M4 开发板

本示例演示如何在 W6300 芯片上使用 SOCKET-less Command(SLCR)实现 PING 功能。W6300 的 TOE 引擎内置了 PING4 指令,可以直接通过写 SLCR 寄存器触发一次 IPv4 ping 请求,ICMP 报文的构造、校验和计算、收发处理全部由硬件完成,结果通过 SLIR 寄存器判断。例程通过 do_ping() 控制流程,ping_run() 驱动状态机,完成多次 PING 请求与结果统计。

前置工具准备

开始本例程前,请确认以下工具已安装:

PING 免套接字指令简介

PING(Packet Internet Groper)是基于 ICMP 协议的网络连通性测试命令,通过发送"回显请求"(Echo Request)并等待"回显应答"(Echo Reply)来检查目标主机是否可达及网络响应时间。W6300 的 TOE 引擎内置了 SOCKET-less Command(SLCR),可以不占用任何 Socket 资源,直接通过寄存器触发 PING、ARP、NS、RS 等网络层报文。

PING4 指令相关寄存器如下:

寄存器说明
SLDIPRSOCKET-less Destination IPv4 Address Register,设置 PING 目标 IPv4 地址
PINGIDRPING ID Register,设置 PING 请求报文的标识符
PINGSEQRPING Sequence-number Register,设置 PING 请求报文的序列号(不会自动增加)
SLCRSOCKET-less Command Register,写入 PING4 位触发 PING 请求;命令完成后自动清 0,未完成前不能执行新命令
SLIRSOCKET-less Interrupt Register,PING4 位表示收到 PING Reply,TOUT 位表示重传超时
SLIRCLRSLIR Clear Register,写 1 清除对应中断位
SLRTR / SLRCRSOCKET-less Retransmission Time/Count Register,控制重传时间(100us 单位)与重传次数,超过次数则 SLIR[TOUT] 置位

W6300 的优势

W6300 的 TOE 引擎原生支持 PING4 免套接字指令,ICMP 报文的构造、校验和计算、收发处理全部由硬件完成。用户只需通过寄存器配置目标地址、PING ID 和序列号,触发 SLCR[PING4] 后轮询 SLIR 结果即可。相比手动构造 ICMP 报文,代码更简洁,不占用 Socket 资源,可靠性更高。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W6300 处于同一网段。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
  3. 确保 W6300 与 MH2457 之间的 QSPI 连线正确(CSn、SCK、DATA0~DATA3)
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W6300 │ │ PC │
│ SLCR Ping │ │ CMD Ping │
│ IP: DHCP │ │ IP: DHCP │
└────┬──────┘ └───────────┘
│ QSPI ↑
┌────┴──────┐ DEBUG USB
│ MH2457 │─────→ WIZ UartTool
│ MCU │
└───────────┘
网络拓扑:开发板与 PC 在同一局域网内,通过路由器互通,MH2457 通过 QSPI 驱动 W6300

工程结构

工程核心文件如下:

Project/
├── main.c                    ← 系统入口:串口、GPIO、QSPI 初始化 + user_run()
└── USER/
    ├── user_main.c           ← 网络地址定义 + PING 目标 + user_run() 主流程
    ├── ping.c                ← PING 状态机核心(do_ping / ping_run / ping_init)
    ├── ping.h
    ├── wiz_platform.c/h      ← 平台适配:debug_usart_init、wizchip_gpio_init、hspi_init
    └── wiz_interface.c/h     ← W6300 驱动接口:wizchip_initialize、network_init、PHY 检测、软件定时器

本例程的核心:通过 SLCR[PING4] 免套接字指令触发 ping,轮询 SLIR 判断结果。PING 状态机在 ping_run() 中运行,通过 do_ping() 完成一次性初始化。

步骤1:主循环调用

文件:USER/user_main.c。在主循环中调用 do_ping() 函数,传入 Socket 号、目标主机 IP 和 PING 请求次数。

uint8_t dest_ip[4] = {192, 168, 1, 20};
uint8_t ping_num = 4;

while (1)
{
    do_ping(SOCKET_ID, dest_ip, ping_num);
}

do_ping() 函数起到了控制 PING 操作流程的作用,首次调用完成一次性初始化(设置目标 IP、标识符、超时参数等),之后每次调用运行 ping_run() 状态机,直到完成指定的请求次数。

步骤2:do_ping() 流程控制

文件:USER/ping.c。首次调用时进行一次性初始化,之后每次调用运行 ping_run() 状态机。

void do_ping(uint8_t sn, uint8_t *remote_ip, uint8_t req_num)
{
    ping_config_t config;

    (void)sn;

    if (s_ping_compat_initialized == 0U)
    {
        if ((remote_ip == NULL) || (req_num == 0U))
        {
            return;
        }

        memset(&config, 0, sizeof(config));
        config.target_use_gateway = 0U;
        memcpy(config.target_ip, remote_ip, sizeof(config.target_ip));
        config.id = 0x1234U;
        config.interval_ms = 3000U;
        config.command_timeout_ms = 100U;
        config.response_timeout_ms = 5000U;

        s_ping_request_limit = req_num;
        s_ping_completed_count = 0U;
        s_ping_reply_count = 0U;

        if (ping_init(&config) < 0)
        {
            return;
        }

        s_ping_compat_initialized = 1U;
    }

    ping_run();
}

do_ping() 首次调用时根据传入的目标 IP 和请求次数构造 ping_config_t 配置,调用 ping_init() 完成初始化;之后每次调用 ping_run() 驱动状态机。PING 序列完成后由状态机内部打印统计信息。

步骤3:ping_run() 状态机

文件:USER/ping.c。PING 操作的核心状态机:IDLE 状态下按间隔触发 ping,WAIT_COMMAND 等待 SLCR 命令完成,WAIT_RESULT 轮询 SLIR 判断结果。

void ping_run(void)
{
    uint32_t now = wiz_platform_get_tick();
    uint8_t slir;

    switch (s_ping_state)
    {
        case PING_STATE_IDLE:
            if ((uint32_t)(now - s_ping_state_tick) >= s_ping_config.interval_ms)
            {
                ping_start(now);
            }
            break;

        case PING_STATE_WAIT_COMMAND:
            if (getSLCR() == 0U)
            {
                s_ping_state = PING_STATE_WAIT_RESULT;
            }
            else if ((uint32_t)(now - s_ping_request_tick) >= s_ping_config.command_timeout_ms)
            {
                printf("PING command: timeout\r\n");
                ping_finish_cycle(now, 0U);
            }
            break;

        case PING_STATE_WAIT_RESULT:
            slir = getSLIR();

            if ((slir & SLIR_PING4) != 0U)
            {
                printf("PING reply: %u.%u.%u.%u, seq=%u, elapsed=%lu ms\r\n",
                       (unsigned int)s_ping_target_ip[0],
                       (unsigned int)s_ping_target_ip[1],
                       (unsigned int)s_ping_target_ip[2],
                       (unsigned int)s_ping_target_ip[3],
                       (unsigned int)s_ping_sequence,
                       (unsigned long)(now - s_ping_request_tick));
                ping_finish_cycle(now, 1U);
            }
            else if ((slir & SLIR_TOUT) != 0U)
            {
                printf("PING timeout: %u.%u.%u.%u\r\n",
                       (unsigned int)s_ping_target_ip[0],
                       (unsigned int)s_ping_target_ip[1],
                       (unsigned int)s_ping_target_ip[2],
                       (unsigned int)s_ping_target_ip[3]);
                ping_finish_cycle(now, 0U);
            }
            else if ((uint32_t)(now - s_ping_request_tick) >= s_ping_config.response_timeout_ms)
            {
                printf("PING response: timeout\r\n");
                ping_finish_cycle(now, 0U);
            }
            break;

        default:
            ping_clear_result();
            s_ping_state = PING_STATE_IDLE;
            s_ping_state_tick = now;
            break;
    }
}

状态机三个状态:IDLE 每隔 interval_ms 触发一次 ping;WAIT_COMMAND 等待 getSLCR() 返回 0(命令完成),超时则判定失败;WAIT_RESULT 轮询 getSLIR(),若 SLIR_PING4 置位表示收到回复,若 SLIR_TOUT 置位表示超时。

步骤4:ping_start() 触发 PING 命令

文件:USER/ping.c。通过免套接字指令触发 PINGv4 操作:写入标识符、序列号、目标 IP,然后设置 SLCR_PING4 触发命令。

static void ping_start(uint32_t now)
{
    if ((s_ping_request_limit != 0U) && (s_ping_completed_count >= s_ping_request_limit))
    {
        return;
    }

    ping_clear_result();

    s_ping_sequence++;
    setPINGIDR(s_ping_config.id);
    setPINGSEQR(s_ping_sequence);
    setSLDIP4R(s_ping_target_ip);
    setSLCR(SLCR_PING4);

    s_ping_request_tick = now;
    s_ping_state = PING_STATE_WAIT_COMMAND;

    printf("PING request: %u.%u.%u.%u, id=%u, seq=%u\r\n",
           (unsigned int)s_ping_target_ip[0],
           (unsigned int)s_ping_target_ip[1],
           (unsigned int)s_ping_target_ip[2],
           (unsigned int)s_ping_target_ip[3],
           (unsigned int)s_ping_config.id,
           (unsigned int)s_ping_sequence);
}

免套接字指令要点

setPINGIDR() / setPINGSEQR() 设置 ICMP 报文的标识符和序列号,setSLDIP4R() 写入目标 IP,最后 setSLCR(SLCR_PING4) 触发命令。整个过程无需用户构造 ICMP 报文,也无需计算校验和,TOE 硬件会自动完成。

步骤5:ping_finish_cycle() 统计结果

文件:USER/ping.c。每次 ping 循环完成后清中断标志、统计请求/回复/丢包,达到请求次数上限时打印汇总信息。

static void ping_finish_cycle(uint32_t now, uint8_t reply_received)
{
    ping_clear_result();
    s_ping_state = PING_STATE_IDLE;
    s_ping_state_tick = now;

    if ((s_ping_request_limit != 0U) && (s_ping_completed_count < s_ping_request_limit))
    {
        s_ping_completed_count++;
        if (reply_received != 0U)
        {
            s_ping_reply_count++;
        }

        if (s_ping_completed_count >= s_ping_request_limit)
        {
            printf("Ping Request = %u, Ping Reply = %u, Lost = %u\r\n",
                   (unsigned int)s_ping_completed_count,
                   (unsigned int)s_ping_reply_count,
                   (unsigned int)(s_ping_completed_count - s_ping_reply_count));
        }
    }
}

运行验证

烧录例程运行后,首先进行 PHY 链路检测,然后打印设置网络信息,最后对 ping 目标 IP 依次发送 4 次请求并收到回复。打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),观察开发板串口输出。

MH2457 W6300 QSPI example start
W6300 PING example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
DHCP running
DHCP success!
====================================================================================================
 W6300 network configuration : DHCP

 MAC         : 00:08:DC:12:34:56
 IP          : 192.168.1.8

 Subnet Mask : 255.255.255.0
 Gateway     : 192.168.1.1
 DNS         : 192.168.1.1
====================================================================================================

PING target: 192.168.1.20
PING request: 192.168.1.20, id=4660, seq=1
PING reply: 192.168.1.20, seq=1, elapsed=3 ms
PING request: 192.168.1.20, id=4660, seq=2
PING reply: 192.168.1.20, seq=2, elapsed=3 ms
PING request: 192.168.1.20, id=4660, seq=3
PING reply: 192.168.1.20, seq=3, elapsed=3 ms
PING request: 192.168.1.20, id=4660, seq=4
PING reply: 192.168.1.20, seq=4, elapsed=3 ms
Ping Request = 4, Ping Reply = 4, Lost = 0
WIZ UartTool 串口输出 — PHY 链路 + 网络信息 
WIZ UartTool 串口输出 — 4 次 Ping 请求/回复统计(Request=4, Reply=4, Lost=0)

常见问题

Q: 免套接字指令与普通 Socket 方式有什么区别

免套接字指令通过写 SLCR 寄存器直接触发 PING、ARP、NS、RS 等网络层报文,不占用 8 个硬件 Socket 中的任何一个,也不需要构造 ICMP 报文和计算校验和。普通 Socket 方式需要创建一个 IPRAW Socket,由用户手动构造报文并处理收发。对于只需要周期性探测网络连通性的场景,免套接字指令更简洁。

Q: PING 请求超时(PING timeout)怎么办

首先检查 PC 端与 W6300 是否处于同一网段;其次确认目标 IP 地址是否正确;再检查网络物理连接是否正常(网线、PHY 链路状态)。若网络存在防火墙,可能拦截 ICMP 报文导致超时。程序中超时由 SLIR_TOUT 置位触发,或者 response_timeout_ms 到期后主动判定超时。

Q: 为什么需要区分 WAIT_COMMAND 和 WAIT_RESULT 两个状态

SLCR_PING4 命令是异步的:写入命令后需要等待命令完成(SLCR 回到 0),然后等待 ICMP 响应到达(SLIR_PING4 或 SLIR_TOUT 置位)。两个阶段分别对应两个超时:command_timeout_ms 防止命令迟迟不完成,response_timeout_ms 防止响应迟迟不返回。分开处理可以更精确地定位问题。

Q: 如何统计 PING 的丢包率

程序中用 s_ping_completed_count 记录已完成的 PING 循环数,用 s_ping_reply_count 记录收到回复的次数,丢包数即为两者之差。当请求数达到设定上限时,通过 printf 输出 "Ping Request = %u, Ping Reply = %u, Lost = %u" 统计信息。丢包率 = 丢失数 / 请求总数 x 100%。

Q: PING 间隔时间如何调整

PING 间隔由 ping_config_t 中的 interval_ms 决定(示例为 3000ms)。调整该值可改变两次 PING 请求之间的间隔。命令超时由 command_timeout_ms 控制(默认 100ms),响应超时由 response_timeout_ms 控制(默认 5000ms)。

总结

本文基于 W6300 的 SOCKET-less Command(SLCR)PING4 指令实现了网络诊断功能:

  • PING 原理:基于 ICMP 协议发送回显请求并等待回显应答,用于测试网络连通性、检测延迟、排查故障
  • 免套接字指令:W6300 TOE 引擎内置 PING4 指令,通过 SLCR 寄存器触发,不占用 Socket 资源,硬件自动构造 ICMP 报文
  • 核心函数:do_ping() 控制流程、ping_init() 初始化、ping_run() 状态机、ping_start() 触发命令、ping_finish_cycle() 统计结果
  • 关键寄存器:SLDIPR(目标 IP)、PINGIDR/PINGSEQR(标识符/序列号)、SLCR(命令)、SLIR(结果)
  • 状态机设计:IDLE → WAIT_COMMAND → WAIT_RESULT 三态切换,分别处理命令超时和响应超时

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5

Andy

W5500 技术支持专家