当前位置: 首页 > ds >正文

Iwip驱动8211FS项目——MPSOC实战1

硬件设计采用RTL8211FS芯片,vitis默认的IWIP库不支持此芯片。

网口相关知识可以翻看前期文章

以太网PHY_MDIO通信(基于RTL8211)--FPGA学习笔记22-CSDN博客

以太网ARP协议——FPGA学习笔记23_fpga以太网学习-CSDN博客

以太网ICMP协议(ping指令)——FPGA学习笔记25_icmp报文 以太网类型-CSDN博客

以太网UDP协议栈实现(支持ARP、ICMP、UDP)--FPGA学习笔记26_description: 接收arp、icmp、udp三种以太网报文,并对相应的数据进行解析,输出给-CSDN博客

感谢小梅哥论坛大佬文章

【Zynq】【Lwip】解决频繁打印link up/down、绿灯不亮、自协商结束后插入网线无反应的问题
https://www.corecourse.cn/forum.php?mod=viewthread&tid=29789
(出处: 芯路恒电子技术论坛)
【Zynq】【Lwip】解决使用官方lwip模板时自动协商失败的问题
https://www.corecourse.cn/forum.php?mod=viewthread&tid=29166
(出处: 芯路恒电子技术论坛)
 

关于芯片兼容修改问题,重点关注以下函数

void init_emacps(xemacpsif_s *xemacps, struct netif *netif);

static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)

LWIP环回代码简解:

1、板级前置初始化

为芯片分配MAC地址,可修改

初始化平台,关闭 I/D Cache、初始化 UART、注册中断控制器、映射 GEM 寄存器等(板级支持包干的事)。

2、协议栈内存 + 网络接口数据结构清零

把 lwIP 全局结构(内存池、定时器、PCB 链表等)全部清零,为后续添加网卡做准备。

3、向 lwIP 注册“唯一”的网卡

把前面得到的 MAC、IP、网关、子网掩码、GEM 基地址打包,创建一个 struct netif 实例 server_netif,并挂到 lwIP 全局链表。

让 lwIP 后续发送默认走这张网卡。

开启指定网口

4、定时器与中断

开启中断功能。使能 IRQ,GEM 接收完成中断、定时器中断等开始工作。

  • 后面主循环会周期性置位:

    • TcpFastTmrFlag = 1 每 250 ms(TCP 快速定时器)

    • TcpSlowTmrFlag = 1 每 500 ms(TCP 慢速定时器)
      这两标志在 xemacif_input() 内部由中断服务程序刷新。

5、DHCP而客户端

#if LWIP_DHCP==1

dhcp_start(echo_netif);
启动 DHCP 状态机,开始 Discover-Offer-Request-Ack 四步舞。

while((ip_addr == 0) && (dhcp_timoutcntr > 0))
主循环里不断调用 xemacif_input() 收包,让 DHCP 状态机跑起来;24×0.5 s = 12 s 超时。

超时仍未拿到地址就 fallback 到静态 192.168.1.10。

6、用户代码绑定

print_app_header() // 打印一条提示

start_application() // 创建 PCB、绑定端口、注册回调

transfer_data() // 周期发送或处理数据

一些函数详解:

void init_emacps(xemacpsif_s *xemacps, struct netif *netif);

Xilinx GEM(PS 端千兆以太网)在 lwIP 下的“一站式硬件启动器”,把 MAC 控制器、PHY、链路速率全部配置到可收发状态

1、拿到MAC控制器句柄

  • xemacps 是 Xilinx 驱动库 XEmacPs 的实例,后续所有寄存器操作都靠它。

2、打开巨型帧 / 组播选项(可选)

  • 巨型帧(9018 B)需要提前使能,否则硬件会截断。
  • 组播选项让 MAC 接受多播哈希表过滤,为 IGMP 服务。

3、把软件 MAC 地址写进硬件寄存器

  • 第 3 个参数 1 表示使用“地址槽 1”(0 留给特殊帧)。

  • 失败直接打印调试信息并继续往下走(后面还可改)。

4、配置 MDIO 时钟

  • 根据 CPU 频率把 MDC 降到 ≤2.5 MHz,满足 IEEE 802.3 要求。

5、探测并初始化 PHY

分两条路:

a) 板载 PCS/PMA 1000Base-X 或 SGMII 口
→ 直接调用 phy_setup_emacps(xemacpsp, 固定地址)
→ 地址由 xparameters.h 给出(例如 1 或 7)。

b) 标准 RGMII/MDIO 总线
detect_phy() 先把 0-31 号 PHY 扫一遍,把在位 PHY 记录到数组 phymapemac0/1[]
→ 然后对每一个在位地址调用 phy_setup_emacps(),完成:
- 软件复位
- 设置自动协商通告(10/100/1000)
- 等待协商完成
- 回传实际链路速率(10/100/1000 Mbps)

 先遍历 1–31 号地址里所有被标记为 TRUE 的 PHY,全部初始化;如果一个都没找到,就退而求其次用广播地址 0 再试一次。

执行完这段代码后:

  • phyaddrforemac 保存了实际使用的 PHY 地址;

  • link_speed 要么等于 10/100/1000,要么标记失败;

  • 后续 XEmacPs_SetOperatingSpeed() 就依据 link_speed 给 MAC 设速。

void detect_phy(XEmacPs *xemacpsp);

        在 MDIO 总线上把 0–31 号地址全部扫一遍,找到真正挂着的 PHY

        (1)先确定是 EMAC0 还是 EMAC1

  • Zynq/MP 有两路 GEM 控制器,函数根据基地址区分当前扫描的是哪一路,然后把结果写到 全局数组 phymapemac0[]phymapemac1[]

        (2)从 31 到 1 号地址倒序扫描

  • 地址 0 是广播地址,跳过;

  • 倒序可以避免某些交换芯片伪应答带来的误判。

        (3)读 “PHY ID 寄存器” 做存在性检测

        此处注意兼容,板载PHY是否为此寄存器地址。

  • PHY_DETECT_REG 通常是 寄存器 2(PHY Identifier 1)

  • 如果读到 0xFFFF,说明该地址没有芯片响应,直接跳过。

        (4)判断芯片是否真实存在

  • PHY_DETECT_MASK 把厂商 OUI 的固定位拉出来做匹配;

  • 满足条件就把 phymapemacX[phy_addr] = TRUE,后面 init_emacps() 会只对这些“真正在位”的地址进行初始化。

        (5)打印调试信息

  • 打开 LWIP_DEBUG 时会看到类似XEmacPs detect_phy: PHY detected at address 1.

        (6)进一步读寄存器 2 做厂商识别


 

  • 这一步只是提示如果 PHY 不是这三家,初始化脚本里对特殊寄存器的配置可能不适用,需要你自己确认。

        扫描结束后,phymapemac0[] / phymapemac1[] 里为 TRUE 的索引就是本总线上实际存在的 PHY 地址;init_emacps() 会遍历这些地址,分别调用 phy_setup_emacps() 完成真正的配置。

6、链路失败退出

  • 此时 MAC 仍处于复位态,lwIP 不会收到任何包。

7、把协商到的速率写回 MAC

  • 告诉 GEM 控制器当前是 10/100/1000 Mbps,内部会重新计算 MII/RGMII 时钟分频。

  • 后面紧跟一段空转延时,让硬件锁定时钟——经验值 20 000 空循环 ≈ 几十微秒。(该部分延时可适当加长)参考文章:

【Zynq】【Lwip】解决频繁打印link up/down、绿灯不亮、自协商结束后插入网线无反应的问题
 

8、全局链路状态变量供后续查询

  • xemacpsif_input() 里会定期查这个变量,发现掉线就丢弃收包,防止错误中断淹掉 CPU。

关于init_emacps()的调用:

init_emacps() 的调用路径只有一条,而且 完全藏在 Xilinx 的 lwIP 适配层内部,用户代码里根本看不到它的名字:

xemac_add()                                                              ← 用户唯一显式调用
 └─ netif_add(netif, ..., xemacpsif_init, ...)                 ← lwIP 标准 API
     └─ xemacpsif_init(netif)                                        ← 在 xemacpsif.c 里
         └─ init_emacps(netif)                                        ← 就在这里被调用

xemac_add() 只在 main() 里被用户显式调用一次;它的使命就是“把 MAC 地址、IP 地址、底层初始化函数挂到 lwIP 的 netif 链表”,成功后退出,后续数据收发不再经过它。

static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)

get_IEEE_phy_speed() 是一个 “厂商识别 + 分发” 的派发函数,根据 PHY 芯片的厂商 ID,把速率解析工作转给对应的专用函数,返回 10/100/1000 或失败。

1、读取 寄存器 2(PHY Identifier 1) 的高 16 位,拿到 OUI 前缀。

  • 三家常量已定义:

    • PHY_TI_IDENTIFIER 0x2000

    • PHY_REALTEK_IDENTIFIER 0x001C

    • 其余默认走 Marvell 分支(0x0141 或其他)

此处注意兼容,以防进入错误分支

2、直接调用对应的厂商函数:

3、返回协商速率

关于static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)的调用

get_IEEE_phy_speed() 只被 phy_setup_emacps() 调用一次,负责 “识别厂商 → 转交对应的寄存器解析函数 → 拿到链路速率”

main()
 └─ xemac_add()
     └─ xemacpsif_init()
         └─ init_emacps()
             └─ phy_setup_emacps()
                 └─ get_IEEE_phy_speed()   ← 这里

static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)

这段代码就是 Realtek PHY 专用的速率获取函数 get_Realtek_phy_speed(),作用与之前的通用协商流程完全一致,只不过把“读速率”这一步固定到 Realtek 的 SPECIFIC_STATUS_REG(通常是 0x1A) 上。

  • get_IEEE_phy_speed() 调用,参数已确认 phy_identity == 0x001C(Realtek)。

  • MDIO 时钟已通过 XEmacPs_SetMdioDivisor() 降到 ≤2.5 MHz。

  • 函数运行在裸机,中断关闭,CPU 主频 666 MHz(Zynq-7000 典型值)。

1、读取并修改 10/100 通告寄存器(地址 0x04

  • MDIO 帧:Start (2b) + Op(2b) + PHYaddr(5b) + Reg(5b) + TA(2b) + 16-bit data

  • 实际总线波形 64 位,约 25 µs 完成。

  • 读回值假设为 0x01E1(出厂默认值)。

control |= IEEE_ASYMMETRIC_PAUSE_MASK   // bit11 = 1| IEEE_PAUSE_MASK              // bit10 = 1| ADVERTISE_100                // bit8  = 1| ADVERTISE_10;                // bit7  = 1
  • 新值 0x05E1 → 表示“本端支持 10/100 全双工 + 对称/非对称流控”。

  • 再次产生 MDIO 写帧,PHY 内部立即更新通告寄存器。

2 、读取并修改 1000 M 通告寄存器(地址 0x09

写入数据0000 0011 0000 0000

  • 读回 0x0000(Realtek RTL8211 默认未设 1000 M 通告)。

control |= ADVERTISE_1000;   // bit9 = 1
  • 新值 0x0200 → 表示“本端支持 1000 M 全双工”。(实际代码为0x0300,可以兼容YT8531)

  • 写入完成,PHY 内部把 1000 M 能力加入下次自协商 FLP 脉冲。

3、重启自协商 + 软复位

XEmacPs_PhyRead(xemacpsp, phy_addr, 0x00, &control);
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE  // bit12 = 1| IEEE_STAT_AUTONEGOTIATE_RESTART // bit9  = 1
  • 新值 0x1200(保持之前设置的 0x1200,再置 bit9)

  • 写完后 PHY 立即发出携带新通告的 Fast Link Pulse (FLP) 序列,链路伙伴开始协商。

  • 软复位:PHY 内部状态机回到初始态,寄存器除 0x00 外全部恢复默认值,但 0x04/0x09 的通告值已被锁存,复位后仍保留。

  • 复位期间 bit15 保持 1,典型耗时 < 100 µs(RTL8211 数据手册标称 60 µs)。

4、轮询等待复位完成

5、等待自协商完成(最耗时)

  • 初始 status 读回 0x7849(bit5 = 0,协商未完成)。

while (!(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)) {  // bit5sleep(1);            // 裸机 sleep(1) ≈ 1 stimeout_counter++;if (timeout_counter == 30) return XST_FAILURE;XEmacPs_PhyRead(xemacpsp, 0x01, &status);
}

  • 最坏情况 30 s 后超时退出;正常千兆对千兆 1–2 s 内 bit5 置 1

  • 串口每秒打印一次 “Waiting for PHY to complete autonegotiation.”

  • 成功后打印 “autonegotiation complete”。

6、读取 Realtek 专用速率寄存器(注意兼容问题

  • 按位掩码比对,立即得到整数速率。注意兼容问题。

  • 若 resolved 位未置 1,说明协商失败,走 return XST_FAILURE;

get_Realtek_phy_speed() 就是 “把 Realtek PHY 的寄存器按官方顺序撸一遍,直到 0x1A 的 resolved 位拉起来,再把 bit14:13 翻译成 Mbps

关于get_Realtek_phy_speed() 的调用

在static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)中调用,其他厂商配置代码类似。

http://www.xdnf.cn/news/20310.html

相关文章:

  • 当服务器出现网卡故障时如何检测网卡硬件故障并解决?
  • Grizzly_高性能 Java 网络应用框架深度解析
  • 基于智能合约实现非托管支付
  • Qt添加图标资源
  • conda配置pytorch虚拟环境
  • git cherry-pick 用法
  • dpdk example
  • 自动化流水线
  • Ubuntu 22 redis集群搭建
  • 电脑越用越卡?C盘红到预警?这款清理神器帮你一键 “减负”!
  • 跨域请求问题浅解
  • 深入浅出 QComboBox:Qt 中的下拉列表组件
  • uniapp开发前端静态视频界面+如何将本地视频转换成网络地址
  • 2024年9月GESPC++三级真题解析(含视频)
  • 核心高并发复杂接口重构方案
  • 9.5 IO-线程day5
  • SQL Sever2022安装教程
  • LKT4202UGM重新定义物联网设备安全标准
  • python 自动化在web领域应用
  • Karmada v1.15 版本发布
  • 如何选择文件夹然后用vscode直接打开
  • 23种设计模式——装饰器模式(Decorator Pattern)详解
  • Meta AI眼镜Hypernova量产临近,微美全息构筑护城河引领人机交互变革浪潮
  • Ubuntu 22.0安装中文输入法
  • 分布式事务的Java实践
  • 面试官问:你如何提高工作效率?
  • 专项智能练习(计算机动画基础)
  • java log相关:Log4J、Log4J2、LogBack,SLF4J
  • 安防芯片ISP白平衡统计数据如何提升场景适应性?
  • 微信小程序如何进行分包处理?