最近有一个项目要用到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: