zoukankan      html  css  js  c++  java
  • SPI协议

    协议简介

    https://www.cnblogs.com/liujinggang/p/9609739.html
    https://www.cnblogs.com/deng-tao/p/6004280.html
    https://blog.csdn.net/weiqifa0/article/details/82765892

    Verilog代码

    SPI总线协议是一种全双工的串行通信协议,数据传输时高位在前,低位在后。SPI协议规定一个SPI设备不能在数据通信过程中仅仅充当一个发送者(Transmitter)或者接受者(Receiver)。在片选信号CS为0的情况下,每个clock周期内,SPI设备都会发送并接收1 bit数据,相当于有1 bit数据被交换了。数据传输高位在前,低位在后(MSB first)。SPI主从结构内部数据传输示意图如下图所示

    用三段式状态机实现

    代码

    `timescale 1ns / 1ps
    module spi_master2(
    	input clk,
    	input rstn,
    	input en,   
    	
    	input [7:0] tx_data,  // 要发送给slave的数据
    	output reg [7:0] rx_data, // 从slave接收的数据
    	output trans_done,    // 发送完成信号
    	output rec_done,     // 接收完成信号
    	
    	// spi interface
    	input miso,
    	output reg sclk,
    	output mosi,
    	output cs
        );
    	
    reg [1:0] spi_state;
    reg [1:0] spi_state_next;
    
    reg [2:0] spi_count;
    
    localparam [1:0] IDLE = 2'd0,TRANS = 2'd1,FINISH = 2'd2;
    
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) spi_state <= IDLE;
    	else spi_state <= spi_state_next;
    end
    
    always @(*) begin
    	case(spi_state)
    		IDLE:
    			begin
    				if(en) spi_state_next <= TRANS;
    				else spi_state_next <= IDLE;
    			end
    		TRANS:
    			begin
    				if(spi_count == 3'd0 && sclk) spi_state_next <= FINISH; // 跟sclk相与是为了spi_count==0持续1个sclk周期
    				else spi_state_next <= TRANS;
    			end
    		FINISH:
    			begin
    				spi_state_next <= IDLE;
    			end
    		default: spi_state_next <= IDLE;
    	endcase
    end
    
    // sclk 为系统时钟的二分频时钟
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) sclk <= 1'b0;
    	else begin
    		if(spi_state==TRANS) sclk <= ~sclk;
    		else sclk <= 1'b0;
    	end
    end
    
    // spi_count
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) spi_count <= 3'd7;
    	else begin
    		if(spi_state==FINISH) spi_count <= 3'd7;
    		else if(spi_state==TRANS && sclk) spi_count <= spi_count - 1'b1;
    		else spi_count <= spi_count;
    	end
    end
    
    // 接收数据
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) rx_data <= 8'd0;
    	else begin
    		if(spi_state==TRANS && (~sclk)) rx_data[spi_count] <= miso;
    		else rx_data <= rx_data;
    	end
    end
    
    // 发送数据
    assign mosi = (spi_state == TRANS)? tx_data[spi_count] : 1'bz;  // 设为z态方便调试
    
    
    assign trans_done = (spi_state == FINISH)? 1'b1 : 1'b0;
    assign rec_done  = trans_done;
    assign cs = (spi_state == TRANS)? 1'b1 : 1'b0;
    
    endmodule
    

    测试激励

    `timescale 1ns / 1ps
    
    module spi_master2_tb;
    
    	// Inputs
    	reg clk;
    	reg rstn;
    	reg en;
    	reg [7:0] tx_data;
    	wire miso;
    
    	// Outputs
    	wire [7:0] rx_data;
    	wire trans_done;
    	wire rec_done;
    	wire sclk;
    	wire mosi;
    	wire cs;
    
    	// Instantiate the Unit Under Test (UUT)
    	spi_master2 uut (
    		.clk(clk), 
    		.rstn(rstn), 
    		.en(en), 
    		.tx_data(tx_data), 
    		.rx_data(rx_data), 
    		.trans_done(trans_done), 
    		.rec_done(rec_done), 
    		.miso(miso), 
    		.sclk(sclk), 
    		.mosi(mosi), 
    		.cs(cs)
    	);
    
    	initial begin
    		// Initialize Inputs
    		clk = 0;
    		rstn = 0;
    		en = 0;
    		tx_data = 0;
    		//miso = 0;
    
    		// Wait 100 ns for global reset to finish
    		#100;
    		@(negedge clk);
    		rstn = 1;
    		@(negedge clk);
    		en = 1;
    		tx_data = 8'b1010_1010;
    		
    		@(negedge trans_done);
    		//miso = 1;
    		tx_data = 8'b0101_0101;
    		@(negedge trans_done);
    		en = 0;
    		
            
    		// Add stimulus here
    
    	end
    	
    	assign miso = mosi;
    	
    	always #20 clk = ~clk;
          
    endmodule
    

    测试波形

    用计数实现

    代码

    `timescale 1ns / 1ps
    module spi_master(
    	input clk,
    	input rstn,
    	input en,  
    	
    	input [7:0] tx_data,  // 要发送给slave的数据
    	output reg [7:0] rx_data, // 从slave接收的数据
    	output reg trans_done,    // 发送完成信号
    	output reg rec_done,     // 接收完成信号
    	
    	// spi interface
    	input miso,
    	output reg sclk,
    	output reg mosi,
    	output reg cs
        );
    	
    reg [3:0] spi_state;
    	
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) begin
    		spi_state <= 4'd0;
    		cs <= 1'b1;
    		mosi <= 1'b0;
    		trans_done <= 1'b0;
    		sclk <= 1'b0;
    		rx_data <= 8'd0;
    		rec_done <= 1'b0;
    	end
    	else begin
    	if(en) begin
    		spi_state <= spi_state + 1'b1;
    		cs <= 1'b0;
    		case(spi_state)
    			4'd0: 
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[7];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd1:
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[7] <= miso;
    					rec_done <= 1'b0;
    				end
    			4'd2:
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[6];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd3: 
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[6] <= miso;
    					rec_done <= 1'b0;
    				end
    			4'd4:
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[5];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd5:
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[5] <= miso;
    					rec_done <= 1'b0;
    				end				
    			4'd6:
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[4];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd7:
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[4] <= miso;
    					rec_done <= 1'b0;
    				end				
    			4'd8: 
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[3];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd9:
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[3] <= miso;
    					rec_done <= 1'b0;
    				end
    			4'd10:
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[2];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd11: 
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[2] <= miso;
    					rec_done <= 1'b0;
    				end
    			4'd12:
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[1];
    					trans_done <= 1'b0;
    					rec_done <= 1'b0;
    				end
    			4'd13:
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[1] <= miso;
    					rec_done <= 1'b0;
    				end				
    			4'd14:
    				begin
    					sclk <= 1'b0;
    					mosi <= tx_data[0];
    					trans_done <= 1'b1;
    					rec_done <= 1'b0;
    				end
    			4'd15:
    				begin
    					sclk <= 1'b1;
    					mosi <= mosi;
    					trans_done <= 1'b0;
    					rx_data[0] <= miso;
    					rec_done <= 1'b1;
    				end				
    		endcase
    	end
    	else begin
    		spi_state <= 4'd0;
    		cs <= 1'b1;
    		mosi <= 1'b0;
    		trans_done <= 1'b0;
    		sclk <= 1'b0;
    		rx_data <= 8'd0;
    		rec_done <= 1'b0;
    	end
    end
    	
    end
    
    endmodule
    
    

    测试激励

    `timescale 1ns / 1ps
    
    module spi_master_tb;
    
    	// Inputs
    	reg clk;
    	reg rstn;
    	reg en;
    	reg [7:0] tx_data;
    	wire miso;
    
    	// Outputs
    	wire [7:0] rx_data;
    	wire trans_done;
    	wire rec_done;
    	wire sclk;
    	wire mosi;
    	wire cs;
    
    	// Instantiate the Unit Under Test (UUT)
    	spi_master uut (
    		.clk(clk), 
    		.rstn(rstn), 
    		.en(en), 
    		.tx_data(tx_data), 
    		.rx_data(rx_data), 
    		.trans_done(trans_done), 
    		.rec_done(rec_done),
    		.miso(miso), 
    		.sclk(sclk), 
    		.mosi(mosi), 
    		.cs(cs)
    	);
    
    	initial begin
    		// Initialize Inputs
    		clk = 0;
    		rstn = 0;
    		en = 0;
    		tx_data = 0;
    		//miso = 0;
    
    		// Wait 100 ns for global reset to finish
    		#100;
    		@(negedge clk);
    		rstn = 1;
    		@(negedge clk);
    		en = 1;
    		tx_data = 8'b1010_1010;
    		
    		@(negedge trans_done);
    		//miso = 1;
    		tx_data = 8'b0101_0101;
    		@(negedge trans_done);
    		en = 0;
    		
            
    		// Add stimulus here
    
    	end
    	
    	assign miso = mosi;
    	
    	always #20 clk = ~clk;
          
    endmodule
    
    

    波形

  • 相关阅读:
    LCS 最长公共子序列
    零和数组
    Learn2Rank
    ac自动机
    208. Implement Trie (Prefix Tree)
    php截取中文字符串 GB2312 utf-8
    纵向文字滚动代码,带上下图片控制的。鼠标放到上下图片上时滚动
    js图片切换 带左右控制的
    实时显示输入的内容
    Lightbox JS v2.0图片切换效果
  • 原文地址:https://www.cnblogs.com/wt-seu/p/12720275.html
Copyright © 2011-2022 走看看