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

以太网通信--读取物理层PHY芯片的状态

PHY芯片通过MDIO接口进行读写,框图如下所示:

原理很简单,就是按照时序将PHY芯片的指定寄存器信息读出或者写入。

MDC时钟需要输出到PHY芯片,一般不低于80MHz。

MDIO是双向接口,FPGA读出状态信息时为输入,FPGA写入控制信息时为输出。

基本时序如下:(来源正点原子)

编码:(使用状态机实现对PHY芯片0x11地址的特殊寄存器的状态读操作)

module mdio_interface (
    input wire        clk,         // FPGA涓绘椂閽?
    input wire        reset_n,     // 澶嶄綅淇″彿锛屼綆鏈夋晥
    output reg        mdc,         // MDC鏃堕挓	涓嶈秴杩?12.5MHz 80ns
    inout              mdio         // MDIO鍙屽悜鏁版嵁绾?
);

reg [2:0] clk_div;
always @ (posedge clk or negedge reset_n) begin
	if (!reset_n) begin
		clk_div <= 3'd0;
	end else if (clk_div == 3'd3) begin
		clk_div <= 3'd0;
	end else begin
		clk_div <= clk_div + 1;
	end
end

always @ (posedge clk or negedge reset_n) begin
	if (!reset_n) begin
		mdc <= 0;
	end else if (clk_div == 3'd2) begin		//120ns鍛ㄦ湡
		mdc <= ~mdc;
	end else begin
		mdc <= mdc;
	end
end

reg mdio_dir;	//0璇?1鍐?
reg mdio_out;	//
assign mdio = mdio_dir ? mdio_out : 1'bz;

parameter IDLE = 8'b00000001;
parameter PREAMBLE = 8'b00000010;	//鍙戦??32浣?1 鍓嶅鐮?
parameter START = 8'b00000100;
parameter OPCODE = 8'b00001000;
parameter PHYADDR = 8'b00010000;
parameter REGADDR = 8'b00100000;
parameter TURNDIR = 8'b01000000;
parameter READ = 8'b10000000;

reg [7:0] state,next_state;
reg [7:0] cnt;
always @ (posedge mdc or negedge reset_n) begin
	if (!reset_n) begin
		state <= IDLE;
	end else begin
		state <= next_state;
	end
end

initial begin
    next_state = IDLE;
end

always @ (*) begin
	case (state)
		IDLE:		
                    next_state = PREAMBLE;
		PREAMBLE:	if (cnt == 8'd32) begin
						next_state = START;
					end else begin
						next_state = PREAMBLE;
					end
		START:		if (cnt == 8'd34) begin
						next_state = OPCODE;
					end else begin
						next_state = START;
					end
		OPCODE:		if (cnt == 8'd36) begin
						next_state = PHYADDR;
					end else begin
						next_state = OPCODE;
					end
		PHYADDR:	if (cnt == 8'd41) begin
						next_state = REGADDR;
					end else begin
						next_state = PHYADDR;
					end
		REGADDR:	if (cnt == 8'd46) begin
						next_state = TURNDIR;
					end else begin
						next_state = REGADDR;
					end
		TURNDIR:	if (cnt == 8'd48) begin
						next_state = READ;
					end else begin
						next_state = TURNDIR;
					end
		READ:		if (cnt == 8'd65) begin
						next_state = IDLE;
					end else begin
						next_state = READ;
					end
	endcase
end

reg [15:0] data_out; 
always @ (posedge mdc or negedge reset_n) begin
	if (!reset_n) begin
		cnt <= 8'd0;
		mdio_dir <= 1'd0;
		mdio_out <= 1'd0;
		data_out <= 16'd0;
	end else begin
		case(state)
			IDLE:		begin
							cnt <= 8'd0;
							mdio_dir <= 1'd0;
							mdio_out <= 1'd0;
							data_out <= 16'd0;
						end 
			PREAMBLE:	begin
							cnt <= cnt + 1;
							mdio_dir <= 1'd1;	//鍙戦?佸墠瀵肩爜锛屽啓32浣?1
							mdio_out <= 1'd1;
						end
			START:		begin
							cnt <= cnt + 1; 
							mdio_out <= (cnt == 8'd33 ? 0 : 1);		//鍥哄畾01
						end
			OPCODE:		begin
							cnt <= cnt + 1;
							mdio_out <= (cnt == 8'd35 ? 1 : 0);		//璇?10 鍐?01
						end
			PHYADDR:	begin
							cnt <= cnt + 1;
							case (cnt) 
								8'd37:	mdio_out <= 0;
								8'd38:	mdio_out <= 0;
								8'd39:	mdio_out <= 1;
								8'd40:	mdio_out <= 0;
								8'd41:	mdio_out <= 0;
							endcase
						end
			REGADDR:	begin
							cnt <= cnt + 1;
							case (cnt) 
								8'd42:	mdio_out <= 1;	//10001瀵勫瓨鍣?
								8'd43:	mdio_out <= 0;
								8'd44:	mdio_out <= 0;
								8'd45:	mdio_out <= 0;
								8'd46:	mdio_out <= 1;
							endcase
						end
			TURNDIR:	begin		//璇籞0 鍐?10
							cnt <= cnt + 1;
							mdio_out <= (cnt == 8'd47 ? 1'bz : 0);
						end
			READ:		begin
							mdio_dir <= 1'd0;
							cnt <= cnt + 1;
							data_out <= {data_out[14:0],mdio};
						end
		endcase
	end
end

ila_1 ila1 (
	.clk(clk), // input wire clk
	.probe0(state), // input wire [7:0]  probe0  
	.probe1(cnt), // input wire [7:0]  probe1 
	.probe2(next_state), // input wire [7:0]  probe2
	.probe3(data_out),
	.probe4(mdio), // input wire [0:0]  probe4 
	.probe5(mdio_out) // input wire [0:0]  probe5
);

endmodule

仿真截图:

可以看出,前32位前导码均为1,在cnt==33时,下两个时钟周期为01即start信号,在cnt==35时,下两个周期即OPCODE信号为10,即读操作,PHY物理地址为00100,这和芯片设计有关,寄存器地址是10001,选取的是特殊寄存器地址,读出的数据是0xbc40。

该寄存器的高四位为1011,高两位对应10即1000Mbps,验证:

链路速率确实为1Gbps,包括

链路实时状态位为1,连接状态。没问题。

代码只实现了读操作,写操作是一样的,有待读者自己完善。

接下来要实现ARP、UDP等通信协议。

 


http://www.kler.cn/a/452090.html

相关文章:

  • Mac上Stable Diffusion的环境搭建(还算比较简单)
  • 使用 OpenCV 绘制线条和矩形
  • React Native 集成原生Android功能
  • Mybatis 小结
  • Centos7中使用yum命令时候报错 “Could not resolve host: mirrorlist.centos.org; 未知的错误“
  • LeetCode 热题 100_LRU 缓存(35_146_中等_C++)(哈希表 + 双向链表)(构造函数声明+初始化列表=进行变量初始化和赋值)
  • C++ 特殊类的设计
  • 开发微信小程序的过程与心得
  • RuoYi-ue前端分离版部署流程
  • mac中idea菜单工具栏没有git图标了
  • 【HarmonyOS NEXT】hdc环境变量配置
  • 认识计算机网络
  • CosyVoice安装过程详解
  • Java基础学习资料
  • Visual Studio - API调试与测试工具之HTTP文件
  • 《战神:诸神黄昏》游戏运行时提示找不到emp.dll怎么办?emp.dll丢失如何修复?
  • 前端开发 -- 自定义鼠标指针样式
  • 【pytorch】深度学习计算
  • 三相异步电动机不能起动有哪些原因
  • jupyter下载使用及汉化
  • 中伟视界:AI识别摄像头+AI预警平台在矿山皮带空载监测中的应用
  • 用 gdbserver 调试 arm-linux 上的 AWTK 应用程序
  • linux中vi 或 vim 编辑文本自动换行错误
  • websocket 在 react 中使用
  • 《OpenCV计算机视觉》-对图片的各种操作(均值、方框、高斯、中值滤波处理)及形态学处理
  • Next.js 14 性能优化:从首屏加载到运行时优化的最佳实践