Chinaunix首页 | 论坛 | 博客
  • 博客访问: 204869
  • 博文数量: 45
  • 博客积分: 945
  • 博客等级: 准尉
  • 技术积分: 360
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-19 10:36
文章分类

全部博文(45)

文章存档

2016年(1)

2015年(1)

2014年(2)

2013年(4)

2012年(8)

2011年(29)

我的朋友

分类: Verilog

2013-06-05 15:45:27

/***********************************************************************************************
 * 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) |
0

上一篇:后仿时序检查出错

下一篇:matlab矩阵操作

给主人留下些什么吧!~~

风铃草lw2016-03-10 09:53:37

怎么读数据是上升沿,  写数据又是下降沿   读写怎么不是在同一段的。那不管用哪个SPI模式 读或者写 总有一个是在数据不稳定区执行的,我完全不能理解