浅谈FPGA网络PHY芯片RTL8211FD的配置和简单使用

2023-05-16

最近迷上了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 <=  1'b0;
        clk_cnt <= 1'b0;
    end
    else if(clk_cnt == clk_divide[5:1] - 1'd1) begin
        clk_cnt <= 1'b0;
        o_dri_clk <= ~o_dri_clk;
    end
    else clk_cnt <= clk_cnt + 1'b1;
end

//产生PHY_MDC时钟
always @(posedge o_dri_clk) begin
    if(!rst_n) o_eth_mdc <= 1'b1;
    else if(cnt[0] == 1'b0) o_eth_mdc <= 1'b1;
    else o_eth_mdc <= 1'b0;  
end

//(三段式状态机)同步时序描述状态转移
always @(posedge o_dri_clk) begin
    if(!rst_n) cur_state <= st_idle;
    else cur_state <= next_state;
end  

//组合逻辑判断状态转移条件
always @(*) begin
    next_state = st_idle;
    case(cur_state)
        st_idle : begin
            if(i_op_exec) next_state = st_pre;
            else next_state = st_idle;   
        end  
        st_pre : begin	//发送前导码,32'hffffffff
            if(st_done) next_state = st_start;
            else next_state = st_pre;
        end
        st_start : begin	//ST+OP=2'b01+2'bxx
            if(st_done) next_state = st_addr;
            else next_state = st_start;
        end
        st_addr : begin	//PHYAD+REGAD
            if(st_done) begin
                if(op_code == 2'b01) next_state = st_wr_data;	//MDIO接口写操作                     
                else next_state = st_rd_data; //MDIO接口读操作                            
            end
            else next_state = st_addr;               
        end
        st_wr_data : begin
            if(st_done) next_state = st_idle;
            else next_state = st_wr_data;
        end        
        st_rd_data : begin
            if(st_done) next_state = st_idle;
            else next_state = st_rd_data;
        end                                                                          
        default : next_state = st_idle;
    endcase
  end

//时序电路描述状态输出
always @(posedge o_dri_clk) begin
    if(!rst_n) begin
        cnt <= 5'd0;
        op_code <= 1'b0;
        addr_t <= 1'b0;
        wr_data_t <= 1'b0;
        rd_data_t <= 1'b0;
        o_op_done <= 1'b0;
        st_done <= 1'b0; 
        o_op_rd_data <= 1'b0;
        o_op_rd_ack <= 1'b1;
        mdio_dir <= 1'b0;
        mdio_out <= 1'b1;
    end
    else begin
        st_done <= 1'b0 ;                            
        cnt     <= cnt +1'b1 ;          
        case(cur_state)
            st_idle : begin
                mdio_out <= 1'b1;                     
                mdio_dir <= 1'b0;                     
                o_op_done <= 1'b0;                     
                cnt <= 7'b0;  
                if(i_op_exec) begin
                    op_code <= {i_op_rh_wl,~i_op_rh_wl}; //OP_CODE: 2'b01(写)  2'b10(读) 
                    addr_t <= i_op_addr;
                    wr_data_t <= i_op_wr_data;
                    o_op_rd_ack <= 1'b1;
                end     
            end 
            st_pre : begin                          //发送前导码:32个1bit 
                mdio_dir <= 1'b1;                   //切换MDIO引脚方向:输出
                mdio_out <= 1'b1;                   //MDIO引脚输出高电平
                if(cnt == 7'd62) st_done <= 1'b1;
                else if(cnt == 7'd63) cnt <= 7'b0;
            end            
            st_start  : begin
                case(cnt)
                    7'd1 : mdio_out <= 1'b0;        //发送开始信号 2'b01
                    7'd3 : mdio_out <= 1'b1; 
                    7'd5 : mdio_out <= op_code[1];  //发送操作码
                    7'd6 : st_done <= 1'b1;
                    7'd7 : begin
                               mdio_out <= op_code[0];
                               cnt <= 7'b0;  
                           end    
                    default : ;
                endcase
            end    
            st_addr : begin
                case(cnt)
                    7'd1 : mdio_out <= PHY_ADDR[4]; //发送PHY地址
                    7'd3 : mdio_out <= PHY_ADDR[3];
                    7'd5 : mdio_out <= PHY_ADDR[2];
                    7'd7 : mdio_out <= PHY_ADDR[1];  
                    7'd9 : mdio_out <= PHY_ADDR[0];
                    7'd11: mdio_out <= addr_t[4];  //发送寄存器地址
                    7'd13: mdio_out <= addr_t[3];
                    7'd15: mdio_out <= addr_t[2];
                    7'd17: mdio_out <= addr_t[1];  
                    7'd18: st_done <= 1'b1;
                    7'd19: begin
                               mdio_out <= addr_t[0]; 
                               cnt <= 7'd0;
                           end    
                    default : ;
                endcase                
            end    
            st_wr_data : begin
                case(cnt)
                    7'd1 : mdio_out <= 1'b1;         //发送TA,写操作(2'b10)
                    7'd3 : mdio_out <= 1'b0;
                    7'd5 : mdio_out <= wr_data_t[15];//发送写寄存器数据
                    7'd7 : mdio_out <= wr_data_t[14];
                    7'd9 : mdio_out <= wr_data_t[13];
                    7'd11: mdio_out <= wr_data_t[12];
                    7'd13: mdio_out <= wr_data_t[11];
                    7'd15: mdio_out <= wr_data_t[10];
                    7'd17: mdio_out <= wr_data_t[9];
                    7'd19: mdio_out <= wr_data_t[8];
                    7'd21: mdio_out <= wr_data_t[7];
                    7'd23: mdio_out <= wr_data_t[6];
                    7'd25: mdio_out <= wr_data_t[5];
                    7'd27: mdio_out <= wr_data_t[4];
                    7'd29: mdio_out <= wr_data_t[3];
                    7'd31: mdio_out <= wr_data_t[2];
                    7'd33: mdio_out <= wr_data_t[1];
                    7'd35: mdio_out <= wr_data_t[0];
                    7'd37: begin
                        mdio_dir <= 1'b0;
                        mdio_out <= 1'b1;
                    end
                    7'd39: st_done <= 1'b1;           
                    7'd40: begin
                               cnt <= 7'b0;
                               o_op_done <= 1'b1;      //写操作完成,拉高op_done信号 
                           end    
                    default : ;
                endcase    
            end
            st_rd_data : begin
                case(cnt)
                    7'd1 : begin
                        mdio_dir <= 1'b0;            //MDIO引脚切换至输入状态
                        mdio_out <= 1'b1;
                    end
                    7'd2 : ;                         //TA[1]位,该位为高阻状态,不操作             
                    7'd4 : o_op_rd_ack <= mdio_in;     //TA[0]位,0(应答) 1(未应答)
                    7'd6 : rd_data_t[15] <= mdio_in; //接收寄存器数据
                    7'd8 : rd_data_t[14] <= mdio_in;
                    7'd10: rd_data_t[13] <= mdio_in;
                    7'd12: rd_data_t[12] <= mdio_in;
                    7'd14: rd_data_t[11] <= mdio_in;
                    7'd16: rd_data_t[10] <= mdio_in;
                    7'd18: rd_data_t[9] <= mdio_in;
                    7'd20: rd_data_t[8] <= mdio_in;
                    7'd22: rd_data_t[7] <= mdio_in;
                    7'd24: rd_data_t[6] <= mdio_in;
                    7'd26: rd_data_t[5] <= mdio_in;
                    7'd28: rd_data_t[4] <= mdio_in;
                    7'd30: rd_data_t[3] <= mdio_in;
                    7'd32: rd_data_t[2] <= mdio_in;
                    7'd34: rd_data_t[1] <= mdio_in;
                    7'd36: rd_data_t[0] <= mdio_in;
                    7'd39: st_done <= 1'b1;
                    7'd40: begin
                        o_op_done <= 1'b1;             //读操作完成,拉高op_done信号          
                        o_op_rd_data <= rd_data_t;
                        rd_data_t <= 16'd0;
                        cnt <= 7'd0;
                    end
                    default : ;
                endcase   
            end                
            default : ;
        endcase               
    end
end                    

endmodule

然后是控制逻辑,原子的例程是通过触摸按键软复位RTL8211FD,然后再读那两个寄存器,感觉没啥用,自己重写了一个,功能是硬件复位完成后直接循环读那两个寄存器,如果自协商完成且连接成功,led亮,否则灭,再用另个led来只是当前的通信速率,直接上代码:

//****************************************************************************************//
module mdio_ctrl(
(* mark_debug ="true" *)    input                clk           ,
(* mark_debug ="true" *)    input                rst_n         ,

(* mark_debug ="true" *)    input                i_op_done     , //读写完成
(* mark_debug ="true" *)    input        [15:0]  i_op_rd_data  , //读出的数据
(* mark_debug ="true" *)    input                i_op_rd_ack   , //读应答信号 0:应答 1:未应答
(* mark_debug ="true" *)    output  reg          o_op_exec     , //触发开始信号
(* mark_debug ="true" *)    output  reg          o_op_rh_wl    , //低电平写,高电平读
(* mark_debug ="true" *)    output  reg  [4:0]   o_op_addr     , //寄存器地址

(* mark_debug ="true" *)   input                i_eth_rst_n   ,
(* mark_debug ="true" *)   output  reg          o_link_led    ,
(* mark_debug ="true" *)   output  reg  [1:0]   o_speed_led 
    );

(* mark_debug ="true" *) reg  [2:0]   flow_cnt;        //流程控制计数器 

always @(posedge clk) begin
	if(!rst_n) begin
		flow_cnt <= 3'd0;
//		link_error <= 1'b0;
		o_op_exec <= 1'b0; 
	    o_op_rh_wl <= 1'b0; 
	    o_op_addr <= 1'b0;   
//	    op_wr_data <= 1'b0;
		o_link_led <= 1'b0;
		o_speed_led<= 2'b0;
	end
	else begin
		case(flow_cnt)
			3'd0:begin
				if(i_eth_rst_n) flow_cnt <= 3'd1;	//reste_n is ok
			end
			3'd1: begin
				o_op_exec <= 1'b1;	//开始操作MDIO
				o_op_rh_wl<= 1'b1;	//读操作
				o_op_addr <= 5'h01;	//读BMSR状态寄存器
				flow_cnt<= 3'd2;
			end
			3'd2: begin
				if(i_op_done) begin	//读操作完成
					if(!i_op_rd_ack) flow_cnt<= 3'd3; //phy应答,做后续判断
					else flow_cnt<= 3'd1;			//phy未应答,重新发起读BMSR状态寄存器				
				end
			end
			3'd3: begin
				if(i_op_rd_data[5] == 1'b1 && i_op_rd_data[2] == 1'b1) begin
					o_link_led<=1'b1;	//自协商完成,link完成
					flow_cnt<=3'd4;
				end
				else o_link_led<=1'b0;			
			end
			3'd4: begin		//读PHYSR特定状态寄存器
				o_op_addr <= 5'h1A;
				flow_cnt<= 3'd5;			
			end
			3'd5: begin
				if(i_op_done) begin	//读操作完成
					if(!i_op_rd_ack) flow_cnt<= 3'd6; //phy应答,做后续判断
					else flow_cnt<= 3'd4;			//phy未应答,重新发起读PHYSR特定状态寄存器
				end
			end						
			3'd6: begin
				flow_cnt<=3'd1;
				if(i_op_rd_data[5:4] == 2'b10) o_speed_led<=2'b11; 		//1000Mbps
				else if(i_op_rd_data[5:4] == 2'b01) o_speed_led<=2'b01; 	//100Mbps
				else if(i_op_rd_data[5:4] == 2'b00) o_speed_led<=2'b10; 	//100Mbps
				else o_speed_led<= 2'b0;                                 
			end
		default: flow_cnt <= 3'd0;
		endcase
	end
end

endmodule

最后是顶层,这里加了硬件复位的10ms,之前说了,菜就别嫌麻烦,跟官方走:

module mdio_rw_test(
    input          sys_clk    ,
    output         eth_mdc    , //PHY管理接口的时钟信号
    inout          eth_mdio   , //PHY管理接口的双向数据信号
    output         eth_rst_n  , //以太网复位信号
	output         o_link_led ,
    output  [1:0]  o_speed_led        //LED连接速率指示
    );
    
//wire define
wire          op_exec    ;  //触发开始信号
wire          op_rh_wl   ;  //低电平写,高电平读
wire  [4:0]   op_addr    ;  //寄存器地址
wire  [15:0]  op_wr_data ;  //写入寄存器的数据
wire          op_done    ;  //读写完成
wire  [15:0]  op_rd_data ;  //读出的数据
wire          op_rd_ack  ;  //读应答信号 0:应答 1:未应答
wire          dri_clk    ;  //驱动时钟
wire rsn_n;
wire clk_50m;

 clk_wiz_0 u_clk_wiz_0
   (
    // Clock out ports
    .clk_out1(clk_50m),     // output clk_out1
    // Status and control signals
    .locked(rsn_n),       // output locked
   // Clock in ports
    .clk_in1(sys_clk));      // input clk_in1

localparam T_10MS = 10_000_000;	//10ms=10_000_000ns
localparam T_P    = 20        ; //50M周期=20ns
localparam RST_CNT= T_10MS/T_P+10;
reg  [18:0]  eth_rsrn_cnt; 
reg o_eth_rst_n;
//根据数据手册,硬件复位至少10ms的低电平
always @(posedge clk_50m) begin
	if(!rsn_n) eth_rsrn_cnt<='d0;
	else if(eth_rsrn_cnt==RST_CNT) eth_rsrn_cnt<=RST_CNT;
	else eth_rsrn_cnt<=eth_rsrn_cnt+19'd1;
end

always @(posedge clk_50m) begin
	if(!rsn_n) o_eth_rst_n<='d0;
	else if(eth_rsrn_cnt==RST_CNT) o_eth_rst_n<=1'd1;
	else o_eth_rst_n<=1'd0;
end

//硬件复位
assign eth_rst_n = o_eth_rst_n;

//MDIO接口驱动
mdio_dri #(
    .PHY_ADDR    (5'h01),   //PHY地址
    .CLK_DIV     (6'd10)    //分频系数
    )
    u_mdio_dri(
    .clk         (clk_50m   ),
    .rst_n       (rsn_n     ),
    .i_op_exec   (op_exec   ),
    .i_op_rh_wl  (op_rh_wl  ),   
    .i_op_addr   (op_addr   ),   
    .i_op_wr_data(op_wr_data),   
    .o_op_done   (op_done   ),   
    .o_op_rd_data(op_rd_data),   
    .o_op_rd_ack (op_rd_ack ),   
    .o_dri_clk   (dri_clk   ),                   
    .o_eth_mdc   (eth_mdc   ),   
    .i_eth_mdio  (eth_mdio  )   
);      

mdio_ctrl u_mdio_ctrl(
    .clk           (dri_clk    ),
    .rst_n         (rsn_n      ),
    .i_op_done     (op_done    ), //读写完成
    .i_op_rd_data  (op_rd_data ), //读出的数据
    .i_op_rd_ack   (op_rd_ack  ), //读应答信号 0:应答 1:未应答
    .o_op_exec     (op_exec    ), //触发开始信号
    .o_op_rh_wl    (op_rh_wl   ), //低电平写,高电平读
    .o_op_addr     (op_addr    ), //寄存器地址
	.i_eth_rst_n   (o_eth_rst_n),
	.o_link_led    (o_link_led ),
	.o_speed_led   (o_speed_led)
    );
endmodule

结果:灯亮,成功
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

浅谈FPGA网络PHY芯片RTL8211FD的配置和简单使用 的相关文章

  • FPGA笔记8——串口通信(回环实验)

    目录 串口通信原理 串行通信基础知识 处理器与外部设备通信的两种方式 串行通信的通信方式 串行通信的传输方向 常见的串行通信接口 异步串口通信UART基础知识 数据格式 传输速率 接口标准 RS232接口 串口通信实验RS 232 实验任务
  • Quartus II 安装

    本次介绍使用的 Quartus 版本为 10 1 目前 Quartus II 官网已经没有 13 1 以下版本的安装包 大家可以安装 13 1 以上版本的软件 功能都是大同小异 下载地址 FPGA Software Download Cen
  • 在vivado中使用tcl脚本(UG894)

    本文源自UG894 主要介绍如何在vivado中使用tcl脚本 1 vivado中如何获取tcl help vivado中任何自带的命令都可以通过 help 获取帮助信息 也可以直接输入 help 取得vivado命令合集 并通过 help
  • Ubuntu16.04主机安装基于ZYNQ的QT交叉编译库

    Ubuntu16 04主机尝试安装基于ZYNQ的QT交叉编译库 前言 基于vivado2016 4 SDK的交叉编译环境 主机Linux上安装vivado2016 4版本 qtcreator上添加基于ZYNQ的交叉编译工具 基本环境 参考资
  • cdc多bit信号-握手处理

    对于多bit数据跨时钟 各个bit之间路径延迟不一样 源时钟域给的数据是2 b11 目的时钟域采样到的数据可能2 b10 因此两级触发器对于单bit数据跨时钟是可以用的 但是对于多bit数据跨时钟就会出错 握手处理的关键是利用源的时钟req
  • Xilinx ISE系列教程(9):LabTools下载、安装、使用教程(独立的下载工具)

    文章目录 1 ISE Vivado LabTools简介 2 ISE 14 7 Lab Tools下载 安装 3 Vivado 2018 3 LabTools下载 安装 1 ISE Vivado LabTools简介 Xilinx LabT
  • Xilinx平台SRIO介绍(二)SRIO IP核基础知识

    使用SRIO IP核必须掌握的基础知识 理解了这篇 剩下的只是代码罢了 汇总篇 Xilinx平台SRIO介绍 汇总篇 目录 前言 SRIO RapidIO GT 有什么关系
  • verilog中wire和reg类型的区别

    module counter parameter CNT MAX 25 d24 999 999 input wire sys clk input wire sys rst n output reg led out reg 24 0 cnt
  • Xilinx 7系列芯片选型手册的资源量怎么看

    推荐阅读AMD官方文档 该文档介绍了各种资源的具体含义 链接 7 Series FPGAs Configurable Logic Block User Guide UG474 以XC7A35T为例 Logic Cells 逻辑单元 对于7系
  • 【Xilinx】SynchronousInterruptHandler错误排查笔记

    SynchronousInterruptHandler错误排查笔记 一 ArmV8的异常处理 二 64位lscript ld的修改 三 asm vectors S的修改 四 SynchronousInterruptHandler函数解析 五
  • HDLBits刷题_Verilog Language_Procedures_Alwaysblock1

    学习内容 Since digital circuits are composed of logic gates connected with wires any circuit can be expressed as some combin
  • Xilinx AXI-memory接口 转 AXI-stream 接口(含源码)

    AXI memory接口 转 AXI stream 接口 AXI memory接口介绍 具体详情可以查看源码 AXI memory接口介绍 从图中我们可以看出memory接口有5个通道 分别是读地址通道 写地址通道 写响应通道 读数据通道
  • Verilog的基础知识

    Verilog的基本介绍 硬件描述语言发展至今已有二十多年历史 当今业界的标准中 IEEE标准 主要有VHDL和Verilog HDL 这两种硬件描述语言 一个设计往往从系统级设计开始 把系统划分成几个大的基本的功能模块 每个功能模块再按一
  • [HDLBits] Exams/ece241 2014 q7a

    Design a 1 12 counter with the following inputs and outputs Reset Synchronous active high reset that forces the counter
  • 64 位 ALU 输出在 TestBench 波上显示高阻抗

    我必须制作一个 64 位 ALU 它接受 A 和 B 64 位输入 进位输入输入并输出 64 位结果以及 1 位进位输出 还有一个 5 位功能选择 FS 其中 FS 0 控制 B 是否反转 使用 2to1 多路复用器 F 1 对 A 执行相
  • 在vhdl中生成随机整数

    我需要在 vhdl 中生成 0 1023 之间的随机整数 但是我在互联网上找不到这方面的好资源 请问有人帮我吗 下面是生成范围 0 1023 内均匀 均匀 分布的整数的示例 请注意 floor必须在与最大值 1 相乘之后使用运算 在本例中为
  • 异步FIFO设计之格雷码

    目录 二进制转格雷码 格雷码转二进制 相邻的格雷码只有1bit的差异 因此格雷码常常用于异步fifo设计中 保证afifo的读地址 或写地址 被写时钟 或读时钟 采样时最多只有1bit发生跳变 在不考虑路径延时的情况下 因为源数据 读写地址
  • VHDL - PhysDesignRules:367

    当我尝试从 VHDL 代码合成 实现和生成程序文件时 我收到警告 当我尝试合成时出现此错误 WARNING Xst 647 Input
  • 使用双寄存器方法解决亚稳态问题

    为了解决Verilog中不同时钟域引起的亚稳态 采用双寄存器方法 但据我所知 亚稳态的最终输出尚未确定 输出独立于输入 那么 我的问题是如何保证使用双寄存器方法输出的正确性 Thanks 您不能完全确定您避免了亚稳态 正如您所提到的 亚稳态
  • FPGA 有哪些实际应用?

    我对我的程序为一个小型七段显示器提供动力感到非常兴奋 但是当我向不在现场的人展示它时 他们总是说 那么你能用它做什么 我永远无法给他们一个简洁的答案 谁能帮我吗 第一 它们不需要具有易失性存储器 事实上 大厂商 Xilinx Altera

随机推荐

  • 进程中产生僵尸和孤儿

    孤儿进程 父进程先于子进程结束 xff0c 则子进程成为孤儿进程 xff0c 子进程的父进程成为init进程 xff0c 称为init进程领养孤儿进程 孤儿进程其实对于操作系统来说是没有太大的危害 xff0c 在孤儿进程中父进程结束了之后
  • C++Primer Plus第6版&C Primer Plus第6版 中文版免费分享啦

    最近在学习C 43 43 xff0c 用的资料是师兄分享的经典书籍 C 43 43 Primer Plus第6版中文版 的PDF xff0c 自带书签 xff0c 使用很方便 但师兄说这个是他在网上花了积分才下载下来的 xff0c 这让我很
  • www服务器是什么

    WWW是一种服务 我们在浏览器的地址栏里输入的网站地址叫做URL Uniform Resource Locator xff0c 统一资源定位符 就像每家每户都有一个门牌地址一样 xff0c 每个网页也都有一个Internet地址 当你在浏览
  • 快速配置VSCode(Visual Studio Code) C/C++开发环境

    简介 VSCode只是一个纯文本编辑器 editor xff0c 不是IDE 集成开发环境 xff0c 不含编译器 compiler 和许多其他功能 xff0c 所以需要自己先搭建环境 但是对小白朋友来说 xff0c 面对一堆的环境变量操作
  • c++:如何定义一个头文件来使用类

    定义自己的头文件 定义类为了方便起见 xff0c 一般不在某个函数内部去定义 要在不同文件中使用同一个类 xff0c 类的定义就必须保持一致 因此考虑拆分一个类 xff0c 在头文件内声明类和其中的成员函数 xff0c 在源文件中写该类的实
  • Ubuntu can口状态检查

    1 配置can0 设置比特率 sudo ip link set can0 type can bitrate 250000 2 打开can0 sudo ip link set can0 up 3 查看 信息 ip details link s
  • Arduino读取DHT11的温湿度显示在基于I2C的1602上

    背景摘要 又到了周末 xff0c B站的番还未更新 闲来无事 xff0c 搞搞吃灰已久的Arduino 南方的冬天真冷啊 xff0c 测测屋子里的温湿度怎么样 xff01 为了测量屋子里的温湿度 xff0c 就用简单大方的Arduino x
  • 终于解决:CUDA: OpenCV requires enabled ‘cudev‘ module from ‘opencv_contrib‘

    把opencv contrib放到opencv文件夾下就行了 編譯到99 時會卡好久 大概半個小時 16線程的CPU 耐心等待即可 編譯的選項 cmake D CMAKE INSTALL PREFIX 61 usr local D CMAK
  • rviz出现Transform [sender=unknown_publisher]For frame [hokuyo_link]: Fixed Frame [map] does not exist

    这是因为本身建模的时候没有用tf包工具发布global fixed frame到topic所在坐标系的tf关系 xff0c 通俗来讲就是模型fixed frame与rviz的不匹配 解决办法 xff1a 修改Fixed frame xff0
  • 镜像后的图片的ORB特征提取

    原图1 xff0c 原图2 xff0c 水平镜像后的原图2 xff1a 用opencv4自带的ORB提取 xff1a 所有的配对如下 筛选后的配对如下 xff1a 可见 xff0c 过滤了一些匹配错误特征点 xff0c 但是还是有很多错误的
  • 构造函数与重载构造函数

    发现slam程序里有个这种写法 在mappoint h中写的如下 MapPoint XXX 重载构造函数 一个默认 new的时候用 一个含参 MapPoint long id Vec3 position 在mappoint cpp中有含参构
  • 内存指针mm_struct

    我们在使用fork 产生了一个子进程 xff0c 子进程和父进程都是执行的相同的代码 xff0c 此时我们又是如何进程执行的呢 虚拟地址空间和物理内存 这就是我们的虚拟地址空间 xff0c 他实际上是使用一个结构体mm struct结构体去
  • Cartographer源码阅读---开始轨迹的相关处理

    上一节我们看了一下node main cc的内容 发现其中最重要的部分就是Node类 这个类吃下了map builder类 且里面实现了传感器数据的处理与分发 sensor bridge 还有整个Cartographer算法的调用 map
  • C++程序, 执行程序加上-v显示版本号的方法

    先宏定义 span class token macro property span class token directive hash span span class token directive keyword define span
  • cartographer源码阅读---位姿推测器

    工程化的cartographer框架为了实现实时可靠的位姿推断 在算法中实现了位姿推测器 pose extrapolator 其作用是通过现有的有关机器人位姿的数据 给前端匹配一个可靠的目标值进行ceres优化 也就是以位姿推测器推出来的位
  • c++程序从.bashrc读取变量并赋值给变量

    有时候cpp程序需要从 bashrc中读取变量进行初始化 这样可以在不同的主机环境中执行不同的配置参数 十分有用 首先我们要在 bashrc 中定义变量名 export 变量名 61 变量 如 export MY PARAM PREFIX
  • Cartographer源码阅读---前端扫描匹配

    Cartographer前端扫描匹配的方式分为两种 xff0c 一种是相关性扫描匹配 xff0c 说白了就是暴力搜索 xff0c 很无脑效率很低 我觉得根本不算是算法 就不细说了 另一种就是ceres优化 1 相关性扫描匹配 xff08 C
  • linux下的vivado工程卡顿或编译时间具长的解决方案

    linux下的vivado工程卡顿或编译时间具长的解决方案 有时 xff0c 你的vivado工程可能无缘由卡顿 xff0c 或者编译时间具长 xff0c vivado窗口显示一直在更新工程 xff0c 或者综合时显示一直在准备 此时 xf
  • 米联客FDMA及其控制器代码逐行讲解,全网最细,不接受反驳

    米联客FDMA及其控制器代码逐行讲解 xff0c 全网最细 xff0c 不接受反驳 对于做图像处理的兄弟来说 xff0c 图像缓存是基本操作 xff0c 一般是图像三帧缓存于DDR3 xff0c 然后再读出显示 xff0c DDR3操作很复
  • 浅谈FPGA网络PHY芯片RTL8211FD的配置和简单使用

    最近迷上了FPGA的网络通信和GTP光通信 xff0c 个人感觉光通信简单一些 xff0c 那就从难得网络通信开始吧 xff0c 先搞个最简单的 xff0c 使用MDIO配置和读取网络PHY的信息 板子 xff1a 米联客的MA703FA