我们接上一讲,要搞懂这一节的内容需要仔细分析一下mdio_ctrl的代码,在百兆以太网中,我们使用的YT8511芯片是需要关闭自协商模式的,也就是寄存器地址为0X00的第12位要置为0,寄存器定义如下图所示:
其次,在第13位上,通过芯片手册可以了解到,百兆网络的寄存器设置是如下所示的:
也就是将第6位设置为0,第13位设置为1
这个过程也是想教大家学会如何看芯片手册
设置的代码如下所示:
if(rst_trig_flag) begin //开始对MDIO接口进行软复位
op_exec <= 1'b1;
op_rh_wl <= 1'b0; //低电平是写信号,代表开始写数据
op_addr <= 5'h0;
op_wr_data <= 16'hA100; //Bit[15]=1'b1,表示软复位
flow_cnt <= 3'd1;
end
如上述代码所示,op_addr是设置寄存器地址为0x00,也就是下图的寄存器
然后将op_wr_data设置为A100,二进制就是1010 0001 0000 0000,可以看到,第6位和第13位分别是0和1,第12位为0,第15位是软复位,默认为1,这样就可以将以太网设置为百兆,时钟频率就为25MHZ了。
修改后的mdio_ctrl完整代码如下,其他模块的代码基本没有改动:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/07/29 17:34:16
// Design Name:
// Module Name: mdio_ctrl
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module mdio_ctrl(
input clk ,
input rst_n ,
input soft_rst_trig , //软复位触发信号 按键按下代表软复位触发
input op_done , //读写完成
input [15:0] op_rd_data , //读出的数据
input op_rd_ack , //读应答信号 0:应答 1:未应答
output reg op_exec , //触发开始信号
output reg op_rh_wl , //低电平写,高电平读
output reg [4:0] op_addr , //寄存器地址
output reg [15:0] op_wr_data , //写入寄存器的数据
output [1:0] led , //LED灯指示以太网连接状态
//test
output timer_cnt ,
output timer_done ,
output [2:0] flow_cnt ,
output pos_rst_trig,
output [1:0] speed_status,
output link_error
);
parameter TIME_CNT = 24'd1_000_000;
//reg define
reg rst_trig_d0;
reg rst_trig_d1;
reg rst_trig_d2;
reg rst_trig_flag; //soft_rst_trig信号触发标志
reg [23:0] timer_cnt; //定时计数器
reg timer_done; //定时完成信号
reg start_next; //开始读下一个寄存器标致
reg read_next; //处于读下一个寄存器的过程
reg link_error; //链路断开或者自协商未完成
reg [2:0] flow_cnt; //流程控制计数器
reg [1:0] speed_status; //连接速率
//wire define
wire pos_rst_trig; //soft_rst_trig信号上升沿
//采soft_rst_trig信号上升沿
assign pos_rst_trig = ~rst_trig_d2 & rst_trig_d1;
//未连接或连接失败时led赋值11
// 10:10Mbps 01:100Mbps 00:1000Mbps 11:其他情况
assign led = speed_status;
//对soft_rst_trig信号延时打拍
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rst_trig_d0 <= 1'b0;
rst_trig_d1 <= 1'b0;
rst_trig_d2 <= 1'b0;
end
else begin
rst_trig_d0 <= soft_rst_trig;
rst_trig_d1 <= rst_trig_d0;
rst_trig_d2 <= rst_trig_d1;
end
end
//定时计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
timer_cnt <= 1'b0;
timer_done <= 1'b0;
end
else begin
if(timer_cnt == TIME_CNT - 1'b1) begin
timer_done <= 1'b1;
timer_cnt <= 1'b0;
end
else begin
timer_done <= 1'b0;
timer_cnt <= timer_cnt + 1'b1;
end
end
end
//根据软复位信号对MDIO接口进行软复位,并定时读取以太网的连接状态
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
flow_cnt <= 3'd0;
rst_trig_flag <= 1'b0;
speed_status <= 2'b00;
op_exec <= 1'b0;
op_rh_wl <= 1'b0;
op_addr <= 5'h0;
op_wr_data <= 16'h0;
start_next <= 1'b0;
read_next <= 1'b0;
//link_error <= 1'b0;
end
else begin
op_exec <= 1'b0;
if(pos_rst_trig)
rst_trig_flag <= 1'b1; //拉高软复位触发标志
case(flow_cnt)
2'd0 : begin
if(rst_trig_flag) begin //开始对MDIO接口进行软复位
op_exec <= 1'b1;
op_rh_wl <= 1'b0; //低电平是写信号,代表开始写数据
op_addr <= 5'h0;
op_wr_data <= 16'hA100; //Bit[15]=1'b1,表示软复位
flow_cnt <= 3'd1;
end
else if(timer_done) begin //定时完成,获取以太网连接状态
op_exec <= 1'b1;
op_rh_wl <= 1'b1;
//op_addr <= 5'h05; //用于仿真
op_addr <= 5'h01; //地址
flow_cnt <= 3'd2;
end
else if(start_next) begin //开始读下一个寄存器,获取以太网通信速度
op_exec <= 1'b1;
op_rh_wl <= 1'b1;
op_addr <= 5'h11; //寄存器地址
//op_addr <= 5'h06; //用于仿真
flow_cnt <= 3'd2;
start_next <= 1'b0;
read_next <= 1'b1;
end
end
2'd1 : begin
if(op_done) begin //MDIO接口软复位完成
flow_cnt <= 3'd0;
rst_trig_flag <= 1'b0;
end
end
2'd2 : begin
if(op_done) begin //MDIO接口读操作完成
if(op_rd_ack == 1'b0 && read_next == 1'b0) //读第一个寄存器,接口成功应答,
flow_cnt <= 3'd3;
else if(op_rd_ack == 1'b0 && read_next == 1'b1)begin //读下一个寄存器,接口成功应答
read_next <= 1'b0;
flow_cnt <= 3'd4;
end
else begin
flow_cnt <= 3'd0;
end
end
end
2'd3 : begin
flow_cnt <= 3'd0; //链路正常
//if(op_rd_data[5] == 1'b1 && op_rd_data[2] == 1'b1)begin
start_next <= 1;
//link_error <= 0;
//end
//else begin
// link_error <= 1;
//end
end
3'd4: begin
flow_cnt <= 3'd0;
if(op_rd_data[15:14] == 2'b10)
speed_status <= 2'b00; //1000Mbps
else if(op_rd_data[15:14] == 2'b01)
speed_status <= 2'b01; //100Mbps
else if(op_rd_data[15:14] == 2'b00)
speed_status <= 2'b10; //10Mbps
else
speed_status <= 2'b11; //其他情况
end
endcase
end
end
endmodule