⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi_core.v

📁 verilog语言写的SPI接口,全同步设计,低门数,可以很容易应用到嵌入设计方案中.
💻 V
字号:
//----------------------------------------------------------------------------
// Project  : SCP1 - Standard Communication Platform Version 1
//----------------------------------------------------------------------------
// Source   : $Source: /db1/Razor_db/RAZOR_UNIVERSE/DOMAIN_01/SCP/Archive/RZ_VCS/scp1/design/arm_periph/spi/rtl/spi_core.v,v $
// Revision : $Revision: 1.4 $
// Date     : $Date: 1999/10/27 07:41:54 $
// Author   : $Author: coste_e $
//
//-Description----------------------------------------------------------------
// 
// 
// 
//---------------------------------------------------------------------------

module spi_core(
		clk,             //clock 
		nreset,          //async system reset
		wait_state_en,   //enable usage of wait states
		spi_si,          //spi serial output
		spi_mode,        //spi mode (0, 1, 2, 3)
		opcode_length,   //size of opcode to be transmitted
		address_length,  //size of address to be sent
		wait_numb,       //number of wait states to be inserted
		opcode_field,    //opcode to send
		addr_field,      //adress to send
		data_field,      //data to send
		start,           //initiate transfert
		transfert_type,  //read/write, opcode+read/write ....
		break,           //in case of fifo full/empty stop transmission completely
		lcd_a,           //bit value to be sent with opcode+address and data field
		time_ext,
		
		spi_clk,         //spi clock to be sent to device
		spi_so,          //spi serial output
		busy,            //indicates a tranfer is ongoing
		fifo_empty,      //fifo is empty 
		fifo_full,       //fifo is full
		nwr_fifo_r,        //write to fifo
		nrd_fifo,        //read from fifo
		nb_data_byte,    //number of data byte to send, receive
		activate_cs,     //designate the device that will be addressed
		inactive_cs_state,//activity level of the cs
		spi_cs,           //spi chip select to devices
		spi_oen,           //spi output enable active low
                rxdata,            //serialy received data
		spi_a,             //serial address for LCD
		transfert_started,
		page_number,
		n_opcode_addr_busy
		);        
   
		
		
// I/O definitions.
   
   input clk;
   input nreset;
   input wait_state_en;
   input spi_si;
   input [1:0] spi_mode;
   input [5:0] opcode_length;
   input [5:0] address_length;
   input [1:0] wait_numb;
   input [31:0] opcode_field;
   input [31:0] addr_field;
   input [7:0] 	data_field;
   input 	start;
   input [2:0] 	transfert_type;
   input 	break;
   input [1:0] 	lcd_a;
   input [2:0] 	time_ext;
      
   output 	spi_clk;
   output 	spi_so;
   output 	busy;
	
   input 	fifo_empty;
   input 	fifo_full;
   output 	nwr_fifo_r;
   output 	nrd_fifo;
   input [7:0] 	nb_data_byte;
   input [1:0] 	activate_cs;
   input [3:0] 	inactive_cs_state;
   output [3:0] spi_cs;
   output 	spi_oen;
   output [7:0] rxdata;
   output 	spi_a;
   output 	transfert_started;
   input [7:0] 	page_number;
   output 	n_opcode_addr_busy;
   
   reg [3:0] 	spi_cs;
   
//-----------------------------------------------------------------------------
// Parameters and constants   
//-----------------------------------------------------------------------------
// All flip-flops are modeled (in RTL) with a (cp->q) delay: tcQ.
// This is to prevent potential problems with gated clocks.

   parameter tcQ=1;


// registers and wire definistions.
   
   wire      start;    //edge detection on start signal
   wire      end_wait;   //wait counter has reached the muber of required ws.
   wire      spi_clk;    // spi clock generated for external device
   wire      spi_so;     // spi serial output to device
   wire      busy;       // spi core is tranfering data to/from spi device
   wire      end_bitcount;  //bit counter has reached its max value
   wire      load;          //load the new value in the shift register
   wire [1:0] field;        //indicates field to be sent serialy
   wire       clk_ena;      //alows activation of the spi clock
  
   wire       nrestart_bit;  //restart bit counter (active low)
   wire       nrestartwait;  //restart wait counter (active low)
   wire       pause_clk;     //pause spi clock for wait state or data missing purpose
   wire       spi_oen;
   wire [7:0] rxdata;   //serialy received data
   wire       spi_a;
   reg 	      spi_a_r;
   
   
   reg [23:0] data_to_send;
   reg [4:0]  nb_bit;
   reg 	      shift;
   reg 	      nwr_fifo_r;
   reg 	      fifo_full_r;
   reg 	      fifo_empty_r;
   wire       fifo_full_c;
   wire       fifo_empty_c;
   wire       stop_clk_c;
   wire       transfert_started;
   



   //logic to have the empty/full signals stay active for at least 1 cycle of functional
   //clock. This is needed because the fifo can be emptied/filled by both CPU
   //and spi_core. Thus if the empty fifo occur because of a core_read and the
   //CPU answer it fast enough then the spi_core will be foooled has it detected an
   //empty fifo and the fifo is not empty anymore.
   
   always @(posedge clk or negedge nreset)
     if(!nreset)
       begin
	 fifo_full_r<=0;
	 fifo_empty_r<=0;
       end // if (!nreset)
     else
       begin
	 fifo_full_r<=fifo_full;
	 fifo_empty_r<=fifo_empty;
       end // else: !if(!nreset)
   
   assign fifo_full_c  = fifo_full_r | fifo_full;
   assign fifo_empty_c = fifo_empty_r | fifo_empty;
   //-------------------------------------------------------------------------  
  

   spi_control State( .nreset(nreset),
		      .clk(clk),
		      
		      .operation(transfert_type),
		      //.start(start_c),
		      .start(start_control),
		      .end_bitcnt(end_bitcount),
		      .end_bytecnt(end_rxtx),
		      .end_waitcnt(end_wait),
		      .wait_en(wait_state_en),
		      .fifo_full(fifo_full_c),
		      .fifo_empty(fifo_empty_c),
		      .break(break),
		      
		      .load(load),
		      .busy(control_busy),
		      .ns_rst_bitcnt(nrestart_bit),
		      .ns_rst_bytecnt(nrestart_byte),
		      .ns_rst_waitcnt(nrestart_wait),
		      .stop_clk(stop_clk),
		      .nwr_spi_fifo(nwr_fifo),
		      .nrd_spi_fifo(nrd_fifo_ctrl),
		      .field(field),
		      .spi_oen(spi_oen),
		      .shift_ena(shift_ena_state),
		      .stop_clkgen(stop_clkgen),
		      .halt_clk(halt_clk_state)
		      );
   
   
   
   spi_page_cnt page_cnt (.clk(clk),       // Clock Input
			  .cdn(nreset),       // Clear Direct Not Input
			  .load(start),      // Load Control Input
			  .datain(page_number),    // Data Input
			  .cen(stop_clkgen),       // Count Enable Input
			  .q(),         //  8 bit Result
			  .tci(end_page_cnt));      // Terminal Count Indicator
   
   
   spi_tx_rx emiter_receiver
     (.nreset(nreset),              //asynchronous system reset 
      .clk(clk),                 //clock (only use rising edge)
      .nrestart_bitcnt(nrestart_bit), //synchronous reset for bit counter
      .field(field),//indicate what is to be send/received op/addr/data
      .opcode_length(opcode_length),       //number of valid bit in opcode field
      .opcode_field(opcode_field),        //opcode to send
      .address_length(address_length),      //number of valid bit in address field
      .addr_field(addr_field),       //address to be sent
      .data_field(data_field),          //data to be sent.
      .lcd_a(lcd_a),               //parralel value for spi_a pin
      .shift(shift),               //makes shift register shift
      .load(load),                //makes the shift register load parralell value
      .spi_si(spi_si),              //serial input
      .spi_so(spi_so),              //serial output 
      .end_transmit(end_bitcount),//active high when number_of bit have been sent
      .data_received(rxdata),        //serialy received data
      .nrestart_bytecnt(nrestart_byte),    //restart byte counter
      .number_of_byte(nb_data_byte),      //number of data byte to send/receive
      .end_data_txrx(end_rxtx),    //active high when number_of_byte have been tx/rx
      .spi_a(spi_a),               //indicate to lcd if data is control/raw data
      .n_opcode_addr_busy(n_opcode_addr_busy)   //                
      );
  


   spi_clock_gen ck_gen(.nreset(nreset),    //async system reset
			.clk(clk),      //system clock
			.start(start_c),     //start transmition signal 
			.spi_mode(spi_mode), //spi mode
			.stop_clk(stop_clk_c), //used to insert wait state or stop the clock
			.end_communication(stop_clkgen), //from main state machine when comm is over
			.spi_clk(spi_clk),   // spi clock to be sent to device only
			.base_cs(base_cs),    //Chip select used to generate all devices chip selects
			.halt_clk(halt_clk),  //  
			.fifo_empty(fifo_empty_c),
			.transfer_type(transfert_type),
			.time_ext(time_ext),
			.cs_gen_busy(cs_gen_busy), //block is busy cannot start a new transfer yet
			.cs_done(start_control)
			);
   
   assign start_c = start | (~(end_page_cnt|cs_gen_busy));
   assign stop_clk_c = stop_clk&((~spi_oen)|(~break));
   assign halt_clk = (halt_clk_state|(end_rxtx&(~spi_oen)&(transfert_type!=3'h2))); 
                                                              //in case of write operation (spi_oen=0)
                                                              //end_rxtx signal will ocur 1 clock cycle before
                                                              //the last active edge of spi_clk. Thus spi_clk
                                                              //must be switched off at that time.
                                                              //in case of read there is a need of a a 
                                                              // 1/2 clock cyle delay.
   
   spi_waitcounter wait_counter (
				 .clk(clk),       // Clock Input
				 .cdn(nreset),       // Clear Direct Not Input
				 .csn(nrestart_wait),
				 .maxval({wait_numb,1'b0}),    // Programmable Maximum Count Value
				 .q(),         //  3 bit Result
				 .tci(end_wait));      // Terminal Count Indicator
   


     

      

// combinational logic used to make the shift register shift or
// memorise the information 
// as spi_mode 1 and 2 are rising edge active the 
// shift register must shift data on the low level of 
// spi_clk (this will occur on falling edge of spi_clk)
// the oposite is valid for mode 0 and 3.
// In case of pause signal due to wait state or due
// no data available in fifo for spi write or no room available
// for spi read, spi_clk is stoped on a different level of spi_clk
// thus pause_signal is used to deactivate shit operation.
   
   always @(spi_clk or shift_ena_state or spi_mode or spi_oen)
     if(~shift_ena_state)
       shift=0;
     else
       if((spi_mode==2'h1) | (spi_mode==2'h2))
	 shift = spi_oen ~^ spi_clk;
       else
	 shift = spi_oen ^ spi_clk;
   
        
   

//generate the 4 chip selects for the devices using the base_cs information genrated by
//the clock_gen block. The Cs genrated have a programable polarity and are activated
// by the software. There is no priority encoding among them therefore it is possible
// for the user to activate one or more CS at the same time. Thus broadcast is
//possible
//note ^ is xor operation

   always @(activate_cs or base_cs or inactive_cs_state)
     begin
       spi_cs=inactive_cs_state;
       case (activate_cs)
	2'b00 : spi_cs[0]=base_cs^inactive_cs_state[0];
	2'b01 : spi_cs[1]=base_cs^inactive_cs_state[1];
	2'b10 : spi_cs[2]=base_cs^inactive_cs_state[2];
	2'b11 : spi_cs[3]=base_cs^inactive_cs_state[3];
       endcase // case(activate_cs)
     end // always @ (activate_cs or base_cs or inactive_cs_state)


   //delay by 1 clock cycle the write to fifo signal to let enough time to the last
   //bit to be shifted in.
   always @(posedge clk or negedge nreset)
     if(!nreset)
       nwr_fifo_r<=1;
     else
       nwr_fifo_r<=nwr_fifo;
   
   //mask the last read from fifo due to core
   //this read is due to the fact the detection of end of communication
   //is made in control state machine at the same time
   //the data are read from fifo.
   //This extra read would not matter in case of single page transmition
   //but would screw up the fifo in case of multiple page transmission.
  
   assign nrd_fifo = nrd_fifo_ctrl | end_rxtx;

   //note that the busy signal below will be used to detect end of communication
   //and signal it to the CPU.
   assign busy=control_busy | cs_gen_busy | start | (~end_page_cnt);

   //handshake to tell the transger is started.
   //this signal is used to reset the start signal in spi_int register.
   //It is required for 2 reasons :
   //- 2 different clock domain
   //- in case of write only operation it is not possible
   //      to start an operation with an empty fifo.
   //      Thus control state machine wait for start and fifo not empty to
   //      actualy start.
  // assign transfert_started = control_busy;
    assign transfert_started = cs_gen_busy;
   
endmodule // spi_core

/*
 spi_core(
		.clk(),             //clock 
		.nreset(),          //async system reset
		.wait_state_en(),   //enable usage of wait states
		.spi_si(),          //spi serial output
		.spi_mode(),        //spi mode (0, 1, 2, 3)
		.opcode_length(),   //size of opcode to be transmitted
		.address_length(),  //size of address to be sent
		.wait_numb(),       //number of wait states to be inserted
		.opcode_field(),    //opcode to send
		.addr_field(),      //adress to send
		.data_field(),      //data to send
		.start(),           //initiate transfert
		.transfert_type(),  //read/write, opcode+read/write ....
                .break(),           //in case of fifo full/empty stop transmission completely
		.lcd_a(),           //bit value to be sent with opcode+address and data field

		.spi_clk(),         //spi clock to be sent to device
		.spi_so(),          //spi serial output
		.busy(),             //indicates a tranfer is ongoing
		.fifo_empty(),      //fifo is empty 
		.fifo_full(),       //fifo is full
		.nwr_fifo_r(),        //write to fifo
		.nrd_fifo(),        //read from fifo
		.nb_data_byte(),   //number of data byte to send, receive
		.activate_cs(),     //designate the device that will be addressed
		.inactive_cs_state(),//activity level of the cs
		.spi_cs(),           //spi chip select to devices
		.spi_oen(),           //spi output enable active low
                .rxdata(),            //serialy received data
		.spi_a_r()             //serial address for LCD 
		);        
 *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -