Перейти к содержанию
    

Хочу попробовать запустить spi slave на циклоне. Поискал в сети готовые исходники, примеров много для этого интерфейса не знаю с какого начать, подскажите пожалуйста ссылку на проверенный пример, который вам понравился ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хочу попробовать запустить spi slave на циклоне. Поискал в сети готовые исходники, примеров много для этого интерфейса не знаю с какого начать, подскажите пожалуйста ссылку на проверенный пример, который вам понравился ))

`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

 

тестбенч:

 

`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...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Благодарю за код, давайте если не жалко )).

Есть какие отличия ? На верилоге вроде компактнее получается код, конечно у меня опыта не много поэтому утверждать не буду.

Сейчас попробую протестировать на stm32f407 ep3c5e результат напишу.

 

Значок решетка что означает? Немного не по теме, случайно не знаете в квартусе 13,1 есть автоформатирование кода ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Благодарю за код, давайте если не жалко )).

Есть какие отличия ?

 

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

 

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;

 

тестбенч:

 

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 Мне не жалко, в надежде, что когда мне что-то понадобиться, то тоже люди тоже откликнуться и помогут...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Благодарю вас. Эта задержка синтезируется или это только для симулятора?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Благодарю вас. Эта задержка синтезируется или это только для симулятора?

только для симулятора

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Понятно. Попробовал сразу все заработало)). Частоту подал на 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 интерфейса в микроконтроллере.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Единственное почему то последний байт не доходит например отправляю с плис 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).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да совпадают

    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.

post-27923-1431267523_thumb.jpg

 

 

 

Дико извиняюсь, я напортачил не правильно настроил, все работает отлично.

нужно было объявить это

`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);

post-27923-1431272143_thumb.jpg

большое спасибо за помощь.))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

только для симулятора

Где-то читал (или сам сделал выводы :) ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика.

Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ).

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Где-то читал (или сам сделал выводы :) ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика.

Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ).

а что оно дает для синтезатора?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а что оно дает для синтезатора?

Разумеется, ничего :)

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

Или есть еще какие-то тонкости? :rolleyes:

 

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

А для каких целей вам надо синтезировать задержку?

Вы синхронный дизайн планируете делать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Где-то читал (или сам сделал выводы :) ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика.

Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ).

Зачем Вам задержка, если надо, чтобы у Вас часть проекта сработало через определенное время, используйте счетчик, это идеальный вариант

Изменено пользователем Nepoch

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#1 сильно помогает "старой гвардии", привыкшей работать с такими конструкциями, во время симуляции видеть причинно-следственные связи, не заглядывая в код, а догадываясь по названиям сигналов.

тем, кто учился писать RTL без #1 - его наличие/отсутствие не помогает никак, может только сбивает с толку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...