全部例程

W6300 使用 SOCKET-less 指令实现 ARP 请求

W6300

更新于 2026年10月10日

本篇总结

基于 W6300 的 SOCKET-less Command(SLCR)ARP4 指令实现 ARP 请求,通过 SLIR 判断结果,并从 SLDHAR 读取目标 MAC 地址。

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

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

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

本示例演示如何在 W6300 芯片上使用 SOCKET-less Command(SLCR)实现 ARP 请求。W6300 的 TOE 引擎内置了 ARP4 指令,可以直接通过写 SLCR 寄存器触发一次 ARP 请求,ARP 报文的构造、发送、接收、解析全部由硬件完成,结果通过 SLIR 寄存器判断,目标 MAC 地址可从 SLDHAR 寄存器直接读取。例程通过 do_arp() 控制流程,arp_run() 驱动状态机,周期性发起 ARP 请求并打印目标 MAC 地址。

前置工具准备

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

ARP 免套接字指令简介

ARP(Address Resolution Protocol)用于在局域网中把 IPv4 地址解析为对应的 MAC 地址。W6300 提供 SOCKET-less Command(SLCR),可以在不使用 Socket 资源的情况下,直接通过寄存器触发 ARP 请求、PING 请求、NS、RS 等网络层报文。命令执行结果通过 SLIR 寄存器确认,命令未完成前不能执行下一条命令。

ARP4 指令相关寄存器如下:

寄存器说明
SLDIPRSOCKET-less Destination IPv4 Address Register,设置 ARP 请求的目标 IPv4 地址
SLCR[ARP4]SOCKET-less Command Register 的 ARP4 位,写 1 发送 ARP 请求;命令完成后自动清 0,未完成前不能执行新命令
SLIR[ARP4]收到 ARP Reply 后置位
SLIR[TOUT]重传次数超过 SLRCR 后置位,表示超时
SLIRCLR写 1 清除 SLIR 中对应位
SLDHARSOCKET-less Destination Hardware Address Register,收到 ARP Reply 后,硬件自动将对方 MAC 地址写入该寄存器
SLRTR / SLRCRSOCKET-less Retransmission Time/Count Register,控制重传时间(单位 100us)与重传次数,超过次数则 SLIR[TOUT] 置位
SLIMRSOCKET-less Interrupt Mask Register,可屏蔽 SLIR 中对应的中断位

ARP4 指令执行流程:

  1. 配置:设置 SLDIPR(目标 IP)、SLRTR / SLRCR(重传时间与次数)、SLIMR(中断屏蔽位)
  2. 触发命令:写 SLCR[ARP4] = 1,等待 SLCR 回到 0 表示命令完成
  3. 等待响应:轮询 SLIR,若 SLIR[ARP4] = 1 表示收到 ARP Reply;若 SLIR[TOUT] = 1 表示超时
  4. 获取结果:收到 ARP Reply 后,从 SLDHAR 读取目标 MAC 地址;写 SLIRCLR 清除对应中断位

W6300 的优势

W6300 的 TOE 引擎原生支持 ARP4 免套接字指令,ARP 报文的构造、发送、接收、解析、重传全部由硬件完成。用户只需通过寄存器配置目标 IP,触发 SLCR[ARP4] 后轮询 SLIR 结果,成功后从 SLDHAR 直接读取目标 MAC 地址。整个过程不占用 Socket 资源。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W6300 处于同一网段,且目标 IP 对应的设备已经在线。

  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 ARP │ │ 192.168.1.20│
│ IP: DHCP │ │ MAC: D8:43:AE:17:65:A4│
└────┬──────┘ └───────────┘
│ QSPI ↑
┌────┴──────┐ DEBUG USB
│ MH2457 │─────→ WIZ UartTool
│ MCU │
└───────────┘
网络拓扑:开发板与 PC 在同一局域网内,通过路由器互通,MH2457 通过 QSPI 驱动 W6300

工程结构

工程核心文件如下:

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

本例程的核心:通过 SLCR[ARP4] 免套接字指令触发 ARP 请求,轮询 SLIR 判断结果,从 SLDHAR 读取目标 MAC 地址。ARP 状态机在 arp_run() 中运行,通过 do_arp() 完成一次性初始化。

步骤1:主循环调用

文件:USER/user_main.c。在主循环中调用 do_arp() 函数,传入 Socket 号、网络缓冲区和目标主机 IP。

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

while (1)
{
    do_arp(SOCKET_ID, ethernet_buf, dest_ip);
}

do_arp() 函数起到了控制 ARP 操作流程的作用,首次调用完成一次性初始化(设置目标 IP、超时参数等),之后每次调用运行 arp_run() 状态机,周期性发起 ARP 请求。

步骤2:do_arp() 流程控制

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

void do_arp(uint8_t sn, uint8_t *buf, uint8_t *dest_ip)
{
    arp_config_t config;

    (void)sn;
    (void)buf;

    if (s_arp_compat_initialized == 0U)
    {
        if (dest_ip == NULL)
        {
            return;
        }

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

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

        s_arp_compat_initialized = 1U;
    }

    arp_run();
}

do_arp() 首次调用时根据传入的目标 IP 构造 arp_config_t 配置,调用 arp_init() 完成初始化;之后每次调用 arp_run() 驱动状态机,每隔 interval_ms 发起一次 ARP 请求。

步骤3:arp_run() 状态机

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

void arp_run(void)
{
    uint32_t now = wiz_platform_get_tick();
    uint8_t slir;
    uint8_t target_mac[6];

    switch (s_arp_state)
    {
        case ARP_STATE_IDLE:
            if ((uint32_t)(now - s_arp_state_tick) >= s_arp_config.interval_ms)
            {
                arp_start(now);
            }
            break;

        case ARP_STATE_WAIT_COMMAND:
            if (getSLCR() == 0U)
            {
                s_arp_state = ARP_STATE_WAIT_RESULT;
            }
            else if ((uint32_t)(now - s_arp_request_tick) >= s_arp_config.command_timeout_ms)
            {
                printf("ARP command: timeout\r\n");
                arp_finish_cycle(now);
            }
            break;

        case ARP_STATE_WAIT_RESULT:
            slir = getSLIR();

            if ((slir & SLIR_ARP4) != 0U)
            {
                getSLDHAR(target_mac);
                printf("ARP reply: %u.%u.%u.%u -> %02X:%02X:%02X:%02X:%02X:%02X, elapsed=%lu ms\r\n",
                       (unsigned int)s_arp_target_ip[0],
                       (unsigned int)s_arp_target_ip[1],
                       (unsigned int)s_arp_target_ip[2],
                       (unsigned int)s_arp_target_ip[3],
                       (unsigned int)target_mac[0],
                       (unsigned int)target_mac[1],
                       (unsigned int)target_mac[2],
                       (unsigned int)target_mac[3],
                       (unsigned int)target_mac[4],
                       (unsigned int)target_mac[5],
                       (unsigned long)(now - s_arp_request_tick));
                arp_finish_cycle(now);
            }
            else if ((slir & SLIR_TOUT) != 0U)
            {
                printf("ARP timeout: %u.%u.%u.%u\r\n",
                       (unsigned int)s_arp_target_ip[0],
                       (unsigned int)s_arp_target_ip[1],
                       (unsigned int)s_arp_target_ip[2],
                       (unsigned int)s_arp_target_ip[3]);
                arp_finish_cycle(now);
            }
            else if ((uint32_t)(now - s_arp_request_tick) >= s_arp_config.response_timeout_ms)
            {
                printf("ARP response: timeout\r\n");
                arp_finish_cycle(now);
            }
            break;

        default:
            arp_finish_cycle(now);
            break;
    }
}

状态机三个状态:IDLE 每隔 interval_ms 触发一次 ARP 请求;WAIT_COMMAND 等待 getSLCR() 返回 0(命令完成),超时则判定失败;WAIT_RESULT 轮询 getSLIR(),若 SLIR_ARP4 置位表示收到 ARP Reply,从 getSLDHAR() 读取目标 MAC;若 SLIR_TOUT 置位表示超时。

步骤4:arp_start() 触发 ARP 命令

文件:USER/arp.c。通过免套接字指令触发 ARP 请求:写入目标 IP,然后设置 SLCR_ARP4 触发命令。

static void arp_start(uint32_t now)
{
    arp_clear_result();
    setSLDIP4R(s_arp_target_ip);
    setSLCR(SLCR_ARP4);

    s_arp_request_tick = now;
    s_arp_state = ARP_STATE_WAIT_COMMAND;

    printf("ARP request: %u.%u.%u.%u\r\n",
           (unsigned int)s_arp_target_ip[0],
           (unsigned int)s_arp_target_ip[1],
           (unsigned int)s_arp_target_ip[2],
           (unsigned int)s_arp_target_ip[3]);
}

免套接字指令要点

setSLDIP4R() 写入目标 IP,setSLCR(SLCR_ARP4) 触发 ARP 请求。整个过程无需用户构造 ARP 报文,也无需解析 ARP 应答,TOE 硬件会自动完成。请求成功或超时后由 SLIR 置位通知。

步骤5:arp_finish_cycle() 结束循环

文件:USER/arp.c。每次 ARP 循环完成后清中断标志、复位状态机,等待下一次触发。

static void arp_finish_cycle(uint32_t now)
{
    arp_clear_result();
    s_arp_state = ARP_STATE_IDLE;
    s_arp_state_tick = now;
}

运行验证

烧录例程运行后,首先进行 PHY 链路检测,然后打印设置网络信息,最后周期性地对 ARP 目标 IP 发起请求并打印目标 MAC 地址。打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),观察开发板串口输出。

MH2457 W6300 QSPI example start
W6300 ARP request 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
====================================================================================================

ARP target: 192.168.1.20
ARP request: 192.168.1.20
ARP reply: 192.168.1.20 -> D8:43:AE:17:65:A4, elapsed=2 ms
ARP request: 192.168.1.20
ARP reply: 192.168.1.20 -> D8:43:AE:17:65:A4, elapsed=2 ms
WIZ UartTool 串口输出 — PHY 链路 + 网络信息 
WIZ UartTool 串口输出 — ARP 请求/应答(目标 MAC D8:43:AE:17:65:A4,耗时 2ms)

常见问题

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

免套接字指令通过写 SLCR 寄存器直接触发 ARP、PING、NS、RS 等网络层报文,不占用 8 个硬件 Socket 中的任何一个,也不需要构造 ARP 报文和解析应答。普通 Socket 方式需要创建一个 MACRAW Socket,由用户手动构造报文并处理收发。对于只需要解析某个 IP 对应 MAC 地址的场景,免套接字指令更简洁。

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

首先检查 PC 端与 W6300 是否处于同一网段;其次确认目标 IP 地址是否正确,且对应设备在线;再检查网络物理连接是否正常(网线、PHY 链路状态)。若目标设备开启了防火墙或关闭了 ARP 响应,可能无法收到应答。程序中超时由 SLIR_TOUT 置位触发,或者 response_timeout_ms 到期后主动判定超时。

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

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

Q: 目标 MAC 地址从哪里读取

收到 ARP 应答后,TOE 硬件会自动把对方的 MAC 地址写入 SLDHAR 寄存器(SOCKET-less Destination Hardware Address Register)。软件通过 getSLDHAR() 即可读取,无需自己解析 ARP 报文。

Q: ARP 请求间隔时间如何调整

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

总结

本文基于 W6300 的 SOCKET-less Command(SLCR)ARP4 指令实现了 ARP 请求功能:

  • ARP 原理:把 IPv4 地址解析为对应的 MAC 地址,用于局域网内二层数据帧封装
  • 免套接字指令:W6300 TOE 引擎内置 ARP4 指令,通过 SLCR 寄存器触发,不占用 Socket 资源,硬件自动构造 ARP 报文
  • 核心函数:do_arp() 控制流程、arp_init() 初始化、arp_run() 状态机、arp_start() 触发命令、arp_finish_cycle() 结束循环
  • 关键寄存器:SLDIPR(目标 IP)、SLCR(命令)、SLIR(结果)、SLDHAR(目标 MAC)
  • 状态机设计:IDLE → WAIT_COMMAND → WAIT_RESULT 三态切换,分别处理命令超时和响应超时

下载本章例程

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

开发环境: Keil MDK5

Andy

W5500 技术支持专家