SPI主機實現

SPI主機實現

一、硬件層

(1)外部引線

SPI通信的最小結構爲一主一從結構,主機向從機提供信號發送接收時鐘SCLK。主機與從機之間存有四根引線,即MOSI(主收從發)、MISO(主發從收)、SCK(通信時鐘)、CS(從機片選信號)。其中,通過在主機上增加片選信號輸出端的數目,或引入編碼,譯碼結構可以使得主機控制更多的從機,實現一主多從的SPI通信。本設計中默認爲一主一從最小結構。

(2)四種工作模式

SPI通信協議規定了4鍾工作模式,在實際應用中應當保證主機和從機工作在相同的工作模式下。SPI工作模式通過時鐘極性CPOL和時鐘相位CPHA聯合指定。其中CPOL指定SCK在空閒狀態時的電平,CPHA指定在SCK的何種邊緣進行數據採樣。其標識如下:
在這裏插入圖片描述
在這裏插入圖片描述

二、FPGA代碼實現

(1)思路

SPI模式0主機控制器在SCK上升沿時對數據進行採樣。由於在時鐘上升沿進行數據採樣,那麼,接收/發送狀態機的狀態應當早於SCK時鐘上升沿提前準備好接收/發送狀態,也就是說在低電平期間就需要準備好

對於發送狀態機,由於數據在SCK時鐘的下降沿進行狀態變換,又因爲從機在上升沿採樣,因此選擇在SCK的低電平中心將需發送的數據壓至MOSI線上。

對於接收狀態機,同樣採用SCK下降沿進行狀態跳變。接收狀態機在SCK上升沿時將數據採集至接收緩衝口,並在採集完一字節數據後生成信號標誌脈衝。

對於SPI主機控制器,另一個重要的模塊是控制模塊,它是用來生成SCK時鐘與CS片選信號的模塊。由於本文設計只有一個從機,因此只單純的控制CS的電平。SCK時鐘的生成也是依靠狀態機,其機理爲當狀態機處於IDLE空閒狀態時,檢測到讀/寫請求,在時鐘相位變爲下降沿時進入工作狀態,並輸出8個完整的SCK時鐘。此後,狀態機轉入STOP狀態,並在一個週期內檢測是否有新的請求信號到來,若無抵達空閒狀態,若有,轉入工作狀態。

(2)代碼實現

宏定義文件

//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2020/01/13 20:01:50
// Design Name: spi_master
// Module Name: global_define
// Project Name: SPI2
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`define SCK_PEDG (phase==9'd499)//默認使用100KHZ的頻率,50M/100k = 500
`define SCK_HIGH (phase==9'd124)
`define SCK_NEDG (phase==9'd249)
`define SCK_LOW  (phase==9'd374)

控制模塊

`include "global_definition.v"
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2020/01/13 20:01:50
// Design Name: spi_master
// Module Name: control_module
// Project Name: SPI2
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module control_module(
	input 				clk,
	input 				rst,
	output reg 			sck,
	output reg 			cs_n,
	output reg[8:0] 	phase,
	input 				wr_req,
	input 				rd_req,
	output reg[3:0] 	cnt//位數計數器
);
	reg[1:0] state;
	reg[1:0] next_state;
	
	localparam IDLE=2'b00;
	localparam WORK=2'b01;
	localparam STOP=2'b11;
	
	always@(posedge clk or negedge rst)begin
		if(!rst)
			phase <= 9'd0;
		else
			if(phase==9'd499)
				phase <= 9'd0;
			else
				phase <= phase + 1'b1;
	end
	
	//狀態機狀態轉移邏輯
	always@(posedge clk or negedge rst)begin
		if(!rst)
			state <= IDLE;
		else
			if(`SCK_NEDG)
				state <= next_state;
			else
				state <= state;
	end
	
	//狀態組合判斷
	always@(wr_req or rd_req or cnt)begin
		case(state)
			IDLE:
				if(wr_req||rd_req)
					next_state <= WORK;
				else
					next_state <= IDLE;
			WORK:
				if(cnt==4'd8)
					next_state <= STOP;
				else
					next_state <= WORK;
			STOP:
				if(wr_req||rd_req)
					next_state <= WORK;
				else
					next_state <= IDLE;
			default:
				next_state <= IDLE;
		endcase
	end
	
	//狀態機輸出
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			sck <= 1'b0;
			cs_n <= 1'b1;
			cnt <= 4'd0;
		end
		else begin
			case(state)
				IDLE:begin
					sck <= 1'b0;
					cs_n <= 1'b1;
					cnt <= 4'd0;
				end
				WORK:begin
					cs_n <= 1'b0;
					if(`SCK_PEDG)begin
						sck <= 1'b1;
						cnt <= cnt + 1'b1;
					end
					else if(`SCK_NEDG)
						sck <= 1'b0;
					else
						sck <= sck;
				end
				STOP:begin
					cnt <= 4'd0;
					sck <= 1'b0;
					cs_n <= 1'b1;
				end
				default:begin
					cnt <= cnt;
					sck <= sck;
					cs_n <= cs_n;
				end
			endcase
		end
	end

endmodule

發送模塊

`include "global_definition.v"
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2020/01/13 20:01:50
// Design Name: spi_master
// Module Name: spi_tx
// Project Name: SPI2
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module spi_tx(
	input 			clk,
	input 			rst,
	input 			wr_req,
	input [7:0]		data_wr,
	input [8:0]		phase,
	output reg 		wr,
	output reg 		mosi,
	input [3:0]		cnt
);
	reg[1:0] state;
	reg[1:0] next_state;
	localparam IDLE=2'b00;
	localparam WORK=2'b01;
	localparam STOP=2'b11;
	
	//狀態機狀態轉移
	always@(posedge clk or negedge rst)begin
		if(!rst)
			state <= IDLE;
		else
			state <= next_state;
	end
	
	//狀態組合判定
	always@(wr_req or cnt)begin
		case(state)
			IDLE:
				if(wr_req)
					next_state <= WORK;
				else
					next_state <= IDLE;
			WORK:
				if(cnt==4'd8)
					next_state <= STOP;
				else
					next_state <= WORK;
			STOP:
				if(wr_req)
					next_state <= WORK;
				else
					next_state <= IDLE;
			default:
				next_state <= next_state;
		endcase
	end
	
	//狀態機輸出
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			mosi <= 1'b0;
			wr <= 1'b1;
		end
		else begin
			case(state)
				IDLE:begin
					mosi <= 1'b0;
					wr <= 1'b1;
				end
				WORK:begin
					wr <= 1'b0;
					//由於上升沿採樣,所以在上升沿到來前把數據給到MOSI
					if(`SCK_LOW)begin
						case(cnt)
							4'd0:mosi <= data_wr[7];
							4'd1:mosi <= data_wr[6];
							4'd2:mosi <= data_wr[5];
							4'd3:mosi <= data_wr[4];
							4'd4:mosi <= data_wr[3];
							4'd5:mosi <= data_wr[2];
							4'd6:mosi <= data_wr[1];
							4'd7:mosi <= data_wr[0];
							default:mosi <= 1'b0;
						endcase
					end
				end
				STOP:begin
					wr <= 1'b1;
					mosi <= 1'b0;
				end
				default:begin
					wr <= wr;
					mosi <= mosi;
				end
			endcase
		end
	end

endmodule

接收模塊

`include "global_definition.v"
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2020/01/13 20:01:50
// Design Name: spi_master
// Module Name: spi_rx
// Project Name: SPI2
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module spi_rx(
	input 				clk,
	input 				rst,
	input 				rd_req,
	output reg[7:0] 	data_rd,
	input[8:0] 			phase,
	output reg 			rd,
	input 				miso,
	input[3:0] 			cnt
);

	reg[1:0] state;
	reg[1:0] next_state;
	localparam IDLE=2'b00;
	localparam WORK=2'b01;
	localparam STOP=2'b11;
	//狀態機狀態轉移
	always@(posedge clk or negedge rst)begin
		if(!rst)
			state <= IDLE;
		else
			state <= next_state;
	end
	
	//狀態組合判定
	always@(rd_req or cnt)begin
		case(state)
			IDLE:
				if(rd_req)
					next_state <= WORK;
				else
					next_state <= IDLE;
			WORK:
				if(cnt==4'd8)
					next_state <= STOP;
				else
					next_state <= WORK;
			STOP:
				if(rd_req)
					next_state <= WORK;
				else
					next_state <= IDLE;
				default:
					next_state <= next_state;
		endcase
	end
	
	//狀態機輸出
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			rd <= 1'b1;
			data_rd <= 8'b0000_0000;
		end
		else begin
			case(state)
				IDLE:begin
					rd <= 1'b1;
					data_rd <= 8'b0000_0000;
				end
				WORK:begin
					rd <= 1'b0;
					if(`SCK_PEDG)begin//下降沿採樣
						case(cnt)
							4'd0:data_rd[7] <= miso;
							4'd1:data_rd[6] <= miso;
							4'd2:data_rd[5] <= miso;
							4'd3:data_rd[4] <= miso;
							4'd4:data_rd[3] <= miso;
							4'd5:data_rd[2] <= miso;
							4'd6:data_rd[1] <= miso;
							4'd7:data_rd[0] <= miso;
							default:data_rd <= data_rd;
						endcase
					end
					else
						data_rd <= data_rd;
				end
				STOP:begin
					rd <= 1'b1;
					data_rd <= data_rd;
				end
				default:begin
					rd <= rd;
					data_rd <= data_rd;
				end
			endcase
		end
	end

endmodule

頂層模塊及例化

//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2020/01/13 20:01:50
// Design Name: spi_master
// Module Name: spi_master
// Project Name: SPI2
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module spi_master(
	input 				clk,
	input 				rst,
	input 				miso,
	output 	 			mosi,
	output 	 			sck,
	output 	 			cs_n,
	output 	 			wr,
	output 	 			rd,
	input[7:0] 			data_wr,
	output[7:0]	data_rd,
	input 				wr_req,
	input 				rd_req
);
	wire[8:0] 			phase;
	wire[3:0] 			cnt;
	
	control_module control_module(
	.clk		(clk),
	.rst		(rst),
	.sck		(sck),
	.cs_n		(cs_n),
	.phase		(phase),
	.wr_req		(wr_req),
	.rd_req		(rd_req),
	.cnt		(cnt)//位數計數器
);
	spi_tx spi_tx(
	.clk		(clk),
	.rst		(rst),
	.wr_req		(wr_req),
	.data_wr	(data_wr),
	.phase		(phase),
	.wr			(wr),
	.mosi		(mosi),
	.cnt        (cnt)
);
	spi_rx spi_rx(
	.clk		(clk),
	.rst		(rst),
	.rd_req		(rd_req),
	.data_rd	(data_rd),
	.phase		(phase),
	.rd			(rd),
	.miso		(miso),
	.cnt        (cnt)
);

endmodule

RTL視圖
在這裏插入圖片描述
狀態機圖
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章