Serdes专题(5)PCS IP配置

文章目录

前言

PCS IP是一个软核,是连接FPGA用户逻辑与Serdes硬件结构的桥梁。Lattice Serdes提供了很多灵活的配置,全部可以通过IP配置的方式灵活调用。IP配置可通过三种方式实现,一是IP生成时,UI界面提供了各种配置选项;二是例化IP时,提供了FPGA写入的控制信号和读出的状态信号。三是,IP软核提供了寄存器配置接口,相对更靠近底层的配置和状态可通过寄存器配置接口读取或配置。本文介绍这三种方式。

1.PCS IP接口信号

如图所示,是所有PCS IP相关的接口信号。其中有关复位与时钟的信号上节已经介绍过,关于Client Interface实际上是寄存器接口,在本文第三节介绍。Primary I/O是硬件上与serdes物理介质连接的接口,不过多介绍。这里介绍一些相关的控制信号和状态信号的配置与使用。所介绍的信号是基于实现serdes 8b/10b通信使用的,一些不常使用未经我验证的信号不做介绍。
控制信号,全部是输入信号

状态信号,全部是输出信号

2. IP核的配置

PCS软核中定义了很多寄存器,初始寄存器设置可通过使用 IPexpress 中的自动配置功能实现,即在UI界面中点点点的方式。模块生成器提供了一个自动配置文件,包含了所选模式下quad和通道寄存器的设置。可参考这个文件来进行前端仿真,还可以集成到位流中。当一个自动配置文件集成到位流中,那么在配置过程中,所有的 quad 和通道寄存器将根据自动配置文件定义的值进行设置。如果在工作时,用户需要更改控制寄存器或监控状态寄存器,那么设计中必须包含SCI接口,即Serdes Client Interface,在下一节介绍。

IP配置第一页,配置使能的通道,与是否同时使能Rx与Tx,通道选择主要与硬件原理图指示的连接一致。如图下拉框主要选择实现协议,下一个专题实现以太网会介绍SGMII接口。本系列实现G8B/10B,其余未用过。

IP配置第二页介绍时钟、线速率、位宽的配置。靠上半部分设置发送通道,Max Data Rate设置serdes线速率,要与FPGA硬件支持能力,光模块能力,应用需求适配。LatticeECP3最大支持3.125G。Tx Refclk Source配置发送通道参考时钟源,注意发送与接收不必同源。参考时钟的频率应与所设置的线速率成一定的倍数关系。IP给FPGA逻辑的时钟则由Tx Rate设置的线速率与数据Bus共同决定,一般情况下,要求发送与接收通道设置一致。图中下半部分设置接收通道与发送通道一致。

PreEmphasis设置是否使能预加重,预加重 (TX FIR)即在"发射端"补高频,它的作用像是在出门前先"穿厚一点的衣服"。你知道外面冷(高频会衰减),于是你提前给高频多一些能量。通常实验室环境设置为0即可。TX I/O Termination是两个差分发送线之间的终端电阻,让高速信号在走线和负载上传播时不产生反射,从而保证眼图稳定、减少抖动和误码。当高频信号衰减严重的时候,在接收端配置Equalization以补偿高速信号在走线中被"削弱"的高频成分,让接收端能够恢复出原始的方波。接收端终端电阻也是50欧姆。耦合方式要与硬件涉及匹配,通常选择AC耦合。最下面设置时钟的终端电阻。Tx PLL则是用来监测Tx端pll失锁的标准值,通常无需设置。

IP配置第四页,本页主要上是选一些硬件结构上的多路器,接收端发送端都是设置是否给信号取反,是否使能编码器,是否使能fifo桥。关于下方字对齐设置是否由软核字对齐。是否利用内部的状态机,选择K码。按照上面默认设置。第五页设置CTC FIFO相关内容,用一个小 FIFO 来吸收 Tx 时钟与 Rx 时钟之间的频偏,使得 RX 用户侧的时钟域能够继续稳定读出数据,不会因时钟不一致而出现漏读/多读。保持默认即可。

第六页设置回环模式,下一篇文章细讲。是否包含复位序列,做内回环测试的时候不包含,其余时刻包含。最后是勾选SCI接口以在代码运行过程中读写寄存器。最后一页包含一些生成信息,保持默认即可。

3.寄存器接口

接口信号如下:

信号 作用
sci_wrdata[7:0] 要写入寄存器的数据
sci_sel_quad 选择quad寄存器,高有效
sci_wrn 要写入寄存器的数据
sci_sel_ch 写选通,低有效
sci_addr 地址总线输入,官方文档中有具体映射
sci_rd 读数据选择
sci_rddata[7:0] 读数据输出
操作时序如下:


下面是我写的寄存器读取的实例代码,供参考。

cpp 复制代码
module reg_rd (
input      clk_fpga,
input      rst_n,
output [7:0]   sci_wrdata,
output [5:0]   sci_addr,
input   [7:0]  sci_rddata,
output         sci_sel_quad,
output         sci_rd,
output         sci_wrn,
output  reg    sci_sel_ch2
);
    
reg [31:0]cnt_1s;
reg start_en;
always @(posedge clk_fpga or negedge rst_n) begin
    if(!rst_n)begin
        cnt_1s <= 0;
        start_en <= 0;
    end else begin
        cnt_1s <= cnt_1s + 1;
        if(cnt_1s == 32'd125_000_000)begin
            cnt_1s <= cnt_1s;
            start_en <= 1;
        end
    end
end


//reg [7:0]reg_0[0:5];
reg [7:0]reg_9;
reg [7:0]reg_a;
reg [7:0]reg_b;
reg [7:0]reg_d;
reg [7:0]reg_2;
reg [7:0]reg_21;
reg [7:0]reg_22;


reg [7:0]reg_ch_00;
reg [7:0]reg_ch_01;
reg [7:0]reg_ch_02;
reg [7:0]reg_ch_03;
reg [7:0]reg_ch_04;
reg [7:0]reg_ch_05;
reg [7:0]reg_ch_06;
reg [7:0]reg_ch_07;
reg [7:0]reg_ch_08;
reg [7:0]reg_ch_09;
reg [7:0]reg_ch_0A;
reg [7:0]reg_ch_0B;
reg [7:0]reg_ch_0C;
reg [7:0]reg_ch_0D;
reg [7:0]reg_ch_0E;
reg [7:0]reg_ch_0F;


reg [7:0]reg_ch_10;
reg [7:0]reg_ch_11;
reg [7:0]reg_ch_12;
reg [7:0]reg_ch_13;
reg [7:0]reg_ch_14;
reg [7:0]reg_ch_15;
reg [7:0]reg_ch_16;
reg [7:0]reg_ch_17;
reg [7:0]reg_ch_18;
reg [7:0]reg_ch_19;


reg [7:0]reg_ch_20;
reg [7:0]reg_ch_21;
reg [7:0]reg_ch_22;
reg [7:0]reg_ch_23;
reg [7:0]reg_ch_24;
reg [7:0]reg_ch_25;
reg [7:0]reg_ch_26;
reg [7:0]reg_ch_27;
reg [7:0]reg_ch_28;
reg [7:0]reg_ch_29;
reg [7:0]reg_ch_2A;
reg [7:0]reg_ch_2B;
reg [7:0]reg_ch_2C;

//read monitor
reg [1:0]State;

reg [5:0] sub_addr;
reg end_flag;
always @(posedge clk_fpga or negedge rst_n) begin
    if(!rst_n)begin
        State <= 0;
        end_flag <= 0;
        sci_sel_ch2 <= 0;
        
        // sci_rd <= 0;
        // sci_sel_quad <= 0;
        reg_2 <= 0;
        reg_9 <= 0;
        reg_a <= 0;
        reg_b <= 0;
        reg_d <= 0;
        reg_21 <= 0;
        reg_22 <= 0;
        sub_addr<=0;
        reg_ch_00 <= 0;
        reg_ch_01 <= 0;
        reg_ch_02 <= 0;
        reg_ch_03 <= 0;
        reg_ch_04 <= 0;
        reg_ch_05 <= 0;
        reg_ch_06 <= 0;
        reg_ch_07 <= 0;
        reg_ch_08 <= 0;
        reg_ch_09 <= 0;
        reg_ch_0A <= 0;
        reg_ch_0B <= 0;
        reg_ch_0C <= 0;
        reg_ch_0D <= 0;
        reg_ch_0E <= 0;
        reg_ch_0F <= 0;

        reg_ch_10 <= 0;
        reg_ch_11 <= 0;
        reg_ch_12 <= 0;
        reg_ch_13 <= 0;
        reg_ch_14 <= 0;
        reg_ch_15 <= 0;
        reg_ch_16 <= 0;
        reg_ch_17 <= 0;
        reg_ch_18 <= 0;
        reg_ch_19 <= 0;

        reg_ch_20 <= 0;
        reg_ch_21 <= 0;
        reg_ch_22 <= 0;
        reg_ch_23 <= 0;
        reg_ch_24 <= 0;
        reg_ch_25 <= 0;
        reg_ch_26 <= 0;
        reg_ch_27 <= 0;
        reg_ch_28 <= 0;
        reg_ch_29 <= 0;
        reg_ch_2A <= 0;
        reg_ch_2B <= 0;
        reg_ch_2C <= 0;
    end else begin
        case (State)
            0: begin //Cycle 1: Set sci_addr[5:0], sci_sel = 1'b1
                // sci_rd <= 0;
                if(start_en)begin
                    State <= sci_sel_ch2 ? 2:1; 
                end else begin
                    State <= 0;
                end
            end
            1:begin//Cycle 2: Set sci_rd from 0  1
                // sci_rd <= 1;
                // sci_sel_quad <= 0;
                // State <= 2;
                // reg_0[sub_addr]<= sci_rddata;
                // if(sci_rddata!=0)begin
                //     end_flag <= 1;
                // end
                sub_addr <= sub_addr + 1;
                if(sub_addr == 6'h2)begin
                    reg_2 <= sci_rddata;
                end
                if(sub_addr == 6'h9)begin
                    reg_9 <= sci_rddata;
                end
                if(sub_addr == 6'ha)begin
                    reg_a <= sci_rddata;
                end
                if(sub_addr == 6'hb)begin
                    reg_b <= sci_rddata;
                end
                if(sub_addr == 6'hd)begin
                    reg_d <= sci_rddata;
                end
                 if(sub_addr == 6'h21)begin
                    reg_21 <= sci_rddata;
                end
                if(sub_addr == 6'h22)begin
                    reg_22 <= sci_rddata;
                end
                if(sub_addr==6'd40  )begin
                    sub_addr <= 0;
                    State <= 2;
                    sci_sel_ch2 <= 1;
                end else begin
                    State <= 0;
                end
            end

            2:begin//Obtain reading data from sci_rddata[7:0]
                sub_addr <= sub_addr + 1;
                case (sub_addr)
                    6'h0:reg_ch_00 <= sci_rddata;
                    6'h1:reg_ch_01 <= sci_rddata;
                    6'h2:reg_ch_02 <= sci_rddata;
                    6'h3:reg_ch_03 <= sci_rddata;
                    6'h4:reg_ch_04 <= sci_rddata;
                    6'h5:reg_ch_05 <= sci_rddata;
                    6'h6:reg_ch_06 <= sci_rddata;
                    6'h7:reg_ch_07 <= sci_rddata;
                    6'h8:reg_ch_08 <= sci_rddata;
                    6'h9:reg_ch_09 <= sci_rddata;
                    6'hA:reg_ch_0A <= sci_rddata;
                    6'hB:reg_ch_0B <= sci_rddata;
                    6'hC:reg_ch_0C <= sci_rddata;
                    6'hD:reg_ch_0D <= sci_rddata;
                    6'hE:reg_ch_0E <= sci_rddata;
                    6'hF:reg_ch_0F <= sci_rddata;
 
                    6'h10:reg_ch_10 <= sci_rddata;
                    6'h11:reg_ch_11 <= sci_rddata;
                    6'h12:reg_ch_12 <= sci_rddata;
                    6'h13:reg_ch_13 <= sci_rddata;
                    6'h14:reg_ch_14 <= sci_rddata;
                    6'h15:reg_ch_15 <= sci_rddata;
                    6'h16:reg_ch_16 <= sci_rddata;
                    6'h17:reg_ch_17 <= sci_rddata;
                    6'h18:reg_ch_18 <= sci_rddata;
                    6'h19:reg_ch_19 <= sci_rddata;

                    6'h20:reg_ch_20 <= sci_rddata;
                    6'h21:reg_ch_21 <= sci_rddata;
                    6'h22:reg_ch_22 <= sci_rddata;
                    6'h23:reg_ch_23 <= sci_rddata;
                    6'h24:reg_ch_24 <= sci_rddata;
                    6'h25:reg_ch_25 <= sci_rddata;
                    6'h26:reg_ch_26 <= sci_rddata;
                    6'h27:reg_ch_27 <= sci_rddata;
                    6'h28:reg_ch_28 <= sci_rddata;
                    6'h29:reg_ch_29 <= sci_rddata;
                    6'h2A:reg_ch_2A <= sci_rddata;
                    6'h2B:reg_ch_2B <= sci_rddata;
                    6'h2C:reg_ch_2C <= sci_rddata; 
                    default: ;
                endcase
                if(sub_addr==6'h2C  )begin
                    sub_addr <= 0;
                    State <= 3;
                end else begin
                    State <= 0;
                end
            end
            3:begin
                // sci_rd <= 0;
                State <= 3;
            end
            default:; 
        endcase
    end
end
assign sci_addr = sub_addr;
assign sci_sel_quad =1;
assign sci_wrn = 0;
assign sci_rd = 1;
endmodule

4.传送门

|-----|
| END |

📡文章原创,首发于CSDN论坛。

📡欢迎点赞♥♥收藏⭐⭐打赏💵💵!

📡欢迎评论区或私信指出错误💉,提出宝贵意见或疑问😱。

相关推荐
国科安芯7 小时前
AS32A601型MCU芯片flash模块的擦除和编程
java·linux·前端·单片机·嵌入式硬件·fpga开发·安全性测试
Aaron158817 小时前
侦察、测向、识别、干扰一体化平台系统技术实现
人工智能·fpga开发·硬件架构·边缘计算·信息与通信·射频工程·基带工程
FPGA_无线通信1 天前
OFDM 频偏补偿和相位跟踪(1)
算法·fpga开发
HIZYUAN1 天前
AI时代,如何利用FPGA在无人机视觉等方面进行快速应用
stm32·单片机·fpga开发·视觉检测·无人机·fpga·光端机
釉色清风1 天前
openEuler 多样算力支持:CPU、GPU 与 FPGA 异构加速实战
fpga开发
Joshua-a2 天前
Quartus命令行烧录FPGA
fpga开发
FPGA_无线通信2 天前
OFDM FFT 时频域转换
fpga开发
XINVRY-FPGA2 天前
EP4CE30F23I7N Altera Cyclone IV E SRAM FPGA
嵌入式硬件·fpga开发·云计算·硬件工程·信息与通信·信号处理·fpga
156082072192 天前
FPGA(采用RGMII接口)逻辑实现千兆网TCP/IP协议栈调试记录
网络协议·tcp/ip·fpga开发