加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Verilog的双向IO口的实现

(2013-03-06 10:58:13)
分类: FPGA

最近有一个项目要用到FPGA,还要用硬件描述语言综合出一个双向IO口用作地址数据总线。

一直没能够实现,在实验过程中遇到了或这或那的问题,终于在今天有所突破!能够正确的读写CAN控制芯片SJA1000的测试寄存器。

 

在试验中也总结了一些东西,如下:

1、Inout口,一般要放在最顶层的V文件中,我试验过放到下面的v文件中,没能够成功(更正一下:inout并非一定要在最顶层,也可以在底层设置。具体可参见黑金开发板建模篇 实验13  DS1302实时时钟驱动。)。

2、在一个module中,可以将输出定义为reg型,然后直接与要驱动module的wire型输入相连,没有问题。

3、在调试程序的过程中,尽量借助于工具,如quartus内部的Signal Tap。之前一直不会使用,现在也在慢慢学习。

 

用来模拟的是intel模式的总线读写

其时序图如下:

代码包括下面的及部分:

can_top.v

module can_top
(
 CLK,
 RSTn,
 Row_scan,
 Column_scan,
 can_pin,
 can_ALE,
 can_WR,
 can_RD,
 can_CS,
 can_dir,
 can_rst_out
);

 input CLK;
 input RSTn;
 output [7:0] Row_scan;
 output [1:0] Column_scan;
 inout [7:0] can_pin;
 output can_ALE;
 output can_WR;
 output can_RD;
 output can_CS;
 output can_dir;
 output can_rst_out;

 wire [7:0] data_in;
 wire rmd;
 wire wmd;
 wire [7:0] adr;
 wire [7:0] data_tx;
 wire [7:0] data_rx;
 wire rd_flag;
 wire wr_flag;


 trans_control U3
 (
  .CLK(CLK),
  .RSTn(RSTn),
  .data_in(data_in),
  .Row_scan(Row_scan),
  .Column_scan(Column_scan) 
 );
 

 wire can_rst;

 
 can_ctr U1
 (
  .CLK(CLK),
  .RSTn(RSTn),
  .rd_flag(rd_flag),
  .wr_flag(wr_flag),
  .data_rx(data_rx),
  .data_display(data_in),
  .rmd(rmd),
  .wmd(wmd),
  .adr(adr),
  .data_tx(data_tx),
  .can_rst(can_rst)
 );
 

 can_op U2
 (
  .CLK(CLK),
  .RSTn(RSTn),
  .can_rst_in(can_rst),
  .rmd(rmd),
  .wmd(wmd),
  .adr(adr),
  .data_tx(data_tx),
  .can_in(can_in_temp),
  .en_out(en_out),
  .can_out(can_out),
  .read_cmd(read_cmd),
  .data_rx(data_rx),
  .can_ALE(can_ALE),
  .can_WR(can_WR),
  .can_RD(can_RD),
  .can_CS(can_CS),
  .can_dir(can_dir),
  .rd_flag(rd_flag),
  .wr_flag(wr_flag),
  .can_rst_out(can_rst_out)   
 );





 wire en_out;
 wire [7:0] can_out;
// wire [7:0] can_in;
 reg [7:0] can_in_temp;

 wire read_cmd;
 
 always @ ( posedge CLK or negedge RSTn )
  begin
   if(!RSTn)
    can_in_temp<=8'b1000_1001;
   else
    begin
     if(read_cmd==1'b1)
     can_in_temp <= can_pin;     
    end
  end

// assign can_in = can_in_temp;
 assign can_pin = (en_out==1'b1)?can_out:8'bZZZZZZZZ;     //双向口设置

 
endmodule

 

can_ctr.v

module can_ctr
(
 CLK,
 RSTn,
 rd_flag,
 wr_flag,
 data_rx,
 data_display,
 rmd,
 wmd,
 adr,
 data_tx,
 can_rst
);

 input CLK;
 input RSTn;
 input rd_flag;
 input wr_flag;
 input [7:0] data_rx;
 output [7:0] data_display;
 output rmd;
 output wmd;
 output [7:0] adr;
 output [7:0] data_tx;
 output can_rst;
 
  
 reg [7:0] data_display_temp;
 reg rmd_temp;
 reg wmd_temp;
 reg [7:0] adr_temp;
 reg [7:0] data_tx_temp;
 reg can_rst_temp;
 reg rst_flag;

  

 parameter TS = 26'd29_999_999;
 parameter T1S = 26'd49_999_999;
 
   



 always @ ( posedge CLK or negedge RSTn )
  begin
   if(!RSTn)
    begin
     can_rst_temp<=1'b1;
     rst_flag<=1'b1;
    end    
   else if (Count_Sec==26'd100 && rst_flag == 1'b1)
    begin
     can_rst_temp<=1'b0;
     rst_flag<=1'b0;
    end
  end  
  


 always @ ( posedge CLK or negedge RSTn )
  begin
   if(!RSTn)
    begin
     rmd_temp<=1'b0;
     wmd_temp<=1'b0;
     adr_temp<=8'b0000_0000;
     data_display_temp<= 8'b1000_1000;
     data_tx_temp<=8'b0000_0000;
    end

   else
    begin
     if (Count_Sec==TS)
      begin
       wmd_temp<=1'b1;
       adr_temp<=8'b0001_0000;
       data_tx_temp<=8'b0001_0010;      
      end
     if (Count_Sec==T1S) 
      begin
       rmd_temp<=1'b1;
       adr_temp<=8'b0001_0000; //读测试寄存器
      end
     if (wr_flag==1'b1)
      begin
       wmd_temp<=1'b0;
      end
     if (rd_flag==1'b1)
      begin
       rmd_temp<=1'b0;
         data_display_temp<= data_rx;
      end  

    end

 
  end    

 

 

  reg [25:0]Count_Sec;
 
 always @ ( posedge CLK or negedge RSTn )
  if( !RSTn )
        Count_Sec <= 26'd0;
  else if( Count_Sec == T1S )
        Count_Sec <= 26'd0;
  else
        Count_Sec <= Count_Sec + 1'b1;
 

 assign data_display=data_display_temp;
 assign rmd=rmd_temp;
 assign wmd=wmd_temp;
 assign adr=adr_temp;
 assign data_tx=data_tx_temp;
 assign can_rst=can_rst_temp;

endmodule 

 

 

can_op.v

module can_op
(
 CLK,
 RSTn,
 can_rst_in,
 rmd,
 wmd,
 adr,
 data_tx,
 can_in,
 en_out,
 can_out,
 read_cmd,
 data_rx,
 can_ALE,
 can_WR,
 can_RD,
 can_CS,
 can_dir,
 rd_flag,
 wr_flag,
 can_rst_out
);
 input CLK;
 input RSTn;
 input can_rst_in;
 input rmd;
 input wmd;
 input [7:0]adr;
 input [7:0]data_tx; 
 input [7:0]can_in;
 output en_out;
 output [7:0] can_out;
 output read_cmd;
 output [7:0]data_rx;
 output can_ALE;
 output can_WR;
 output can_RD;
 output can_CS;
 output can_dir;
 output rd_flag;
 output wr_flag;
 output can_rst_out;
 

 reg [7:0] can_out_temp;
 reg en_out_temp;                  //这两个变量来组成双向口 输出控制
 reg read_cmd_temp;  
 reg [7:0] data_rx_temp;
 reg can_ALE_temp;
 reg can_WR_temp;
 reg can_RD_temp;
 reg can_CS_temp;
 reg can_dir_temp;
 reg rd_flag_temp;
 reg wr_flag_temp;
 reg [3:0] count;
 

 always @ ( posedge CLK or negedge RSTn )
 begin
  if ( !RSTn )
    begin
     rd_flag_temp<=1'b0;
     wr_flag_temp<=1'b0;
     can_WR_temp<=1'b1;
     can_RD_temp<=1'b1;
     can_CS_temp<=1'b1;
     can_dir_temp<=1'b0;   
     data_rx_temp<=8'd221;    
     count<= 4'd0;
     en_out_temp<=1'b1;
     can_out_temp<=8'd0;
     read_cmd_temp<=1'b0;
     end
   else
    begin
     if (rmd)
      begin
       case(count)
        
        4'd0,4'd1,4'd6:   count<= count+1'b1;
        4'd2:
         begin
          can_out_temp<= adr;
          en_out_temp<=1'b1;
          can_ALE_temp<= 1'b1;
          count<= count+1'b1;
         end
        4'd3:
         begin
          can_ALE_temp<=1'b0;
          count<= count+1'b1;
         end
        4'd4:
         begin
          can_CS_temp<= 1'b0;
          count<= count+1'b1;
          en_out_temp<=1'b0;
          end
        4'd5:
         begin
          can_RD_temp<= 1'b0;
          can_dir_temp=1'b1;
          count<= count+1'b1;
         end

        4'd7:
         begin
          read_cmd_temp<=1'b1;
          count<= count+1'b1;
         end
        4'd8:
         begin        
          count<= count+1'b1;
          read_cmd_temp<=1'b0;
            
         end
        4'd9:
         begin
          data_rx_temp <= can_in; 
          can_RD_temp<= 1'b1;
          count<= count+1'b1;
          can_dir_temp <= 1'b0;
          en_out_temp<=1'b1;
         end
        4'd10:
         begin
          can_CS_temp<= 1'b1;
          count<= count+1'b1;
          rd_flag_temp<=1'b1;
         end
        4'd11:
         begin
          count<=4'd0;
          rd_flag_temp<=1'b0;
         end
       endcase
      end
     if (wmd)
      begin
       case(count)
         
         4'd0,4'd1:   count<= count+1'b1;
         4'd2:
          begin
           can_out_temp<= adr;
           en_out_temp<=1'b1;
           can_ALE_temp<= 1'b1;
           count<= count+1'b1;
          end
         4'd3:
          begin
           can_ALE_temp<=1'b0;
           count<= count+1'b1;
          end
         4'd4:
          begin
           can_CS_temp<= 1'b0;
           count<= count+1'b1;
          end
         4'd5:
          begin
           can_WR_temp<= 1'b0;
           count<= count+1'b1;
          end
         4'd6:
          begin
           can_out_temp<= data_tx;
           count<= count+1'b1;        
          end       
         4'd7:
          begin
           count<= count+1'b1;
          end
         4'd8:
          begin
           can_WR_temp<= 1'b1;
           count<= count+1'b1;
          end
         4'd9:
          begin
           can_CS_temp<= 1'b1;
           can_ALE_temp<=1'b1;
           count<= count+1'b1;
           wr_flag_temp<=1'b1;
          end
         4'd10:
          begin
           count<= 1'b0;
           wr_flag_temp<=1'b0;       
          end

       endcase
      end
    end
  
 end


 

 assign data_rx=data_rx_temp;
 assign can_ALE=can_ALE_temp;
 assign can_WR=can_WR_temp;
 assign can_RD=can_RD_temp;
 assign can_CS=can_CS_temp;
 assign can_dir=can_dir_temp;
 assign wr_flag=wr_flag_temp;
 assign rd_flag=rd_flag_temp;
 assign can_rst_out=can_rst_in;
 assign can_out=can_out_temp;
 assign en_out=en_out_temp;
 assign read_cmd=read_cmd_temp;


 
endmodule
  

 

trans_control.v   这个与下面两个v文件是用来将接收到的数据显示到数码管上

module trans_control
(
 CLK,
 RSTn,
 data_in,
 Row_scan,
 Column_scan
);

 input CLK;
 input RSTn;
 input [7:0] data_in;
 output [7:0] Row_scan;
 output [1:0] Column_scan;
 
 wire [7:0] data1_temp;
 wire [7:0] data2_temp;
 

 trans_module U1
 (
  .CLK (CLK),
  .RSTn (RSTn),
  .data_in (data_in),
  .out_data1 (data1_temp),
  .out_data2 (data2_temp)
 );
 
 scan_module U2
 (
  .CLK (CLK),
  .RSTn (RSTn),
  .scan_data1 (data1_temp),
  .scan_data2 (data2_temp),
  .Row_scan (Row_scan),
  .Column_scan (Column_scan)
 );

endmodule

 

trans_module.v

module trans_module
(
 CLK,
 RSTn,
 data_in,
 out_data1,
 out_data2
);


 input CLK;
 input RSTn;
 input [7:0] data_in;
 output [7:0] out_data1;
 output [7:0] out_data2;

 reg [7:0] out_data1_temp;
 reg [7:0] out_data2_temp;
 
 reg [3:0] temp1;
 reg [3:0] temp2;

 
  parameter _0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100,
            _3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010,
      _6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,
      _9 = 8'b1001_0000, _A = 8'b1000_1000, _B = 8'b1000_0011,
      _C = 8'b1100_0110, _D = 8'b1010_0001, _E = 8'b1000_0100,
      _F = 8'b1000_1110;
     

 always @ ( posedge CLK or negedge RSTn )

  if( !RSTn )
   begin
    out_data1_temp<= 8'b1100_0000;
    out_data2_temp<= 8'b1100_0000;
    temp1 <= 4'd0;
    temp2 <= 4'd0;
   end
  else
   begin
    temp1 <= data_in[3:0];
    temp2 <= data_in[7:4];
    case(temp1)
     4'h0 : out_data1_temp <= _0;
     4'h1 : out_data1_temp <= _1;
     4'h2 : out_data1_temp <= _2;
     4'h3 : out_data1_temp <= _3;
     4'h4 : out_data1_temp <= _4;
     4'h5 : out_data1_temp <= _5;
     4'h6 : out_data1_temp <= _6;
     4'h7 : out_data1_temp <= _7;
     4'h8 : out_data1_temp <= _8;
     4'h9 : out_data1_temp <= _9;
     4'hA : out_data1_temp <= _A;
     4'hB : out_data1_temp <= _B;
     4'hC : out_data1_temp <= _C;
     4'hD : out_data1_temp <= _D;
     4'hE : out_data1_temp <= _E;
     4'hF : out_data1_temp <= _F;
    endcase
    case(temp2)
     4'h0 : out_data2_temp <= _0;
     4'h1 : out_data2_temp <= _1;
     4'h2 : out_data2_temp <= _2;
     4'h3 : out_data2_temp <= _3;
     4'h4 : out_data2_temp <= _4;
     4'h5 : out_data2_temp <= _5;
     4'h6 : out_data2_temp <= _6;
     4'h7 : out_data2_temp <= _7;
     4'h8 : out_data2_temp <= _8;
     4'h9 : out_data2_temp <= _9;
     4'hA : out_data2_temp <= _A;
     4'hB : out_data2_temp <= _B;
     4'hC : out_data2_temp <= _C;
     4'hD : out_data2_temp <= _D;
     4'hE : out_data2_temp <= _E;
     4'hF : out_data2_temp <= _F;
    endcase       
   end
    

 assign out_data1 = out_data1_temp;
 assign out_data2 = out_data2_temp;


   
endmodule

 

scan_module.v

module scan_module
(
 CLK,
 RSTn,
 scan_data1,
 scan_data2,
 Column_scan,
 Row_scan
);

 input CLK;
 input RSTn;
 input [7:0] scan_data1;
 input [7:0] scan_data2;
 output [7:0] Row_scan;
 output [1:0] Column_scan;
 
 
 
 
  parameter T10MS = 19'd499_999;//50M*0.01-1=499_999
 
 
 
  reg [18:0]Count1;
 
  always @ ( posedge CLK or negedge RSTn )
      if( !RSTn )
        Count1 <= 19'd0;
    else if( Count1 == T10MS )
        Count1 <= 19'd0;
    else
        Count1 <= Count1 + 19'b1;
 
 
 
  reg [1:0]t;
 
  always @ ( posedge CLK or negedge RSTn )
      if( !RSTn )
        t <= 2'd0;
    else if( t == 2'd2 )
        t <= 2'd0;
    else if( Count1 == T10MS )
        t <= t + 1'b1;
    
   
  reg [7:0] Row_scan_temp;
  reg [1:0] Column_scan_temp;
 
  always @ ( posedge CLK or negedge RSTn )
      if( !RSTn )
   begin
    Column_scan_temp <= 2'b01;
    Row_scan_temp <= 8'hd0;
   end
    else if( Count1 == T10MS )
        case( t )
    
        2'd0 : begin Column_scan_temp <= 2'b01; Row_scan_temp <= scan_data1; end
     
      2'd1 : begin Column_scan_temp <= 2'b10; Row_scan_temp <= scan_data2; end
    
    endcase 
    
 
 
  assign Column_scan = Column_scan_temp;
  assign Row_scan = Row_scan_temp;
   
endmodule

 

 

代码就这些,还有TCL引脚说明

#------------------GLOBAL--------------------#
set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED"
set_global_assignment -name ENABLE_INIT_DONE_OUTPUT OFF

#复位引脚
set_location_assignment PIN_M1 -to RSTn

#时钟引脚
set_location_assignment PIN_R9 -to CLK

#数码管对应的引脚
set_location_assignment PIN_M8 -to Row_scan[0]
set_location_assignment PIN_L7 -to Row_scan[1]
set_location_assignment PIN_P9 -to Row_scan[2]
set_location_assignment PIN_N9 -to Row_scan[3]
set_location_assignment PIN_M9 -to Row_scan[4]
set_location_assignment PIN_M10 -to Row_scan[5]
set_location_assignment PIN_P11 -to Row_scan[6]
set_location_assignment PIN_N11 -to Row_scan[7]
set_location_assignment PIN_N8 -to Column_scan[0]
set_location_assignment PIN_P8 -to Column_scan[1]

#CAN控制信号对应引脚
set_location_assignment PIN_R1 -to can_pin[0]
set_location_assignment PIN_R3 -to can_pin[1]
set_location_assignment PIN_L3 -to can_pin[2]
set_location_assignment PIN_K5 -to can_pin[3]
set_location_assignment PIN_P3 -to can_pin[4]
set_location_assignment PIN_L8 -to can_pin[5]
set_location_assignment PIN_N5 -to can_pin[6]
set_location_assignment PIN_K6 -to can_pin[7]
set_location_assignment PIN_L6 -to can_ALE
set_location_assignment PIN_T3 -to can_WR
set_location_assignment PIN_L4 -to can_RD
set_location_assignment PIN_N3 -to can_CS
set_location_assignment PIN_T2 -to can_dir
set_location_assignment PIN_P2 -to can_rst_out

 


 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有