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视图
在这里插入图片描述
状态机图
在这里插入图片描述

发布了5 篇原创文章 · 获赞 10 · 访问量 159

猜你喜欢

转载自blog.csdn.net/qq_43650722/article/details/103975489
今日推荐