IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Xilinx的IP核gig_ethernet_pcs_pma例化案例 -> 正文阅读

[嵌入式]Xilinx的IP核gig_ethernet_pcs_pma例化案例

1G/2.5G Ethernet PCS/PMA or SGMII v16.1

废话不BB,直接用。手册看完,一礼拜没理解透。理解出现偏差。最后实验出真知。

IP核例化

gig_ethernet_pcs_pma_0 gig_ethernet_pcs_pma_0 (
  .gtrefclk_p				(gtrefclk1_p), //不废话  
  .gtrefclk_n				(gtrefclk1_n), //不废话  
  .gtrefclk_out				(),                      	
  .gtrefclk_bufg_out		(),           				
  .txn						(sfp_tx_n),    //不废话  
  .txp						(sfp_tx_p),    //不废话
  .rxn						(sfp_rx_n),    //不废话    
  .rxp						(sfp_rx_p),    //不废话    
  .independent_clock_bufg	(clk_200M),  //200M时钟
  .userclk_out				(),                       	
  .userclk2_out				(gmii_clk),    //125M时钟,死的,不会变
  .rxuserclk_out			(),                    		
  .rxuserclk2_out			(),                    		
  .resetdone				(),                           
  .pma_reset_out			(),                    		
  .mmcm_locked_out			(),               			
  .sgmii_clk_r				(),                        	
  .sgmii_clk_f				(),                        	
  .sgmii_clk_en				(sgmii_clk_en), //可变脉冲,125M,12.5M,1.25M             
  .gmii_txd					(gmii_txd	),  //发送数据,必须顺应百兆或千兆  
  .gmii_tx_en				(gmii_tx_en	),  //发送数据,必须顺应百兆或千兆    
  .gmii_tx_er				('b0),        	//甭管,直接置0
  .gmii_rxd					(gmii_rxd	),  //接受数据,随百兆或千兆  
  .gmii_rx_dv				(gmii_rx_dv	),  //接受数据,随百兆或千兆
  .gmii_rx_er				(			),  //不需要          
  .gmii_isolate				(			),  //不需要
  .configuration_vector		(5'b10000	),  //写死,[4]=1,启动自协商    		
  .an_interrupt				(an_interrupt), //=1,链路已链接,Link up   
  .an_adv_config_vector		(16'h8821	),  //妈的,就是这个坑死人,写死半双工千兆,这是我的最佳选择    		
  .an_restart_config		('b0		),  //一样坑死人,上面写死了,不用上升沿触发重启         	
  .speed_is_10_100			(speed_is_10_100), //和下面一起控制sgmii_clk_en的频率的
  .speed_is_100				(speed_is_100	), //和上面一起控制sgmii_clk_en的频率的
  .status_vector			(			),     //最坑人,对端是强制端,根本就不反应协商信息,要了何用           
  .reset					(!rst_n			), //随便复位一下       
  .signal_detect			(1'b1			), //1表示不是光口。           
  .gt0_pll0outclk_out		(),   					      
  .gt0_pll0outrefclk_out	(),   					 	
  .gt0_pll1outclk_out		(),   					      
  .gt0_pll1outrefclk_out	(),   					 	
  .gt0_pll0lock_out			(),              			
  .gt0_pll0refclklost_out	()  						
);	    

计数开头的55,判断1000M或者100M

对端是强制端。比如设置电脑端为,100M半双工。即使an_adv_config_vector设置1000M,底层自协商就能连接上。自协商结束,an_interrupt=1’b1;但status_vector[11:10]的值完全不反应实际的速率。还是010,千兆的值。实际是百兆。能正常接受数据,gmii_clk一直为125M。所以计数前导码55,1000M,就是7个55,100M就是70个55.简单区分百兆和千兆。再去配置speed_is_100 ,speed_is_10_100 。这样sgmii_clk_en就是我想要的频率了。如果speed_is_100 = 0 ,speed_is_10_100 = 0;sgmii_clk_en常1;如果speed_is_100 = 1 ,speed_is_10_100 = 1;sgmii_clk_en是12.5M脉冲;详细见手册。
这里做了几次实验。如果speed_is_100 = 0 ,speed_is_10_100 = 0;写死,百兆千兆都能正常接受数据。如果speed_is_100 = 1 ,speed_is_10_100 = 1;写死,千兆就无法正常接受数据了,表现为,gmii_rxd还是百兆时钟切换数据。

//  计数开头的55,判断1000M或者100M
    reg             gmii_rx_dv_r ;
    always @(posedge gmii_clk)      gmii_rx_dv_r <= gmii_rx_dv ;
    reg         judge_flag ;
    always @(posedge gmii_clk)
        if      (!rst_n)                                                judge_flag <= 'b0 ;
        else if (gmii_rx_dv && !gmii_rx_dv_r)                           judge_flag <= 'b1 ;
        else if (judge_flag && gmii_rxd==8'hd5)                         judge_flag <= 'b0 ;
    reg  [7:0]  cnt_55 ;
    always @(posedge gmii_clk)
        if      (!rst_n)                                                cnt_55 <= 'd0 ;
        else if (judge_flag && gmii_rxd==8'h55)                         cnt_55 <= cnt_55 + 'd1 ;
        else                                                            cnt_55 <= 'd0 ;

    always @(posedge gmii_clk)
        if      (!rst_n)                                                flag_1000M <= 'b0 ;
        else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 < 'd10)        flag_1000M <= 'b1 ;
        else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 > 'd10)        flag_1000M <= 'b0 ;
    always @(posedge gmii_clk)
        if      (!rst_n)                                                flag_100M <= 'b0 ;
        else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 > 'd10)        flag_100M <= 'b1 ;
        else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 < 'd10)        flag_100M <= 'b0 ;
    //  speed_is_100 speed_is_10_100
    reg     speed_is_100 ;
    reg     speed_is_10_100 ;
    always @(posedge gmii_clk)
        if      (!rst_n)        begin speed_is_100 <= 1'b0 ; speed_is_10_100 <= 1'b0 ; end 
        else if (flag_1000M)    begin speed_is_100 <= 1'b0 ; speed_is_10_100 <= 1'b0 ; end 
        else if (flag_100M)     begin speed_is_100 <= 1'b1 ; speed_is_10_100 <= 1'b1 ; end 

以太网数据异步缓存FIFO

跨始终域问题。千兆都是125M.没有问题。百兆就要设计一下了。接受数据,等接受完成后,再读。发送数据简单了。

wire  eth_clk = flag_1000M ? gmii_clk : sgmii_clk_en ;   //  125M:12.5M
//	发送数据
fifo_gig_ethernet fifo_gig_ethernet_T (
    .wr_clk     (gmii_clk       ),      // input wire wr_clk
    .din        (eth_tx_data    ),      // input wire [7 : 0] din
    .wr_en      (eth_tx_en      ),      // input wire wr_en
    
    .rd_clk     (eth_clk        ),      // input wire rd_clk
    .rd_en      ('b1            ),      // input wire rd_en
    .dout       (gmii_txd       ),      // output wire [7 : 0] dout
    .valid      (gmii_tx_en     ),      // output wire valid
    
    .full       (               ),      // output wire full
    .empty      (               )       // output wire empty
);
//  接受数据
wire            empty_R ;
reg             rd_en_R ;
always @(posedge gmii_clk)
    if      (!rst_n)                          rd_en_R <= 1'b0 ;
    else if (gmii_rx_dv_r && !gmii_rx_dv)     rd_en_R <= 1'b1 ;  // 开始读取
    else if (empty_R)                         rd_en_R <= 1'b0 ;
fifo_gig_ethernet fifo_gig_ethernet_R (
    .wr_clk     (eth_clk        ),      // input wire wr_clk
    .din        (gmii_rxd       ),      // input wire [7 : 0] din
    .wr_en      (gmii_rx_dv     ),      // input wire wr_en
    
    .rd_clk     (gmii_clk       ),      // input wire rd_clk
    .rd_en      (rd_en_R        ),      // input wire rd_en
    .dout       (eth_rx_data    ),      // output wire [7 : 0] dout
    .valid      (eth_rx_vaild   ),      // output wire valid
    
    .full       (               ),      // output wire full
    .empty      (empty_R        )       // output wire empty
);

总结

这里就发现坑的地方了。明明an_adv_config_vector设置的千兆。却能链接上。接受发送数据都没有问题。底层自协商完成了,已经是百兆的工作模式了。这和我配置an_adv_config_vector没有半点关系。之前花了好长时间,想去得到协商结果,再去配置an_adv_config_vector,还得an_restart_config上升沿重启。实际半毛钱关系都没。
我的理解是an_adv_config_vector是我希望的最佳工作模式。如果对端也是自协商端,就能接受到我的FLP,得到这个值,我也能在status_vector里得到对方的能力值。如果对方强制端,不发FLP,我就得不到参数,status_vector的值就是无意义的。但是底层还是通过NLP得知对方是100M,就自协商100M建立了链接。an_interrupt 置 1 了;而我就没法得到速度参数。

如图,接受数据
百兆
在这里插入图片描述
千兆
在这里插入图片描述

如图,发送数据
百兆
在这里插入图片描述

千兆
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:04:50  更:2021-09-03 12:05:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:27:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码