W6300 使用 SOCKET-less 指令实现 ping 功能
更新于 2026年10月10日
本篇总结
基于 W6300 的 SOCKET-less Command(SLCR)PING4 指令实现 ping 功能,通过 SLIR 判断结果,并统计请求、回复与丢包数量。
硬件平台:本例程基于 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 请求与结果统计。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口调试工具:点击下载
PING 免套接字指令简介
PING(Packet Internet Groper)是基于 ICMP 协议的网络连通性测试命令,通过发送"回显请求"(Echo Request)并等待"回显应答"(Echo Reply)来检查目标主机是否可达及网络响应时间。W6300 的 TOE 引擎内置了 SOCKET-less Command(SLCR),可以不占用任何 Socket 资源,直接通过寄存器触发 PING、ARP、NS、RS 等网络层报文。
PING4 指令相关寄存器如下:
| 寄存器 | 说明 |
|---|---|
| SLDIPR | SOCKET-less Destination IPv4 Address Register,设置 PING 目标 IPv4 地址 |
| PINGIDR | PING ID Register,设置 PING 请求报文的标识符 |
| PINGSEQR | PING Sequence-number Register,设置 PING 请求报文的序列号(不会自动增加) |
| SLCR | SOCKET-less Command Register,写入 PING4 位触发 PING 请求;命令完成后自动清 0,未完成前不能执行新命令 |
| SLIR | SOCKET-less Interrupt Register,PING4 位表示收到 PING Reply,TOUT 位表示重传超时 |
| SLIRCLR | SLIR Clear Register,写 1 清除对应中断位 |
| SLRTR / SLRCR | SOCKET-less Retransmission Time/Count Register,控制重传时间(100us 单位)与重传次数,超过次数则 SLIR[TOUT] 置位 |
W6300 的优势
W6300 的 TOE 引擎原生支持 PING4 免套接字指令,ICMP 报文的构造、校验和计算、收发处理全部由硬件完成。用户只需通过寄存器配置目标地址、PING ID 和序列号,触发 SLCR[PING4] 后轮询 SLIR 结果即可。相比手动构造 ICMP 报文,代码更简洁,不占用 Socket 资源,可靠性更高。
硬件连接与拓扑
请注意:
测试需要 PC 端和 W6300 处于同一网段。
- Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
- 网线连接开发板 RJ45 网口 到路由器 LAN 口
- 确保 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 │
└───────────┘
工程结构
工程核心文件如下:
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

常见问题
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 三态切换,分别处理命令超时和响应超时