Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: модуль spi slave verilog
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
sergey sva
Хочу попробовать запустить spi slave на циклоне. Поискал в сети готовые исходники, примеров много для этого интерфейса не знаю с какого начать, подскажите пожалуйста ссылку на проверенный пример, который вам понравился ))
Maverick
Цитата(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...
sergey sva
Благодарю за код, давайте если не жалко )).
Есть какие отличия ? На верилоге вроде компактнее получается код, конечно у меня опыта не много поэтому утверждать не буду.
Сейчас попробую протестировать на stm32f407 ep3c5e результат напишу.

Значок решетка что означает? Немного не по теме, случайно не знаете в квартусе 13,1 есть автоформатирование кода ?
Maverick
Цитата(sergey sva @ May 10 2015, 12:03) *
Благодарю за код, давайте если не жалко )).
Есть какие отличия ?


описание на VHDL - функциональных отличий нет по сравнению с описанием на verilog.

CODE
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity spi_slave is
generic (DATA_LENGTH : integer:=8;
SHIFT_DIRECTION: std_logic := '0';
CLOCK_POLARITY:std_logic:='0';
CLOCK_PHASE:std_logic:='0');
port (
CSn : in std_logic;
DATA_IN : in std_logic_vector(7 downto 0);
WR_RD : in std_logic;
DATA_OUT : out std_logic_vector(7 downto 0);
TX_RDY : out std_logic;
RX_RDY : out std_logic;
TX_ERR : out std_logic;
RX_ERR : out std_logic;
CLK_I : in std_logic;
RST_I : in std_logic;
MISO_SLAVE : out std_logic;
MOSI_SLAVE : in std_logic;
CSn_SLAVE : in std_logic;
SCLK_SLAVE : in std_logic
);

end;

architecture arch of spi_slave is
constant UDLY:time:=1 ns;
signal latch_s_data:std_logic_vector(7 downto 0);
signal reg_rxdata:std_logic_vector(DATA_LENGTH-1 downto 0);
signal reg_txdata:std_logic_vector(DATA_LENGTH-1 downto 0);
signal rx_shift_data:std_logic_vector(DATA_LENGTH-1 downto 0);

signal reg_toe:std_logic;
signal reg_roe:std_logic;
signal reg_trdy:std_logic;
signal reg_rrdy:std_logic;

signal tx_done:std_logic;
signal rx_done:std_logic;
signal rx_done_flip1:std_logic;
signal rx_done_flip2:std_logic;
signal rx_done_flip3:std_logic;
signal tx_done_flip1:std_logic;
signal tx_done_flip2:std_logic;
signal tx_done_flip3:std_logic;
signal rx_data_cnt:std_logic_vector(5 downto 0);
signal tx_data_cnt:std_logic_vector(5 downto 0);

begin

TX_RDY<=reg_trdy;
RX_RDY<=reg_rrdy;
TX_ERR<=reg_toe;
RX_ERR<=reg_roe;
DATA_OUT<=reg_rxdata;

process(CLK_I,RST_I) begin
if(RST_I='1') then
latch_s_data <= (others => '0');
elsif rising_edge(CLK_I) then
if (WR_RD='0' and CSn='0' and reg_trdy='1') then
latch_s_data <=DATA_IN;
end if;
end if;
end process;

--Receive Data Register
process(CLK_I,RST_I) begin
if(RST_I='1') then
reg_rxdata <=(others => '0');
elsif rising_edge(CLK_I) then
if (rx_done_flip1='1' and rx_done_flip2='0') then
reg_rxdata <= rx_shift_data;
end if;
end if;
end process;

--Transmit Data Register
process(CLK_I,RST_I) begin
if(RST_I='1') then
reg_txdata <= (others => '0');
elsif rising_edge(CLK_I) then
reg_txdata <= latch_s_data;
end if;
end process;

-------------------------------For Rx data,
-------------------sample at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0

u1: if CLOCK_POLARITY='0' and CLOCK_PHASE='0' generate

process(SCLK_SLAVE,RST_I) begin
if (RST_I='1') then
rx_shift_data <= (others => '0');
elsif rising_edge(SCLK_SLAVE) then
if (CSn_SLAVE='0') then
if (SHIFT_DIRECTION='1') then
rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1);
else
rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE;
end if;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_data_cnt <= (others => '0');
elsif rising_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_data_cnt <=(others => '0');
elsif (CSn_SLAVE='0') then
rx_data_cnt <=rx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_done <= '0';
elsif rising_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_done <= '1';
else
rx_done <= '0';
end if;
end if;
end process;
end generate;
-------------------sample at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1
u2: if CLOCK_POLARITY='0' and CLOCK_PHASE='1' generate
--For Rx data, sample at negedge when CLOCK_PHASE is 1
process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_shift_data <= (others => '0');
elsif falling_edge(SCLK_SLAVE) then
if (CSn_SLAVE='0') then
if (SHIFT_DIRECTION='1') then
rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1);
else
rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE;
end if;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_data_cnt <= (others => '0');
elsif falling_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_data_cnt <=(others => '0');
elsif (CSn_SLAVE='0') then
rx_data_cnt <=rx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_done <= '0';
elsif falling_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_done <= '1';
else
rx_done <= '0';
end if;
end if;
end process;
end generate;
-------------------sample at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0
u3:if CLOCK_POLARITY='1' and CLOCK_PHASE='0' generate

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_shift_data <= (others => '0');
elsif falling_edge(SCLK_SLAVE) then
if (CSn_SLAVE='0') then
if (SHIFT_DIRECTION='1') then
rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1);
else
rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE;
end if;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_data_cnt <= (others => '0');
elsif falling_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_data_cnt <=(others => '0');
elsif (CSn_SLAVE='0') then
rx_data_cnt <=rx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_done <= '0';
elsif falling_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_done <= '1';
else
rx_done <= '0';
end if;
end if;
end process;
end generate;

-------------------sample at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1
u4: if CLOCK_POLARITY='1' and CLOCK_PHASE='1' generate
--For Rx data, sample at negedge when CLOCK_PHASE is 1
process(SCLK_SLAVE,RST_I) begin
if (RST_I='1') then
rx_shift_data <= (others => '0');
elsif rising_edge(SCLK_SLAVE) then
if (CSn_SLAVE='0') then
if (SHIFT_DIRECTION='1') then
rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1);
else
rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE;
end if;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_data_cnt <= (others => '0');
elsif rising_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_data_cnt <=(others => '0');
elsif (CSn_SLAVE='0') then
rx_data_cnt <=rx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
rx_done <= '0';
elsif rising_edge(SCLK_SLAVE) then
if (rx_data_cnt = DATA_LENGTH - 1) then
rx_done <= '1';
else
rx_done <= '0';
end if;
end if;
end process;
end generate;

process(CLK_I,RST_I) begin
if (RST_I='1') then
rx_done_flip1 <= '0';
rx_done_flip2 <= '0';
rx_done_flip3 <= '0';
elsif rising_edge(CLK_I) then
rx_done_flip1 <= rx_done;
rx_done_flip2 <= rx_done_flip1;
rx_done_flip3 <= rx_done_flip2;
end if;
end process;


process(CLK_I,RST_I) begin
if (RST_I='1') then
reg_rrdy <= '0';
elsif rising_edge(CLK_I) then
if (rx_done_flip2='1' and rx_done_flip3='0') then
reg_rrdy <= '1';
elsif (WR_RD='1' and CSn='0') then
reg_rrdy <= '0';
end if;
end if;
end process;

process(CLK_I,RST_I) begin
if (RST_I='1') then
reg_roe <= '0';
elsif rising_edge(CLK_I) then
if (rx_done_flip2='1' and rx_done_flip3='0' and reg_rrdy='1') then
reg_roe <= '1';
elsif (WR_RD='1' and CSn='0') then
reg_roe <= '0';
end if;
end if;
end process;

----------------------For Tx data,
-------------------------------------update at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0
u11: if CLOCK_POLARITY='0' and CLOCK_PHASE='0' generate

process(reg_txdata,tx_data_cnt,CSn_SLAVE ) begin
if (CSn_SLAVE='0') then
if(SHIFT_DIRECTION='1') then
MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt));
else
MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1));
end if;
else
MISO_SLAVE<='Z';
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_data_cnt <= (others => '0');
elsif falling_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_data_cnt <= (others => '0');
elsif (CSn_SLAVE='0') then
tx_data_cnt <= tx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_done <='0';
elsif falling_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_done <= '1';
else
tx_done <= '0';
end if;
end if;
end process;
end generate;
-------------------------------------update at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1
u22: if CLOCK_POLARITY='0' and CLOCK_PHASE='1' generate

process (SCLK_SLAVE) begin
if rising_edge(CLK_I) then
if (CSn_SLAVE='0') then
if(SHIFT_DIRECTION='1') then
MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt));
else
MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1));
end if;
else
MISO_SLAVE<='Z';
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_data_cnt <= (others => '0');
elsif rising_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_data_cnt <= (others => '0');
elsif (CSn_SLAVE='0') then
tx_data_cnt <= tx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_done <= '0';
elsif rising_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_done <= '1';
else
tx_done <= '0';
end if;
end if;
end process;
end generate;

-------------------------------------update at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0
u33: if CLOCK_POLARITY='1' and CLOCK_PHASE='0' generate
process(reg_txdata,tx_data_cnt,CSn_SLAVE ) begin
if (CSn_SLAVE='0') then
if(SHIFT_DIRECTION='1') then
MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt));
else
MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1));
end if;
else
MISO_SLAVE<='Z';
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_data_cnt <= (others => '0');
elsif rising_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_data_cnt <= (others => '0');
elsif (CSn_SLAVE='0') then
tx_data_cnt <= tx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_done <= '0';
elsif rising_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_done <= '1';
else
tx_done <= '0';
end if;
end if;
end process;

end generate;

-------------------------------------update at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1
u44: if CLOCK_POLARITY='1' and CLOCK_PHASE='1' generate

process (SCLK_SLAVE) begin
if falling_edge(CLK_I) then
if (CSn_SLAVE='0') then
if(SHIFT_DIRECTION='1') then
MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt));
else
MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1));
end if;
else
MISO_SLAVE<='Z';
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_data_cnt <= (others => '0');
elsif falling_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_data_cnt <= (others => '0');
elsif (CSn_SLAVE='0') then
tx_data_cnt <= tx_data_cnt + 1;
end if;
end if;
end process;

process(SCLK_SLAVE ,RST_I) begin
if (RST_I='1') then
tx_done <='0';
elsif falling_edge(SCLK_SLAVE) then
if (tx_data_cnt = DATA_LENGTH - 1) then
tx_done <= '1';
else
tx_done <= '0';
end if;
end if;
end process;

end generate;

process(CLK_I,RST_I) begin
if (RST_I='1') then
tx_done_flip1 <= '0';
tx_done_flip2 <= '0';
tx_done_flip3 <= '0';
elsif rising_edge(CLK_I) then
tx_done_flip1 <= tx_done;
tx_done_flip2 <= tx_done_flip1;
tx_done_flip3 <= tx_done_flip2;
end if;
end process;

process(CLK_I,RST_I) begin
if (RST_I='1') then
reg_roe <= '0';
elsif rising_edge(CLK_I) then
if (rx_done_flip2='1' and rx_done_flip3='0' and reg_rrdy='1') then
reg_roe <= '1';
elsif (WR_RD='1' and CSn='0') then
reg_roe <= '0';
end if;
end if;
end process;


process(CLK_I,RST_I) begin
if (RST_I='1') then
reg_trdy <= '1';
elsif rising_edge(CLK_I) then
if (WR_RD='0' and CSn='0') then
reg_trdy <= '0';
elsif (tx_done_flip2='1' and tx_done_flip3='0') then
reg_trdy <= '1';
end if;
end if;
end process;


process(CLK_I,RST_I) begin
if (RST_I='1') then
reg_toe <= '0';
elsif rising_edge(CLK_I) then
if(reg_trdy='0' and WR_RD='0' and CSn='0') then
reg_toe <= '1';
elsif(WR_RD='0' and CSn='0') then
reg_toe <= '0';
end if;
end if;
end process;

end arch;


тестбенч:

CODE
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity spi_master is
port(
sclk_master: out std_logic;
csn_master: out std_logic;
mosi_master: out std_logic;
miso_master: in std_logic
);
end;

architecture arch_spi_master of spi_master is

constant CLOCK_PHASE:std_logic:='0';
constant CLOCK_POLARITY:std_logic:='0';
constant SHIFT_DIRECTION:std_logic:='0';
constant DATA_LENGTH:integer:= 8;

--signal master_data_in:std_logic_vector(7 downto 0);
--signal master_data_out:std_logic_vector(7 downto 0);
--
--signal cnt:std_logic_vector(2 downto 0);

signal sclk_master_tmp: std_logic;
signal csn_master_tmp: std_logic;
signal mosi_master_tmp: std_logic;

function slv4_xcha (inp: STD_LOGIC_VECTOR(3 downto 0)) return CHARACTER is
variable result: character;

begin
case inp is
when "0000" => result := '0';
when "0001" => result := '1';
when "0010" => result := '2';
when "0011" => result := '3';
when "0100" => result := '4';
when "0101" => result := '5';
when "0110" => result := '6';
when "0111" => result := '7';
when "1000" => result := '8';
when "1001" => result := '9';
when "1010" => result := 'a';
when "1011" => result := 'b';
when "1100" => result := 'c';
when "1101" => result := 'd';
when "1110" => result := 'e';
when "1111" => result := 'f';
when others => result := 'x';
end case;
return result;
end;

function slv8_xstr (inp: STD_LOGIC_VECTOR(7 downto 0)) return STRING is
variable result : string (1 to 2);

begin
result := slv4_xcha(inp(7 downto 4)) & slv4_xcha(inp(3 downto 0));
return result;
end;

procedure spi_master_operation (signal sclk_master_tmp : out std_logic;
signal csn_master_tmp: out std_logic;
signal mosi_master_tmp: out std_logic;
signal miso_master: in std_logic;
constant data_out:in STD_LOGIC_VECTOR(7 downto 0);
constant CLOCK_PHASE : in std_logic;
constant CLOCK_POLARITY : in std_logic;
constant SHIFT_DIRECTION : in std_logic;
constant DATA_LENGTH : in integer
) is
variable master_data_in:std_logic_vector(7 downto 0):=(others => '0');
variable master_data_out:std_logic_vector(7 downto 0):=(others => '0');
variable cnt:integer;
variable i:integer;
variable sclk_cycle:time:=40 ns;

begin
csn_master_tmp<='1';
mosi_master_tmp<='0';
report "SPI master sends data " & slv8_xstr(data_out);
master_data_out:=data_out;
csn_master_tmp<='0';
if(CLOCK_POLARITY='0') then
if(CLOCK_PHASE='0') then
cnt:=0;
for i in 7 downto 0 loop
if(SHIFT_DIRECTION='1') then
mosi_master_tmp<=master_data_out(cnt);
else
mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1);
end if;
wait for sclk_cycle;
sclk_master_tmp<='1';
master_data_in:=(master_data_in(6 downto 0) & miso_master);
wait for sclk_cycle;
sclk_master_tmp<='0';
cnt:=cnt+1;
end loop;
wait for 2 ns;
csn_master_tmp<='1';
else
cnt:=0;
for i in 7 downto 0 loop
wait for sclk_cycle;
sclk_master_tmp<='1';
if(SHIFT_DIRECTION='1') then
mosi_master_tmp<=master_data_out(cnt);
else
mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1);
end if;
cnt:=cnt+1;
wait for sclk_cycle;
sclk_master_tmp<='0';
master_data_in:=(master_data_in(6 downto 0) & miso_master);
end loop;
wait for 2 ns;
csn_master_tmp<='1';
end if;

else
if(CLOCK_PHASE='0') then
cnt:=0;
for i in 7 downto 0 loop
if(SHIFT_DIRECTION='1') then
mosi_master_tmp<=master_data_out(cnt);
else
mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1);
end if;
wait for sclk_cycle;
sclk_master_tmp<='0';
master_data_in:=(master_data_in(6 downto 0) & miso_master);
wait for sclk_cycle;
sclk_master_tmp<='1';
cnt:=cnt+1;
end loop;
wait for 2 ns;
csn_master_tmp<='1';

else
cnt:=0;
for i in 7 downto 0 loop
wait for sclk_cycle;
sclk_master_tmp<='0';
if(SHIFT_DIRECTION='1') then
mosi_master_tmp<=master_data_out(cnt);
else
mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1);
end if;
cnt:=cnt+1;
wait for sclk_cycle;
sclk_master_tmp<='1';
master_data_in:=(master_data_in(6 downto 0) & miso_master);
end loop;
wait for 2 ns;
csn_master_tmp<='1';
end if;
end if;
report "SPI master receive data " & slv8_xstr(master_data_in);
end;

begin

sclk_master<=sclk_master_tmp;
csn_master<=csn_master_tmp;
mosi_master<=mosi_master_tmp;

initial: process begin
--wait for 1 ns;
if(CLOCK_POLARITY='1') then
sclk_master_tmp<='1' after 1 ns;
else
sclk_master_tmp<='0';
end if;

wait for 306 ns;

spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master,
"01110011",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH);

wait for 100 ns;

spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master,
"01000011",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH);

wait for 104 ns;

spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master,
"00011001",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH);

wait for 100 ns;

spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master,
"01010101",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH);

wait for 100 ns;

spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master,
"10101010",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH);

wait for 100 ns;
wait;
end process;

end arch_spi_master;


-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity back_end_device is
port(
CSn: out std_logic;
DATA_IN:in STD_LOGIC_VECTOR(7 downto 0);
WR_RD: out std_logic;
DATA_OUT:out STD_LOGIC_VECTOR(7 downto 0);
TX_RDY: in std_logic;
RX_RDY: in std_logic;
TX_ERR: in std_logic;
RX_ERR: in std_logic;
CLK: out std_logic;
RST: out std_logic
);
end;

architecture arch_back_end_device of back_end_device is
constant clk_cycle:time:=5 ns;
signal clk_temp:std_logic;
signal data_out_temp:STD_LOGIC_VECTOR(7 downto 0);
signal i:integer:=0;

function slv4_xcha_r (inp: STD_LOGIC_VECTOR(3 downto 0)) return CHARACTER is
variable result: character;

begin
case inp is
when "0000" => result := '0';
when "0001" => result := '1';
when "0010" => result := '2';
when "0011" => result := '3';
when "0100" => result := '4';
when "0101" => result := '5';
when "0110" => result := '6';
when "0111" => result := '7';
when "1000" => result := '8';
when "1001" => result := '9';
when "1010" => result := 'a';
when "1011" => result := 'b';
when "1100" => result := 'c';
when "1101" => result := 'd';
when "1110" => result := 'e';
when "1111" => result := 'f';
when others => result := 'x';
end case;
return result;
end;

function slv8_xstr_r (inp: STD_LOGIC_VECTOR(7 downto 0)) return STRING is
variable result : string (1 to 2);

begin
result := slv4_xcha_r(inp(7 downto 4)) & slv4_xcha_r(inp(3 downto 0));
return result;
end;
begin

clk_gen:process
begin
clk_temp<='0';
wait for clk_cycle;
loop
clk_temp<=not clk_temp;
wait for clk_cycle;
end loop;
end process;

CLK<=clk_temp;
DATA_OUT<=data_out_temp;

initial: process begin
RST<='0';
CSn<='1';
WR_RD<='1';
data_out_temp<=(others => '0');

wait for 2 ns;
RST<='1';
wait for 202 ns;
RST<='0';

while(i<3) loop
wait until clk_temp'event and clk_temp = '1';
if(RX_RDY='1' or TX_RDY='1') then
if(TX_RDY='1') then
CSn<='0' after 1 ns;
WR_RD<='0' after 1 ns;
if(i=0) then
data_out_temp<="00001000" after 1 ns;
elsif(i=1) then
data_out_temp<="11101101" after 1 ns;
elsif(i=2) then
data_out_temp<="11011001" after 1 ns;
end if;
i<=i+1;
wait for 1 ns;
report "Back end device send data " & slv8_xstr_r(data_out_temp);
wait until clk_temp'event and clk_temp = '1';
CSn<='1' after 1 ns;
WR_RD<='1' after 1 ns;
elsif(RX_RDY='1') then
CSn<='0' after 1 ns;
WR_RD<='1' after 1 ns;
report "Back end device receive data " & slv8_xstr_r(DATA_IN);

wait until clk_temp'event and clk_temp = '1';
CSn<='1' after 1 ns;
WR_RD<='1' after 1 ns;
end if;
end if;
end loop;

while(i=3) loop
wait until clk_temp'event and clk_temp = '1';
CSn<='0' after 1 ns;
WR_RD<='0' after 1 ns;
data_out_temp<="11100011" after 1 ns;
wait for 1 ns;
report "Back end device send data " & slv8_xstr_r(data_out_temp);
wait until clk_temp'event and clk_temp = '1';
CSn<='1' after 1 ns;
WR_RD<='1' after 1 ns;
i<=4;
end loop;
wait for 2500 ns;
--wait;
end process;


end arch_back_end_device;

-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity spi_speripheral_tb is
end spi_speripheral_tb;

architecture arch_spi_speripheral_tb of spi_speripheral_tb is

component spi_slave is
--generic (DATA_LENGTH : integer:=8;
-- SHIFT_DIRECTION: std_logic := '0';
-- CLOCK_POLARITY:std_logic:='0';
-- CLOCK_PHASE:std_logic:='0');
port (
CSn : in std_logic;
DATA_IN : in std_logic_vector(7 downto 0);
WR_RD : in std_logic;
DATA_OUT : out std_logic_vector(7 downto 0);
TX_RDY : out std_logic;
RX_RDY : out std_logic;
TX_ERR : out std_logic;
RX_ERR : out std_logic;
CLK_I : in std_logic;
RST_I : in std_logic;
MISO_SLAVE : out std_logic;
MOSI_SLAVE : in std_logic;
CSn_SLAVE : in std_logic;
SCLK_SLAVE : in std_logic
);

end component;

component spi_master is
port(
sclk_master: out std_logic;
csn_master: out std_logic;
mosi_master: out std_logic;
miso_master: in std_logic
);
end component;

component back_end_device is
port(
CSn: out std_logic;
DATA_IN: in std_logic_vector(7 downto 0);
WR_RD: out std_logic;
DATA_OUT: out std_logic_vector(7 downto 0);
TX_RDY: in std_logic;
RX_RDY: in std_logic;
TX_ERR: in std_logic;
RX_ERR: in std_logic;
CLK: out std_logic;
RST: out std_logic
);
end component;

signal clk,rst:std_logic;
signal mosi,csn_spi,sclk:std_logic;
signal csn,wr_rd:std_logic;
signal data_out:std_logic_vector(7 downto 0);

signal miso:std_logic;
signal tx_rdy,rx_rdy,tx_err,rx_err:std_logic;
signal data_in:std_logic_vector(7 downto 0);

begin

spi_master_uut: spi_master port map(
sclk_master=>sclk,
csn_master=>csn_spi,
mosi_master=>mosi,
miso_master=>miso
);

spi_slave_uut: spi_slave port map
(
CSn=>csn,
DATA_IN=>data_in,
WR_RD=>wr_rd,
DATA_OUT=>data_out,
TX_RDY=>tx_rdy,
RX_RDY=>rx_rdy,
TX_ERR=>tx_err,
RX_ERR=>rx_err,

MISO_SLAVE=>miso,
MOSI_SLAVE=>mosi,
CSn_SLAVE=>csn_spi,
SCLK_SLAVE=>sclk,
CLK_I=>clk,
RST_I=>rst
);

back_end_device_uut: back_end_device port map(
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
);

end arch_spi_speripheral_tb;


Цитата
Значок решетка что означает?

#100; (verilog) = wait for 100 ns; (vhdl)

PS у меня это описание работало в "железе"
PS PS Мне не жалко, в надежде, что когда мне что-то понадобиться, то тоже люди тоже откликнуться и помогут...
sergey sva
Благодарю вас. Эта задержка синтезируется или это только для симулятора?
Maverick
Цитата(sergey sva @ May 10 2015, 16:09) *
Благодарю вас. Эта задержка синтезируется или это только для симулятора?

только для симулятора
sergey sva
Понятно. Попробовал сразу все заработало)). Частоту подал на clck_in 200Мгц , правильно ?

Код
spi_slave spi_uc(csn,datain,wr_rd,dataout,tx_rdy,rx_rdy,tx_err,rx_err,CLOCK,RESET,SDOUT_UC,SD
I_UC,CS_UC,SCLCK_UC);
//--------------------------------------------------------------------------//


//--------------------------------------------------------------------------//
always@(posedge CLOCK )
begin
    if(RESET == 1)
     begin        
        rxtxrdwr     <= 8'd0;
        adressreg    <= 8'd0;
         getadres     <= 1'b0;         
         csn          <= 1'b1;  
       wr_rd        <= 1'b1;
        
         for(initdatafor = 0; initdatafor < 8'd255;initdatafor = initdatafor + 8'd1)
       begin
         dataINuc[initdatafor]  <= 8'd0;
          dataOUTuc[initdatafor] <= 8'd0;
       end    
    
     end
     else begin
    
          if(CS_UC == 1)
           begin
               getadres  <= 1'b0;
           end  
    
    
          if(tx_rdy || rx_rdy) begin
             if(tx_rdy) begin
                 csn<= 1'b0;
                 wr_rd<= 1'b0;  
                      rxtxrdwr <= 8'd1;
                      
                      if(getadres == 1)
                      begin
                     datain <= 20;//dataOUTuc[adressreg];
                      end else
                      begin
                          datain <= 8'd0;
                      end      
                
                
             end
             else if(rx_rdy) begin          
                 csn<=  1'b0;
                 wr_rd<=  1'b1;                
                      rxtxrdwr <= 8'd2;
                    
                      if(getadres == 0)
                      begin
                          getadres  <= 1'b1;
                            adressreg <= dataout;                            
                      end else
                      begin
                          dataINuc[adressreg] <= dataout;                     
                     end            
                  
            
             end
          end else
            begin
                if(rxtxrdwr == 1)begin
                     csn<= 1'b1;  
                 wr_rd<= 1'b1;
                     rxtxrdwr <= 8'd0;
                 end else if(rxtxrdwr == 2)begin    
                  csn<=  1'b1;  
                 wr_rd<=  1'b1;
                     rxtxrdwr <= 8'd0;
                 end
            
            
            end
    
    
    
     end
end
//--------------------------------------------------------------------------//

Единственное почему то последний байт не доходит например отправляю с плис 20 в мк приходит 10 и тд.
Микроконтроллер вначале пробовал с mems датчиком что бы проверить правильность настройки spi интерфейса в микроконтроллере.
Maverick
Цитата(sergey sva @ May 10 2015, 16:20) *
Единственное почему то последний байт не доходит например отправляю с плис 20 в мк приходит 10 и тд.
Микроконтроллер вначале пробовал с mems датчиком что бы проверить правильность настройки spi интерфейса в микроконтроллере.

режимы работы SPI в мк и в плис должны совпадать. совпадают?

Цитата
Для обозначения режимов работы интерфейса SPI принято следующее соглашений:

режим 1 (CPOL = 0, CPHA = 0);
режим 2 (CPOL = 0, CPHA = 1);
режим 3 (CPOL = 1, CPHA = 0);
режим 4 (CPOL = 1, CPHA = 1).
sergey sva
Да совпадают
Код
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    SPI_I2S_DeInit(SPI1);
    SPI_InitTypeDef spi1;
    SPI_StructInit(&spi1);
    spi1.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    spi1.SPI_Mode = SPI_Mode_Master;
    spi1.SPI_DataSize = SPI_DataSize_8b;
    spi1.SPI_CPOL = SPI_CPOL_Low;
    spi1.SPI_CPHA = SPI_CPHA_1Edge;
    spi1.SPI_NSS =  SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
    spi1.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    spi1.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &spi1);
    SPI_Cmd(SPI1, ENABLE);
    SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);


Сделал осциллограмму если правильно смотрю из плис уходит 00001010 = 10 а должно быть 00010100.
Нажмите для просмотра прикрепленного файла



Дико извиняюсь, я напортачил не правильно настроил, все работает отлично.
нужно было объявить это
Код
`define   CLOCK_POLARITY  
`define   CLOCK_PHASE

Это настройки spi в stm32f407
Код
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    SPI_I2S_DeInit(SPI1);
    SPI_InitTypeDef spi1;
    SPI_StructInit(&spi1);
    spi1.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    spi1.SPI_Mode = SPI_Mode_Master;
    spi1.SPI_DataSize = SPI_DataSize_8b;
    spi1.SPI_CPOL = SPI_CPOL_Low;
    spi1.SPI_CPHA = SPI_CPHA_1Edge;
    spi1.SPI_NSS =  SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
    spi1.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    spi1.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &spi1);
    SPI_Cmd(SPI1, ENABLE);
    SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);

Нажмите для просмотра прикрепленного файла
большое спасибо за помощь.))
johan
Цитата(Maverick @ May 10 2015, 16:10) *
только для симулятора

Где-то читал (или сам сделал выводы sm.gif ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика.
Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ).

Maverick
Цитата(johan @ May 10 2015, 20:52) *
Где-то читал (или сам сделал выводы sm.gif ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика.
Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ).

а что оно дает для синтезатора?
sergey sva
Можно как то синтезировать задержку? Иногда очень нужна, делаю либо сдвигом клока либо внешними цепочками.
johan
Цитата(Maverick @ May 10 2015, 20:58) *
а что оно дает для синтезатора?

Разумеется, ничего sm.gif
Или смысл только в том, что бы видеть в симуляции времянки более красивые и приближенные к реальности (появления значения на выходе триггера) "позже", чем edge клока?
Или есть еще какие-то тонкости? rolleyes.gif

Цитата
Можно как то синтезировать задержку? Иногда очень нужна, делаю либо сдвигом клока либо внешними цепочками.

А для каких целей вам надо синтезировать задержку?
Вы синхронный дизайн планируете делать?
Nepoch
Цитата(johan @ May 10 2015, 21:52) *
Где-то читал (или сам сделал выводы sm.gif ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика.
Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ).

Зачем Вам задержка, если надо, чтобы у Вас часть проекта сработало через определенное время, используйте счетчик, это идеальный вариант
krux
#1 сильно помогает "старой гвардии", привыкшей работать с такими конструкциями, во время симуляции видеть причинно-следственные связи, не заглядывая в код, а догадываясь по названиям сигналов.
тем, кто учился писать RTL без #1 - его наличие/отсутствие не помогает никак, может только сбивает с толку.
fookat
Здравствуйте. Недавно начал вникать в тему FPGA и поэтому возник вопрос..
В коде присутствуют регистры для устранения метастабильности rx_done.

Код
   reg                     rx_done;
   reg                     rx_done_flip1;
   reg                     rx_done_flip2;
   reg                     rx_done_flip3;


По фронту тактирующего сигнала CLK_I происходит запись в эти регистры

Код
   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


Меня интересует почему во время записи reg_rxdata <= rx_shift_data;
используется проверка if (rx_done_flip1 && !rx_done_flip2)

Код
   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;


А при установке регистра reg_rrdy
используется проверка else if (rx_done_flip2 && !rx_done_flip3)

Код
   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;



И почему, например в (rx_done_flip2 && !rx_done_flip3), регистр rx_done_flip3 берётся с инверсией?
Чтобы значение reg_rrdy было зафиксировано только когда rx_done_flip2 установлен, а rx_done_flip3 ещё нет?

Спасибо.

Tausinov
Путем таких нехитрых условий требуемое действие происходит только на фронте сигнала. Если текущее значение ноль, а предыдущее было единичка, то это задний фронт; если текущее единичка, а предыдущее было ноль - передний фронт. Т.о., если какой-то сигнал держится в единичке или в нуле больше одного такта, можно относительно просто совершить однократное действие, связанное с его значением.
glb
Доброго дня! Использовал приведенный пример SPI, при приеме пакета по SPI сигнал RX_RDY "сдвигается" и срабатывает до окончания приема, с чем это может быть связано?
likeasm
Цитата(glb @ Aug 23 2016, 15:53) *
Доброго дня! Использовал приведенный пример SPI, при приеме пакета по SPI сигнал RX_RDY "сдвигается" и срабатывает до окончания приема, с чем это может быть связано?

может быть дребезг на фронтах клока.
Jenya7
решил поднять тему. посмотрел описание SPI Slave на VHDL. вроде логика понятна. непонятно как написать надстройку над модулем, пользовательскую логику управляющую слейвом.
если я правильно понял из тестбенч - никакого разрешающего тригера нет. передача инициализируется при CSn<='0';
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.