最近迷上了FPGA的网络通信和GTP光通信,个人感觉光通信简单一些,那就从难得网络通信开始吧,先搞个最简单的,使用MDIO配置和读取网络PHY的信息。 板子:米联客的MA703FA(A7-35T板子); 参考例程:正点原子达芬奇开发板例程; IDE:vivado2020.2; 具体的原理啥的建议去看正点原子的文档吧,讲得很好,但原子的例程感觉不贴近实际项目,所以我改了一下,使之适合真是项目。 先来看看这块芯片RTL8211FD的数据手册。 这是官方给的应用架构,很简单,RTL8211FD与MAC通信,通过MDC和MDIO配置。
芯片BD,没啥好说的,典型的rgmii接口,内部模块电路感觉没必要深究,反正也不懂,能用就行了。
硬件复位这里要注意,官方说应至少保持10ms低电平,最好还是按官方说的做,菜就要多听话。
芯片地址这里注意了,RTL8211FD器件地址由5位构成,高两位固定为2’b00,第三位后这三个引脚的上下拉电平决定,所以看看米联客板子的原理图:
由此可得:此RTL8211FD器件地址为:5’b00001; 这块芯片是不需要配置也能使用的,参考官方给的寄存器默认值可知,默认状态下芯片开启自协商,速率1000M,这就行了,已经不需要配置了,但为了学习,我们可以读状态寄存器,从而获得连接状态和通信速率。需要读两个状态寄存器:
第一是这个,需要读他的第2和第5位,
第2位:芯片和MAC连接成功; 第5位:芯片和MAC自协商成功;
还有这个寄存器,主要读芯片的通信速率;
第4到5位是通信速率; 好了,在看代码: MDIO控制器直接用原子的,写法和他们家的iic控制器类似,够骚,也够繁琐,但能用,菜就别讲究了吧。
//****************************************************************************************//
module mdio_dri #(
parameter PHY_ADDR = 5'b00001,//PHY地址
parameter CLK_DIV = 6'd10 //分频系数
)
(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效
input i_op_exec , //触发开始信号
input i_op_rh_wl , //低电平写,高电平读
input [4:0] i_op_addr , //寄存器地址
input [15:0] i_op_wr_data, //写入寄存器的数据
output reg o_op_done , //读写完成
output reg [15:0] o_op_rd_data, //读出的数据
output reg o_op_rd_ack , //读应答信号 0:应答 1:未应答
output reg o_dri_clk , //驱动时钟
output reg o_eth_mdc , //PHY管理接口的时钟信号
inout i_eth_mdio //PHY管理接口的双向数据信号
);
//parameter define
localparam st_idle = 6'b00_0001; //空闲状态
localparam st_pre = 6'b00_0010; //发送PRE(前导码)
localparam st_start = 6'b00_0100; //开始状态,发送ST(开始)+OP(操作码)
localparam st_addr = 6'b00_1000; //写地址,发送PHY地址+寄存器地址
localparam st_wr_data = 6'b01_0000; //TA+写数据
localparam st_rd_data = 6'b10_0000; //TA+读数据
//reg define
reg [5:0] cur_state ;
reg [5:0] next_state;
reg [5:0] clk_cnt ; //分频计数
reg [15:0] wr_data_t ; //缓存写寄存器的数据
reg [4:0] addr_t ; //缓存寄存器地址
reg [6:0] cnt ; //计数器
reg st_done ; //状态开始跳转信号
reg [1:0] op_code ; //操作码 2'b01(写) 2'b10(读)
reg mdio_dir ; //MDIO数据(SDA)方向控制
reg mdio_out ; //MDIO输出信号
reg [15:0] rd_data_t ; //缓存读寄存器数据
//wire define
wire mdio_in ; //MDIO数据输入
wire [5:0] clk_divide ; //PHY_CLK的分频系数
assign i_eth_mdio = mdio_dir ? mdio_out : 1'bz; //控制双向io方向
assign mdio_in = i_eth_mdio; //MDIO数据输入
//将PHY_CLK的分频系数除以2,得到dri_clk的分频系数,方便对MDC和MDIO信号操作
assign clk_divide = CLK_DIV >> 1;
//分频得到dri_clk时钟
always @(posedge clk) begin
if(!rst_n) begin
o_dri_clk
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?