RT-Thread论坛
直播中

颜立歆

9年用户 1033经验值
擅长:控制/MCU
私信 关注
[问答]

移植网络PHY芯片驱动,如何融入 rt-thread 的网络体系,并添加新的以太网类型的报文?

我需要移植一个 PHY 芯片(IS32CG5317,通过 SPI 与单板通信),当单板与 PHY 芯片的 SPI 通信驱动移植完后:

  • 我如何将 PHY 芯片融入 rt-thread 的网络体系(该 PHY 芯片最底层收发以太网报文,有可能组成 VLAN 网络);
  • 我要实现一个新的以太网类型报文(HPGP报文,以太网报文类型为 0x88E1),要求能在应用层收发该以太网类型报文,并且和多线程下的 TCP 和 UDP 报文不冲突(对于同一个网络接口,可能会同时收发 TCP、UDP 和 HPGP报文)。


回帖(1)

李斌

2025-9-25 18:17:34

要将 IS32CG5317 PHY 芯片驱动融入 RT-Thread 网络体系并支持自定义 HPGP 报文(0x88E1),需完成以下关键步骤:




1. 集成 PHY 驱动到网络框架


(1) 实现网络设备驱动


创建 struct netdev 的子类,实现底层操作:


#include 

static const struct rt_eth_phy_ops phy_ops = {
    .init = phy_init,
    .read = phy_reg_read,
    .write = phy_reg_write,
};

static rt_err_t eth_tx(rt_device_t dev, struct pbuf* p) {
    // 将 pbuf 数据通过 SPI 发送到 PHY
    spi_send(p->payload, p->len);
    return RT_EOK;
}

static struct pbuf* eth_rx(rt_device_t dev) {
    // 从 SPI 读取以太网帧并返回 pbuf
    struct pbuf* p = pbuf_alloc(PBUF_RAW, FRAME_SIZE, PBUF_POOL);
    spi_receive(p->payload, &p->len);
    return p;
}

static const struct rt_eth_dev_ops eth_ops = {
    .eth_tx = eth_tx,
    .eth_rx = eth_rx,
};

int phy_driver_register(void) {
    struct eth_device* eth_dev = rt_malloc(sizeof(struct eth_device));
    eth_dev->phy_ops = &phy_ops;
    eth_dev->parent.ops = ð_ops;
    rt_eth_device_init(eth_dev, "spi0");
    return 0;
}
INIT_DEVICE_EXPORT(phy_driver_register);

(2) 配置 lwIP 底层接口


修改 ethernetif.c 中的底层收发函数:


err_t ethernetif_input(struct netif *netif) {
    struct pbuf *p;
    while ((p = eth_rx(netif)) != NULL) {
        if (p->len > 0) {
            // 识别 VLAN 标签(可选)
            struct eth_hdr* ethhdr = (struct eth_hdr*)p->payload;
            if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
                // 处理 VLAN 标签
                struct eth_vlan_hdr* vlan = (struct eth_vlan_hdr*)(ethhdr + 1);
                ethhdr->type = vlan->tpid;
            }
            // 传递到上层
            netif->input(p, netif);
        }
    }
    return ERR_OK;
}



2. 支持 HPGP 自定义报文


(1) 扩展 lwIP 协议类型


lwipopts.h 中启用原始链路层访问:


#define LWIP_RAW 1                   // 启用 RAW API
#define ETH_PAD_SIZE 0               // 禁用填充

注册自定义协议处理回调:


// 定义 HPGP 类型 (0x88E1)
#define ETHTYPE_HPGP 0x88E1

static struct raw_pcb *hpgp_pcb = NULL;

void hpgp_input(struct raw_pcb *pcb, struct pbuf *p, struct netif *inp) {
    // 应用层处理 HPGP 报文
    rt_kprintf("Received HPGP frame, len: %dn", p->tot_len);
    pbuf_free(p);
}

void hpgp_init(void) {
    hpgp_pcb = raw_new(PP_NTOHS(ETHTYPE_HPGP)); // 绑定到 0x88E1
    if (hpgp_pcb) {
        raw_recv(hpgp_pcb, hpgp_input, NULL);
    }
}
INIT_COMPONENT_EXPORT(hpgp_init);

(2) 应用层收发 HPGP 报文


发送 HPGP 报文


void send_hpgp_frame(void) {
    struct pbuf* p = pbuf_alloc(PBUF_RAW, HPGP_SIZE, PBUF_RAM);
    struct eth_hdr* ethhdr = (struct eth_hdr*)p->payload;

    // 填充目标 MAC、源 MAC 和 HPGP 类型
    memcpy(ethhdr->dest, dest_mac, 6);
    memcpy(ethhdr->src, src_mac, 6);
    ethhdr->type = PP_HTONS(ETHTYPE_HPGP);

    // 填充 HPGP 数据
    memcpy((char*)ethhdr + sizeof(struct eth_hdr), hpgp_data, data_len);

    // 通过网卡发送
    netif->linkoutput(netif, p);
    pbuf_free(p);
}

接收 HPGP 报文(通过 RAW Socket):


int hpgp_sock = socket(PF_PACKET, SOCK_RAW, htons(ETHTYPE_HPGP));
struct sockaddr_ll sll;
memset(&sll, 0, sizeof(sll));
sll.sll_ifindex = netif_get_index(netif); // 绑定到网卡

bind(hpgp_sock, (struct sockaddr*)&sll, sizeof(sll));

// 接收线程
void hpgp_recv_thread(void) {
    while(1) {
        char buf[1500];
        recv(hpgp_sock, buf, sizeof(buf), 0);
        // 处理 HPGP 数据...
    }
}



3. 确保多协议共存



  • 流量隔离

    • TCP/UDP 使用标准 Sockets API(AF_INET + SOCK_STREAM/SOCK_DGRAM

    • HPGP 使用原始链路层 Socket(PF_PACKET + SOCK_RAW


  • 线程安全

    • lwIP 内部通过互斥锁(sys_mutex)保护协议栈资源

    • 应用层使用 RT-Thread 的线程同步机制(如信号量)


  • VLAN 支持

    • 在 PHY 驱动中解析 VLAN 标签(802.1Q)

    • 修改 struct eth_hdr 包含 VLAN 字段:
      struct eth_vlan_hdr {
      u16_t tpid;    // 0x8100
      u16_t tci;     // Priority + VLAN ID
      u16_t proto;   // 上层协议 (HPGP/TCP/UDP)
      };





关键配置总结



  1. 驱动层

    • 实现 phy_opseth_ops 完成 SPI-PHY 通信

    • 在接收路径处理 VLAN 标签(如需要)


  2. 协议栈
    // lwipopts.h
    #define LWIP_RAW 1        // 启用 RAW Socket
    #define LWIP_NETIF_LOOPBACK 1

  3. 应用层

    • HPGP 使用 PF_PACKET + SOCK_RAW 收发

    • TCP/UDP 使用标准 BSD Socket



通过以上步骤,您的 PHY 驱动将无缝集成到 RT-Thread 网络栈,同时支持 TCP/UDP 和自定义 HPGP 报文的多协议并行处理。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分