首页/文章/ 详情

FPGA入门6——并行通信

1年前浏览332

并行是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高,但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错。

异步并口应用:CPU类的芯片与FPGA的数据交互,数据速率一般在100Mbps以内。数据总线不大于16bit。

非CPU类的功能芯片与FPGA通过并口进行数据交互,例如配置寄存器等等。

并行由于数据传输的相位差之间的正确窗口大小限制其传输速度。

这里提出亚稳态的概念,从事多时钟设计的第一步是要理解信号稳定性问题。当一个信号跨越某个时钟域时,对新时钟域的电路来说它就是一个异步信号。接收该信号的电路需要对其进行同步,同步可以防止第一级存储单元(触发器)的亚稳态在新的时钟域传播蔓延。

亚稳态是指触发器无法在某个规定时间段内达到一个可确认的状态。当一个触发器进入亚稳态时,既无法预测单元的输出电平也无法预测何时输出才能稳定在某个正确的电平上。在这个稳定期间,触发器输出一些中间级电平或者处于振荡状态,并且这种无用的输出电平可以沿信号通道上的各个触发器级联式传播下去。

代码实现:

























































































module parall_inerf(  input wire sclk,  input wire rst_n,  input wire cs_n,  input wire rd_n,  input wire wr_n,  inout tri [15:0] data,  input wire [7:0] addr);
reg [15:0] data_0,data_1,data_2,data_3,      data_4,data_5,data_6,data_7;reg  [1:0] cs_n_r,rd_n_r,wr_n_r;reg [47:0] data_r;reg [23:0] addr_r;reg [15:0] rdata;//降低亚稳态出现概率,把CS_n,rd_n,wr_n,单比特信号打两拍always @(posedge sclk or negedge rst_n)  if(rst_n==1'b0)    {cs_n_r,rd_n_r,wr_n_r}<=9'h1ff;  else    {cs_n_r,rd_n_r,wr_n_r}<={{cs_n_r[1:0],cs_n},{rd_n_r[1:0],rd_n},{wr_n_r[1:0],wr_n}};
//降低亚稳态出现概率,always @(posedge sclk or negedge rst_n)  if(rst_n==1'b0) begin    data_r<=48'd0;    addr_r<=24'd0;  end  else begin    data_r<={data_r[31:0],data};    addr_r<={addr_r[15:0],addr};  end//写always @(posedge sclk or negedge rst_n)  if(rst_n==1'b0) begin    data_0<=8'd0;    data_1<=8'd0;    data_2<=8'd0;    data_3<=8'd0;    data_4<=8'd0;    data_5<=8'd0;    data_6<=8'd0;    data_7<=8'd0;  end  else if{cs_n_r[2] == 1'b0 && rd_n_r[2] == 1'b1 && wr_n_r[2] == 1'b0} begin    case(addr_r[23:16])      8'd0:data_0<=data_r[47:32];      8'd0:data_1<=data_r[47:32];      8'd0:data_2<=data_r[47:32];      8'd0:data_3<=data_r[47:32];      8'd0:data_4<=data_r[47:32];      8'd0:data_5<=data_r[47:32];      8'd0:data_6<=data_r[47:32];      8'd0:data_7<=data_r[47:32];    dafaulet:begin      data_0<=data_0;      data_1<=data_1;      data_2<=data_2;      data_3<=data_3;      data_4<=data_4;      data_5<=data_5;      data_6<=data_6;      data_7<=data_7;      end    endcase
 end
always @(posedge sclk or negedge rst_n)  if(rst_n==1'b0) begin    r_data<='d0;  else if(cs_n_r[2] == 1'b0 && wr_n_r[2] == 1'b1)begin    case(addr[23:16])      8'd0:rdata=data_0;      8'd0:rdata<=data_1;      8'd0:rdata<=data_2;      8'd0:rdata<=data_3;      8'd0:rdata<=data_4;      8'd0:rdata<=data_5;      8'd0:rdata<=data_6;      8'd0:rdata<=data_7;      default:rdata<=16'd0;    endcase//三态门assign data=(cs_n_r[2] == 1'b0 && rd_n_r[2]==1'b0)?rdata:16'hzzz;
endmodule

代码测试:


































































































































`timescale 1ns/1nsmodule tb_parall_interf();
reg  sclk,rst_n;reg cs_n,rd_n,wr_n;reg [15:0] data;reg [7:0] addr;reg [15:0] w_date;parameter setup_time=2;parameter hold_time=2;parameter data_time=4;parameter read_time=2;
initial begin  sclk=0;  rst_n=0;  #200  rst_n=1;end
always #10 sclk=~sclk;//例化parall_interf parall_interf_inst(  .sclk  (sclk),  .rst_n  (rst_n),  .cs_n  (cs_n),  .rd_n  (rd_n),  .wr_n  (wr_n),  .data   (w_data),  .addr   (addr));
initial begin  cs_n=1;  rd_n=1;  wr_n=1;  data=0;  addr=0;  @(posedge rst_n);
 #100  write_data(8);  #100  read_data(8);end
//写数据任务task write_data(len);  integer i,len;  begin    for(i=0;i<len;i=i+1)    begin      cs_n=0;      data=i[15:0];      addr=i[7:0];
     setup_dly();      wr_n=0;      data_dly();      wr_n=1;      hold_dly();      //cs_n=1;    end    cs_n=1;  endendtask//读数据任务task read_data(len);  integer i,len;  begin    for(i=0;i<len;i=i+1)    begin
     cs_n=0;      addr=i[7:0];      read_dly();      rd_n=0;      data_dly();      $display(" addr=%d data=%d",i,w_data);      rd_n=1;    end    cs_n=1;  endendtask//测试激励的三态门assign w_data=(wr_n==1'b0)?data:16'hzzzz;
//延时task setup_dly();  integer i;  begin    for (i=0;i<setup_time;i=i+1)    begin      @(posedge sclk);    end  endendtask
task hold_dly();  integer i;  begin    for(i=0;i<hold_time;i=i+1)    begin      @(posedge sclk);    end  endendtask
task data_dly();  integer i;  begin    for(i=0;i<data_time;i=i+1)    begin      @(posedge sclk);    end  endendtask
task read_dly();  integer i;  begin    for(i=0;i<read_time;i=i+1)    begin      @(posedge sclk);    end  endendtask
endmodule


来源:集成电路小刚
电路芯片通信
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2023-06-27
最近编辑:1年前
集成电路小刚
硕士 立志成为集成电路领域专家
获赞 3粉丝 42文章 69课程 0
点赞
收藏
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈