/***********************************************************************************************
* SPI MASTER
* January 2007
************************************************************************************************/
`timescale 10ns/1ns
module SPI_Master ( miso, mosi, sclk, ss, data_bus, CS, addr, pro_clk, WR, RD);
inout [7:0] data_bus; // 8 bit bidirectional data bus
input pro_clk; // Host Processor clock
input miso; // Master in slave out
input [1:0] addr; // A1 and A0, lower bits of address bus
input CS; // Chip Select
input WR, RD; // Write and read enables
output mosi; // Master out slave in
output sclk; // SPI clock
output [7:0] ss; // 8 slave select lines
reg [7:0] shift_register; // Shift register
reg [7:0] txdata; // Transmit buffer
reg [7:0] rxdata; // Receive buffer
reg [7:0] data_out; // Data output register
reg [7:0] data_out_en; // Data output enable
reg [7:0] control, status; // Control Register COntrols things like ss, CPOL, CPHA, clock divider
// Status Register is a dummy register never used.
reg [7:0] clk_divide; // Clock divide counter
reg [3:0] count; // SPI word length counter
reg sclk;
reg slave_cs; // Slave cs flag
reg mosi; // Master out slave in
reg spi_word_send; // Will send a new spi word.
wire [7:0] data_bus;
wire [7:0] data_in = data_bus;
wire spi_clk_gen;
wire [2:0] divide_factor = control[2:0];
wire CPOL = control[3];
wire CPHA = control[4];
wire [7:0]ss;
/* Slave Select lines */
assign ss[7] = ~( control[7] & control[6] & control[5] & (~slave_cs));
assign ss[6] = ~( control[7] & control[6] & ~control[5] & (~slave_cs));
assign ss[5] = ~( control[7] & ~control[6] & control[5] & (~slave_cs));
assign ss[4] = ~( control[7] & ~control[6] & ~control[5] & (~slave_cs));
assign ss[3] = ~(~control[7] & control[6] & control[5] & (~slave_cs));
assign ss[2] = ~(~control[7] & control[6] & ~control[5] & (~slave_cs));
assign ss[1] = ~(~control[7] & ~control[6] & control[5] & (~slave_cs));
assign ss[0] = ~(~control[7] & ~control[6] & ~control[5] & (~slave_cs));
/* clock divide */
assign spi_clk_gen = clk_divide[divide_factor];
/* Clock Divider */
always @ (negedge pro_clk) begin
clk_divide = clk_divide + 1;
end
/* Reading the miso line and shifting */
always @ (posedge (sclk ^ (CPHA ^ CPOL)) or posedge spi_word_send) begin
if (spi_word_send) begin
shift_register[7:0] = txdata;
end else begin
shift_register = shift_register << 1;
shift_register[0] <= miso;
end
end
/* Writing the mosi */
always @ (negedge (sclk ^ (CPHA ^ CPOL)) or posedge spi_word_send) begin
if (spi_word_send) begin
mosi = txdata[7];
end else begin
mosi = shift_register[7];
end
end
/* Contolling the interrupt bit in the status bit */
always @ (posedge slave_cs or posedge spi_word_send) begin
if (spi_word_send) begin
status[0] = 0;
end else begin
status = 8'h01;
rxdata = shift_register; // updating read buffer
end
end
/* New SPI wrod starts when the transmit buffer is updated */
always @ (posedge pro_clk) begin
if (spi_word_send) begin
slave_cs <= 0;
end else if ((count == 8) & ~(sclk ^ CPOL)) begin
slave_cs <= 1;
end
end
/* New Spi word is intiated when transmit buffer is updated */
always @ (posedge pro_clk) begin
if (CS & WR & addr[1] & ~addr[0]) begin
spi_word_send <=1;
end else begin
spi_word_send <=0;
end
end
/* Generating the SPI clock */
always @ (posedge spi_clk_gen) begin
if (~slave_cs) begin
sclk = ~sclk;
end else if (~CPOL) begin
sclk = 0;
end else begin
sclk = 1;
end
end
/* Counting SPI word length */
always @ (posedge sclk or posedge slave_cs) begin
if (slave_cs) begin
count = 0;
end else begin
count = count + 1;
end
end
/* Reading, writing SPI registers */
always @ (posedge pro_clk) begin
if (CS) begin
case (addr)
2'b00 : if (WR) control <= data_in;
2'b01 : if (RD) data_out <= status; // Void
2'b10 : if (WR) txdata <= data_in;
2'b11 : if (RD) data_out <= rxdata;
endcase
end
end
/* Controlling the data out enable */
always @ (RD or data_out) begin
if (RD)
data_out_en = data_out;
else
data_out_en = 8'bz;
end
assign data_bus = data_out_en;
initial
begin
mosi = 0;
//sclk = 0;
control = 0;
count = 0;
slave_cs = 1;
txdata = 0;
rxdata = 0;
clk_divide = 0;
data_out = 0;
end
endmodule
/********************************************** END ******************************************************************/
/******************************************************************************************
* Test Bench for SPI Master
* January 2007
*******************************************************************************************/
`timescale 10ns/1ns
module SPI_master_test;
wire [7:0] data_bus; // Bidirectional
wire mosi; // Output from main module
wire sclk; // Output from main module
wire [7:0] ss; // Output from main module
/* Inputs to main module */
reg miso;
reg CS;
reg [1:0] addr;
reg pro_clk;
reg WR,RD;
SPI_Master tb ( miso, mosi, sclk, ss, data_bus, CS, addr, pro_clk, WR, RD);
/* Internal registers defined for TB */
reg [7:0] data_send;
reg [7:0] transmit_store;
reg [7:0] data_receive;
reg [7:0] miso_data;
reg [7:0] mosi_data;
assign data_bus = data_send;
initial // Generates serial clock of time period 10
begin
pro_clk = 0;
forever #5 pro_clk = !pro_clk;
end
initial
begin
CS = 0;
RD = 0;
WR = 0;
data_send = 0;
addr = 0;
miso = 0;
#20
/* Updating Control register */
@ (negedge pro_clk)
CS = 1;
WR = 1;
data_send = 0;
addr = 0;
/* Updating Transmit buffer */
@ (negedge pro_clk)
CS = 1;
WR = 1;
data_send = $random;
addr = 2'b10;
#1 transmit_store = data_send;
@ (negedge pro_clk)
$display ("Transmit Buffer loaded");
$display ("SS[0] = 0, CPHA = 0, CPOL = 0 at time:",$time);
$display ("Observe Waveform for spi clock frequency, spi data changing at falling egde, valid at rising edge");
CS = 0;
WR = 0;
data_send = 8'bz;
@ (posedge ss[0])
#20
/* Checking Status */
@ (negedge pro_clk)
CS = 1;
RD = 1;
addr = 2'b01;
@ (negedge pro_clk)
data_receive = data_bus;
@ (negedge pro_clk)
if (data_receive[0]) begin
$display("Interrupt detected at time:", $time);
addr = 2'b11;
end else begin
$display("Interrupt detect failed at time:", $time);
end
@ (negedge pro_clk)
data_receive = data_bus;
if (data_bus == miso_data) begin
$display("Data received from spi slave verified", $time);
end else begin
$display("Data receive failed",$time);
end
/* Writing new control word */
@ (negedge pro_clk)
CS = 1;
WR = 1;
RD = 0;
data_send = 8'b10001001;
addr = 0;
@ (negedge pro_clk)
CS = 1;
WR = 1;
data_send = $random;
addr = 2'b10;
#1 transmit_store = data_send;
@ (negedge pro_clk)
$display ("\n Transmit Buffer reloaded");
$display ("Observe Waveform for spi clock frequency, spi data changing at rising edge and valid at falling edge");
$display ("SS[4] = 0, CPHA = 0, CPOL = 1 at time:",$time);
CS = 0;
RD = 0;
WR = 0;
data_send = 8'bz;
@ (posedge ss[4])
#20
/* Checking Status */
@ (negedge pro_clk)
CS = 1;
RD = 1;
addr = 2'b01;
@ (negedge pro_clk)
data_receive = data_bus;
@ (negedge pro_clk)
if (data_receive[0]) begin
$display("Interrupt detected at time:", $time);
addr = 2'b11;
end else begin
$display("Interrupt detect failed at time:", $time);
end
@ (negedge pro_clk)
data_receive = data_bus;
if (data_bus == miso_data) begin
$display("Data received from spi slave verified", $time);
end else begin
$display("Data receive failed",$time);
end
/* Writing new control word */
@ (negedge pro_clk)
CS = 1;
WR = 1;
RD = 0;
data_send = 8'b11110010;
addr = 0;
@ (negedge pro_clk)
CS = 1;
WR = 1;
data_send = $random;
addr = 2'b10;
#1 transmit_store = data_send;
@ (negedge pro_clk)
$display ("\n Transmit Buffer reloaded");
$display ("Observe Waveform for spi clock frequency, spi data changing at rising edge and valid at falling edge");
$display ("SS[7] = 0, CPHA = 1, CPOL = 0 at time:",$time);
CS = 0;
RD = 0;
WR = 0;
data_send = 8'bz;
@ (posedge ss[7])
#20
/* Checking Status */
@ (negedge pro_clk)
CS = 1;
RD = 1;
addr = 2'b01;
@ (negedge pro_clk)
data_receive = data_bus;
@ (negedge pro_clk)
if (data_receive[0]) begin
$display("interrupt detected at time:", $time);
addr = 2'b11;
end else begin
$display("interrupt detect failed at time:", $time);
end
@ (negedge pro_clk)
data_receive = data_bus;
if (data_bus == miso_data) begin
$display("Data received from spi slave verified", $time);
end else begin
$display("Data receive failed",$time);
end
/* Writing new control word */
@ (negedge pro_clk)
CS = 1;
WR = 1;
RD = 0;
data_send = 8'b01111100;
addr = 0;
@ (negedge pro_clk)
CS = 1;
WR = 1;
data_send = $random;
addr = 2'b10;
#1 transmit_store = data_send;
@ (negedge pro_clk)
$display ("\n Transmit Buffer reloaded");
$display ("Observe Waveform for spi clock frequency, spi data changing at falling edge and valid at rising edge");
$display ("SS[3] = 0, CPHA = 1, CPOL = 1 at time:",$time);
CS = 0;
RD = 0;
WR = 0;
data_send = 8'bz;
@ (posedge ss[3])
#20
/* Checking Status */
@ (negedge pro_clk)
CS = 1;
RD = 1;
addr = 2'b01;
@ (negedge pro_clk)
data_receive = data_bus;
@ (negedge pro_clk)
if (data_receive[0]) begin
$display("Interrupt detected at time:", $time);
addr = 2'b11;
end else begin
$display("Interrupt detect failed at time:", $time);
end
@ (negedge pro_clk)
data_receive = data_bus;
if (data_bus == miso_data) begin
$display("Data received from spi slave verified", $time);
end else begin
$display("Data receive failed",$time);
end
@ (negedge pro_clk)
$display ("\n PASS: hit break to stop simulation");
end
initial
begin
/* Writing MISO / Reading MOSI for random values */
#20
miso_data = $random;
@ (negedge ss[0])
miso = miso_data[7];
@ (posedge sclk)
mosi_data[7] = mosi;
@ (negedge sclk)
miso = miso_data[6];
@ (posedge sclk)
mosi_data[6] = mosi;
@ (negedge sclk)
miso = miso_data[5];
@ (posedge sclk)
mosi_data[5] = mosi;
@ (negedge sclk)
miso = miso_data[4];
@ (posedge sclk)
mosi_data[4] = mosi;
@ (negedge sclk)
miso = miso_data[3];
@ (posedge sclk)
mosi_data[3] = mosi;
@ (negedge sclk)
miso = miso_data[2];
@ (posedge sclk)
mosi_data[2] = mosi;
@ (negedge sclk)
miso = miso_data[1];
@ (posedge sclk)
mosi_data[1] = mosi;
@ (negedge sclk)
miso = miso_data[0];
@ (posedge sclk)
mosi_data[0] = mosi;
#5
if(mosi_data == transmit_store) begin
$display("Data transmitted to spi slave verified", $time );
end else begin
$display("Data Transmit to spi slave failed !", $time );
end
/* Next set : CPOL = 1, CPHA = 0 */
@ (negedge ss[4])
miso_data = $random;
miso = miso_data[7];
@ (negedge sclk)
mosi_data[7] = mosi;
@ (posedge sclk)
miso = miso_data[6];
@ (negedge sclk)
mosi_data[6] = mosi;
@ (posedge sclk)
miso = miso_data[5];
@ (negedge sclk)
mosi_data[5] = mosi;
@ (posedge sclk)
miso = miso_data[4];
@ (negedge sclk)
mosi_data[4] = mosi;
@ (posedge sclk)
miso = miso_data[3];
@ (negedge sclk)
mosi_data[3] = mosi;
@ (posedge sclk)
miso = miso_data[2];
@ (negedge sclk)
mosi_data[2] = mosi;
@ (posedge sclk)
miso = miso_data[1];
@ (negedge sclk)
mosi_data[1] = mosi;
@ (posedge sclk)
miso = miso_data[0];
@ (negedge sclk)
mosi_data[0] = mosi;
#5
if(mosi_data == transmit_store) begin
$display("Data transmitted to spi slave verified", $time );
end else begin
$display("Data Transmit to spi slave failed !", $time );
end
/* Next set : CPOL = 0, CPHA = 1 */
@ (negedge ss[7])
miso_data = $random;
@ (posedge sclk)
miso = miso_data[7];
@ (negedge sclk)
mosi_data[7] = mosi;
@ (posedge sclk)
miso = miso_data[6];
@ (negedge sclk)
mosi_data[6] = mosi;
@ (posedge sclk)
miso = miso_data[5];
@ (negedge sclk)
mosi_data[5] = mosi;
@ (posedge sclk)
miso = miso_data[4];
@ (negedge sclk)
mosi_data[4] = mosi;
@ (posedge sclk)
miso = miso_data[3];
@ (negedge sclk)
mosi_data[3] = mosi;
@ (posedge sclk)
miso = miso_data[2];
@ (negedge sclk)
mosi_data[2] = mosi;
@ (posedge sclk)
miso = miso_data[1];
@ (negedge sclk)
mosi_data[1] = mosi;
@ (posedge sclk)
miso = miso_data[0];
@ (negedge sclk)
mosi_data[0] = mosi;
#5
if(mosi_data == transmit_store) begin
$display("Data transmitted to spi slave verified", $time );
end else begin
$display("Data Transmit to spi slave failed !", $time );
end
/* Next set : CPOL = 1, CPHA = 1 */
@ (negedge ss[3])
miso_data = $random;
@ (negedge sclk)
miso = miso_data[7];
@ (posedge sclk)
mosi_data[7] = mosi;
@ (negedge sclk)
miso = miso_data[6];
@ (posedge sclk)
mosi_data[6] = mosi;
@ (negedge sclk)
miso = miso_data[5];
@ (posedge sclk)
mosi_data[5] = mosi;
@ (negedge sclk)
miso = miso_data[4];
@ (posedge sclk)
mosi_data[4] = mosi;
@ (negedge sclk)
miso = miso_data[3];
@ (posedge sclk)
mosi_data[3] = mosi;
@ (negedge sclk)
miso = miso_data[2];
@ (posedge sclk)
mosi_data[2] = mosi;
@ (negedge sclk)
miso = miso_data[1];
@ (posedge sclk)
mosi_data[1] = mosi;
@ (negedge sclk)
miso = miso_data[0];
@ (posedge sclk)
mosi_data[0] = mosi;
#5
if(mosi_data == transmit_store) begin
$display("Data transmitted to spi slave verified", $time );
end else begin
$display("Data Transmit to spi slave failed !", $time );
end
end
endmodule
/*************************************** END OF TB ***********************************************************************/
本文引自: http://www.cnblogs.com/shangdawei/archive/2012/05/16/2503511.html
阅读(6209) | 评论(1) | 转发(0) |