Цитата(sergey sva @ May 9 2015, 18:14)

Хочу попробовать запустить spi slave на циклоне. Поискал в сети готовые исходники, примеров много для этого интерфейса не знаю с какого начать, подскажите пожалуйста ссылку на проверенный пример, который вам понравился ))
CODE
`timescale 1ns/1ns
`define CLOCK_PHASE 0
`define CLOCK_POLARITY 0
module spi_slave #(
parameter SHIFT_DIRECTION = 0,
parameter DATA_LENGTH = 8 // changed from 32 to 8
)
(
//Back end device interfacet
CSn,
DATA_IN, //8 bit width - changed from 32 bits
WR_RD,
DATA_OUT, //8 bit width - changed from 32 bits
TX_RDY,
RX_RDY,
TX_ERR,
RX_ERR,
CLK_I,
RST_I,
//spi interface
MISO_SLAVE,
MOSI_SLAVE,
CSn_SLAVE,
SCLK_SLAVE
);
//back end device interface
input CSn;
input [7:0] DATA_IN; //8 bit width - changed from 32 bits
input WR_RD;
output [7:0] DATA_OUT; //8 bit width - changed from 32 bits
output TX_RDY;
output RX_RDY;
output TX_ERR;
output RX_ERR;
input CLK_I;
input RST_I;
//spi interface
output MISO_SLAVE;
input MOSI_SLAVE;
input CSn_SLAVE;
input SCLK_SLAVE;
parameter UDLY = 1;
//register access
reg MISO_SLAVE;
reg [7:0] latch_s_data; //8 bit width - changed from 32 bits
reg [DATA_LENGTH-1:0] reg_rxdata;
reg [DATA_LENGTH-1:0] reg_txdata;
reg [DATA_LENGTH-1:0] rx_shift_data;
reg reg_toe;
reg reg_roe;
reg reg_trdy;
reg reg_rrdy;
reg tx_done;
reg rx_done;
reg rx_done_flip1;
reg rx_done_flip2;
reg rx_done_flip3;
reg tx_done_flip1;
reg tx_done_flip2;
reg tx_done_flip3;
reg [5:0] rx_data_cnt;
reg [5:0] tx_data_cnt;
assign TX_RDY=reg_trdy;
assign RX_RDY=reg_rrdy;
assign TX_ERR=reg_toe;
assign RX_ERR=reg_roe;
assign DATA_OUT=reg_rxdata;
always @(posedge CLK_I or posedge RST_I)
if(RST_I)
latch_s_data <= #UDLY 32'h0;
else if (!WR_RD && !CSn && reg_trdy)
latch_s_data <= #UDLY DATA_IN;
//Receive Data Register
always @(posedge CLK_I or posedge RST_I)
if(RST_I)
reg_rxdata <= #UDLY 'h0;
else if (rx_done_flip1 && !rx_done_flip2)
reg_rxdata <= #UDLY rx_shift_data;
//Transmit Data Register
always @(posedge CLK_I or posedge RST_I)
if(RST_I)
reg_txdata <= #UDLY 'h0;
else //if (!WR_RD && !CSn && reg_trdy)
reg_txdata <= #UDLY latch_s_data;
//-----------------------------For Rx data,
//-----------------sample at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0
`ifdef CLOCK_POLARITY
`ifdef CLOCK_PHASE
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_shift_data <= #UDLY 'h0;
else if (!CSn_SLAVE)
if (SHIFT_DIRECTION)
rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]};
else
rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE};
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_data_cnt <= #UDLY 'h0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
rx_data_cnt <= #UDLY rx_data_cnt + 1;
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_done <= #UDLY 1'b0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_done <= #UDLY 1'b1;
else
rx_done <= #UDLY 1'b0;
//-----------------sample at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1
`else
//For Rx data, sample at negedge when CLOCK_PHASE is 1
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_shift_data <= #UDLY 'h0;
else if (!CSn_SLAVE)
if (SHIFT_DIRECTION)
rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]};
else
rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE};
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_data_cnt <= #UDLY 'h0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
rx_data_cnt <= #UDLY rx_data_cnt + 1;
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_done <= #UDLY 1'b0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_done <= #UDLY 1'b1;
else
rx_done <= #UDLY 1'b0;
//end
`endif
//-----------------sample at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0
`else
`ifdef CLOCK_PHASE
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_shift_data <= #UDLY 'h0;
else if (!CSn_SLAVE)
if (SHIFT_DIRECTION)
rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]};
else
rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE};
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_data_cnt <= #UDLY 'h0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
rx_data_cnt <= #UDLY rx_data_cnt + 1;
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_done <= #UDLY 1'b0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_done <= #UDLY 1'b1;
else
rx_done <= #UDLY 1'b0;
//-----------------sample at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1
`else
//For Rx data, sample at negedge when CLOCK_PHASE is 1
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_shift_data <= #UDLY 'h0;
else if (!CSn_SLAVE)
if (SHIFT_DIRECTION)
rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]};
else
rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE};
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_data_cnt <= #UDLY 'h0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
rx_data_cnt <= #UDLY rx_data_cnt + 1;
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
rx_done <= #UDLY 1'b0;
else if (rx_data_cnt == DATA_LENGTH - 1)
rx_done <= #UDLY 1'b1;
else
rx_done <= #UDLY 1'b0;
//end
`endif
`endif
always @(posedge CLK_I or posedge RST_I)
if (RST_I) begin
rx_done_flip1 <= #UDLY 1'b0;
rx_done_flip2 <= #UDLY 1'b0;
rx_done_flip3 <= #UDLY 1'b0;
end
else begin
rx_done_flip1 <= #UDLY rx_done;
rx_done_flip2 <= #UDLY rx_done_flip1;
rx_done_flip3 <= #UDLY rx_done_flip2;
end
always @(posedge CLK_I or posedge RST_I)
if (RST_I)
reg_rrdy <= #UDLY 1'b0;
else if (rx_done_flip2 && !rx_done_flip3)
reg_rrdy <= #UDLY 1'b1;
else if (WR_RD && !CSn)
reg_rrdy <= #UDLY 1'b0;
always @(posedge CLK_I or posedge RST_I)
if (RST_I)
reg_roe <= #UDLY 1'b0;
else if (rx_done_flip2 && !rx_done_flip3 && reg_rrdy)
reg_roe <= #UDLY 1'b1;
else if (WR_RD && !CSn)
reg_roe <= #UDLY 1'b0;
//--------------------For Tx data,
//-----------------------------------update at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0
`ifdef CLOCK_POLARITY
`ifdef CLOCK_PHASE
//always @(*)
always @(reg_txdata or tx_data_cnt or CSn_SLAVE )
if (!CSn_SLAVE)
MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] :
reg_txdata[DATA_LENGTH-tx_data_cnt-1];
else
MISO_SLAVE<=1'bz;
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_data_cnt <= #UDLY 'h0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
tx_data_cnt <= #UDLY tx_data_cnt + 1;
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_done <= #UDLY 1'b0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_done <= #UDLY 1'b1;
else
tx_done <= #UDLY 1'b0;
//-----------------------------------update at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1
`else
//always @(posedge SCLK_SLAVE or posedge RST_I)
// if (RST_I)
// MISO_SLAVE <= #UDLY 1'b0;
// else
// MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] :
// reg_txdata[DATA_LENGTH-tx_data_cnt-1];
always @(posedge SCLK_SLAVE)
if (!CSn_SLAVE)
MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] :
reg_txdata[DATA_LENGTH-tx_data_cnt-1];
else
MISO_SLAVE<=1'bz;
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_data_cnt <= #UDLY 'h0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
tx_data_cnt <= #UDLY tx_data_cnt + 1;
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_done <= #UDLY 1'b0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_done <= #UDLY 1'b1;
else
tx_done <= #UDLY 1'b0;
`endif
//-----------------------------------update at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0
`else
`ifdef CLOCK_PHASE
//always @(*)
always @(reg_txdata or tx_data_cnt or CSn_SLAVE )
if (!CSn_SLAVE)
MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] :
reg_txdata[DATA_LENGTH-tx_data_cnt-1];
else
MISO_SLAVE<=1'bz;
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_data_cnt <= #UDLY 'h0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
tx_data_cnt <= #UDLY tx_data_cnt + 1;
always @(posedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_done <= #UDLY 1'b0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_done <= #UDLY 1'b1;
else
tx_done <= #UDLY 1'b0;
//-----------------------------------update at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1
`else
// always @(negedge SCLK_SLAVE or posedge RST_I)
// if (RST_I)
// MISO_SLAVE <= #UDLY 1'b0;
// else
// MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] :
// reg_txdata[DATA_LENGTH-tx_data_cnt-1];
always @(negedge SCLK_SLAVE)
if (!CSn_SLAVE)
MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] :
reg_txdata[DATA_LENGTH-tx_data_cnt-1];
else
MISO_SLAVE<=1'bz;
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_data_cnt <= #UDLY 'h0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_data_cnt <= #UDLY 'h0;
else if (!CSn_SLAVE)
tx_data_cnt <= #UDLY tx_data_cnt + 1;
always @(negedge SCLK_SLAVE or posedge RST_I)
if (RST_I)
tx_done <= #UDLY 1'b0;
else if (tx_data_cnt == DATA_LENGTH - 1)
tx_done <= #UDLY 1'b1;
else
tx_done <= #UDLY 1'b0;
`endif
`endif
always @(posedge CLK_I or posedge RST_I)
if (RST_I) begin
tx_done_flip1 <= #UDLY 1'b0;
tx_done_flip2 <= #UDLY 1'b0;
tx_done_flip3 <= #UDLY 1'b0;
end
else begin
tx_done_flip1 <= #UDLY tx_done;
tx_done_flip2 <= #UDLY tx_done_flip1;
tx_done_flip3 <= #UDLY tx_done_flip2;
end
always @(posedge CLK_I or posedge RST_I)
if (RST_I)
reg_trdy <= #UDLY 1'b1;
else if (!WR_RD && !CSn)
reg_trdy <= #UDLY 1'b0;
else if (tx_done_flip2 && !tx_done_flip3)
reg_trdy <= #UDLY 1'b1;
always @(posedge CLK_I or posedge RST_I)
if(RST_I)
reg_toe <= #UDLY 1'b0;
else if(!reg_trdy && !WR_RD && !CSn)
reg_toe <= #UDLY 1'b1;
else if(!WR_RD && !CSn)
reg_toe <= #UDLY 1'b0;
endmodule
тестбенч:
CODE
`timescale 1ns/1ps
module spi_speripheral_tb;
wire clk,rst;
wire mosi,csn_spi,sclk;
wire csn,wr_rd;
wire [7:0] data_out;
wire miso;
wire tx_rdy,rx_rdy,tx_err,rx_err;
wire [7:0] data_in;
spi_master spi_master(
.sclk_master(sclk),
.csn_master(csn_spi),
.mosi_master(mosi),
.miso_master(miso)
);
spi_slave spi_slave
(
//slave port
.CSn(csn),
.DATA_IN(data_in), //8 bit width - changed from 32 bits
.WR_RD(wr_rd),
.DATA_OUT(data_out), //8 bit width - changed from 32 bits
.TX_RDY(tx_rdy),
.RX_RDY(rx_rdy),
.TX_ERR(tx_err),
.RX_ERR(rx_err),
//spi interface
.MISO_SLAVE(miso),
.MOSI_SLAVE(mosi),
.CSn_SLAVE(csn_spi),
.SCLK_SLAVE(sclk),
//system clock and reset
.CLK_I(clk),
.RST_I(rst)
);
back_end_device back_end_device(
.CSn(csn),
.DATA_IN(data_out),
.WR_RD(wr_rd),
.DATA_OUT(data_in),
.TX_RDY(tx_rdy),
.RX_RDY(rx_rdy),
.TX_ERR(tx_err),
.RX_ERR(rx_err),
.CLK(clk),
.RST(rst)
);
endmodule
`timescale 1ns/1ps
module spi_master(
sclk_master,
csn_master,
mosi_master,
miso_master
);
parameter CLOCK_PHASE = 0;
parameter CLOCK_POLARITY = 0;
parameter sclk_cycle= 40;
parameter SHIFT_DIRECTION = 0;
parameter DATA_LENGTH = 8; // changed from 32 to 8
output sclk_master;
output csn_master;
output mosi_master;
input miso_master;
reg sclk_master;
reg csn_master;
reg mosi_master;
reg [7:0] master_data_in;
reg [7:0] master_data_out;
reg [2:0] cnt;
initial begin
if(CLOCK_POLARITY)
sclk_master<=#1 1'b1;
else
sclk_master<=#1 1'b0;
csn_master<=1'b1;
master_data_in<=8'h00;
master_data_out<=8'h00;
cnt<=3'h0;
mosi_master<=1'b0;
#306;
spi_master_operation(8'h73);
#100;
spi_master_operation(8'h43);
#104;
spi_master_operation(8'h19);
#100
spi_master_operation(8'h55);
#100
spi_master_operation(8'haa);
#100
$stop;
end
task spi_master_operation;
input [7:0] data_out;
integer i;
begin
$display($time,"ns: SPI master sends data %h",data_out);
master_data_out=data_out;
csn_master<=1'b0;
if(!CLOCK_POLARITY) begin
if(!CLOCK_PHASE) begin
cnt<=3'h0;
for (i = 7; i >= 0; i = i - 1) begin
mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1];
#sclk_cycle;
sclk_master<=#1 1'b1;
master_data_in<={master_data_in[6:0],miso_master};
#sclk_cycle;
sclk_master<=#1 1'b0; // at the falling edge of SCLK.
cnt=cnt+1;
end
#2;
csn_master<=1'b1;
end
else begin
cnt<=3'h0;
for (i = 7; i >= 0; i = i - 1) begin
#sclk_cycle;
sclk_master<=1'b1; // at the raising edge of SCLK.
mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1];
cnt<=cnt+1;
#sclk_cycle;
sclk_master<=1'b0;
master_data_in<={master_data_in[6:0],miso_master};
end
#2;
csn_master<=1'b1;
end
end
else begin
if(!CLOCK_PHASE) begin
cnt<=3'h0;
for (i = 7; i >= 0; i = i - 1) begin
mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1];
#sclk_cycle;
sclk_master<=1'b0;
master_data_in<={master_data_in[6:0],miso_master};
#sclk_cycle;
sclk_master<=1'b1; // at the raising edge of SCLK.
cnt=cnt+1;
end
#2;
csn_master<=1'b1;
end
else begin
cnt<=3'h0;
for (i = 7; i >= 0; i = i - 1) begin
#sclk_cycle;
sclk_master<=1'b0; // at the falling edge of SCLK.
mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1];
cnt<=cnt+1;
#sclk_cycle;
sclk_master<=1'b1;
master_data_in<={master_data_in[6:0],miso_master};
end
#2;
csn_master<=1'b1;
end
end
$display($time,"ns: SPI master receive data %h",master_data_in);
end
endtask
endmodule
`timescale 1ns/1ps
module back_end_device(
CSn,
DATA_IN,
WR_RD,
DATA_OUT,
TX_RDY,
RX_RDY,
TX_ERR,
RX_ERR,
CLK,
RST
);
output CLK;
output RST;
output CSn;
input [7:0] DATA_IN;
output WR_RD;
output [7:0] DATA_OUT;
input TX_RDY;
input RX_RDY;
input TX_ERR;
input RX_ERR;
parameter clk_cycle= 10;
reg CLK;
reg RST;
reg CSn;
reg WR_RD;
reg [7:0] DATA_OUT;
integer i;
always #(clk_cycle/2) CLK = ~CLK;
initial begin
RST<=1'b0;
CLK<= 1'b0;
CSn<=1'b1;
WR_RD<=1'b1;
DATA_OUT<=8'h00;
i=0;
#2;
RST<=1'b1;
#200;
RST<=1'b0;
while(i<3) begin
@(posedge CLK)
if(RX_RDY || TX_RDY) begin
if(TX_RDY) begin
CSn<=#1 1'b0;
WR_RD<=#1 1'b0;
DATA_OUT=#1 $random % 60;
i=i+1;
$display($time,"ns: Back end device send data %h",DATA_OUT);
@(posedge CLK)
CSn<=#1 1'b1;
WR_RD<=#1 1'b1;
end
else if(RX_RDY) begin
CSn<=#1 1'b0;
WR_RD<=#1 1'b1;
$display($time,"ns: Back end device receive data %h",DATA_IN);
@(posedge CLK)
CSn<=#1 1'b1;
WR_RD<=#1 1'b1;
end
end
end
@(posedge CLK)
CSn<=#1 1'b0;
WR_RD<=#1 1'b0;
DATA_OUT=#1 $random % 60;
$display($time,"ns: Back end device send data %h",DATA_OUT);
@(posedge CLK)
CSn<=#1 1'b1;
WR_RD<=#1 1'b1;
end
endmodule
//--------------------------------EOF-----------------------------------------
module BI_DIR (O,I0,IO,OE);
input I0,OE;
inout IO;
output O;
supply0 GND;
supply1 VCC;
reg IO0, O0;
wire IO1;
parameter PULL = "Off";
parameter OUTOPEN = "Off";
//assign O=O0;
buf INSXQ1 (O,O0);
//assign IO = IO0;
//buf INSXQ2 (IO,IO0);
//assign IO1 = IO;
buf INSXQ3 (IO1,IO);
bufif1 INSXQ2 (IO,IO0,OE);
always @(IO1)
begin
if (PULL == "Off")
case(IO1)
1'b0: O0 = 1'b0;
1'b1: O0 = 1'b1;
1'bz: O0 = 1'bx;
1'bx: O0 = 1'bx;
endcase
else if (PULL == "Up")
case(IO1)
1'b0: O0 = 1'b0;
1'b1: O0 = 1'b1;
1'bz: O0 = 1'b1;
endcase
else if (PULL == "Down")
case(IO1)
1'b0: O0 = 1'b0;
1'b1: O0 = 1'b1;
1'bz: O0 = 1'b0;
endcase
else if (PULL == "Hold")
case(IO1)
1'b0: O0 = 1'b0;
1'b1: O0 = 1'b1;
1'bz: O0 = O0;
endcase
end
always @(OE or I0)
begin
if (OE == 1'b0)
IO0 = 1'bz;
else if (OE == 1'b1)
if (OUTOPEN == "Off")
case(I0)
1'b0: IO0 = 1'b0;
1'b1: IO0 = 1'b1;
1'bz: IO0 = 1'bx;
1'bx: IO0 = 1'bx;
endcase
else if (OUTOPEN == "Drain" || OUTOPEN == "Collect")
begin
if (I0 == 1'b0)
IO0 = 1'b0;
else if (I0 == 1'b1)
begin
if (PULL == "Off")
IO0 = 1'bz;
else if (PULL == "Up")
IO0 = 1'b1;
else if (PULL == "Down")
IO0 = 1'b0;
else if (PULL == "Hold")
IO0 = IO0;
else
IO0 = 1'bz;
end
else
IO0 = 1'bx;
end
end
specify
(I0 => IO) = 0:0:0, 0:0:0;
(OE => IO) = 0:0:0, 0:0:0;
(IO => O) = 0:0:0, 0:0:0;
endspecify
endmodule
PS могу поделиться описанием на VHDL...
If it doesn't work in simulation, it won't work on the board.
"Ты живешь в своих поступках, а не в теле. Ты — это твои действия, и нет другого тебя" Антуан де Сент-Экзюпери повесть "Маленький принц"