📄 spi_core.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 + -