SPI简介及FPGA通用MOSI模块实现

这篇具有很好参考价值的文章主要介绍了SPI简介及FPGA通用MOSI模块实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

SPI(Serial Peripheral Interface,串行外围设备接口)通讯协议,是Motorola公司提出的一种同步串行接口技术。是一种高速、全双工、同步通信总线。在芯片中只占用四根管脚用来控制及数据传输。

优缺点:

SPI通讯协议的优点是支持全双工通信,通讯方式较为简单,且相对数据传输速率较快;
缺点是没有指定的流控制,没有应答机制确认数据是否接收,与IIC总线通讯协议相比,在数据可靠性上有一定缺陷。

物理层

对于SPI协议的物理层,需要讲解的就是SPI通讯设备的连接方式和设备引脚的功能描述。
SPI通讯设备的通讯模式是主从通讯模式,通讯双方有主从之分,根据从机设备的个数,SPI通讯设备之间的连接方式可分为一主一从和一主多从,具体见下图1、2。

spi通讯mosi,# FPGA协议与接口,fpga开发,spi协议
图 1 一主一从SPI通讯设备连接图
spi通讯mosi,# FPGA协议与接口,fpga开发,spi协议
图 2 一主多从SPI通讯设备连接图

SPI通讯协议包含1条时钟信号线、2条数据总线和1条片选信号线, 时钟信号线为SCK,2条数据总线分别为MOSI(主输出从输入)、MISO(主输入从输出),片选信号线为,它们的作用介绍如下:

  1. SCK (Serial Clock):时钟信号线,用于同步通讯数据。由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不同,两个设备之间通讯时,通讯速率受限于低速设备。

  2. MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,数据方向由主机到从机。

  3. MISO (Master Input,Slave Output):主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,数据方向由从机到主机。

  4. (Chip Select):片选信号线,也称为CS_N,以下用CS_N表示。当有多个SPI从设备与SPI主机相连时,设备的其它信号线SCK、MOSI及MISO同时并联到相同的SPI总线上,即无论有多少个从设备,都共同使用这3条总线;而每个从设备都有独立的这一条CS_N信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。

I2C协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而SPI协议中没有设备地址,它使用CS_N信号线来寻址,当主机要选择从设备时,把该从设备的CS_N信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI通讯。所以SPI通讯以CS_N线置低电平为开始信号,以CS_N线被拉高作为结束信号。

四种通讯模式

SPI通讯协议一共有四种通讯模式,模式0、模式1、模式2以及模式3,这4种模式分别由时钟极性(CPOL,Clock Polarity)和时钟相位(CPHA,Clock Phase)来定义。

CPOL参数规定了空闲状态(CS_N为高电平,设备未被选中)时SCK时钟信号的电平状态;
CPHA规定了数据采样是在SCK时钟的奇数边沿还是偶数边沿。

极性和相位

SPI的极性Polarity和相位Phase,最常见的写法是CPOL和CPHA,不过也有一些其他写法,简单总结如下:
(1) CKPOL (Clock Polarity) = CPOL = POL = Polarity = (时钟)极性
(2) CKPHA (Clock Phase) = CPHA = PHA = Phase = (时钟)相位
(3) SCK=SCLK=SPI的时钟
(4) Edge=边沿,即时钟电平变化的时刻,即上升沿(rising edge)或者下降沿(falling edge)

模式判别

CPOL,表示当SCLK空闲idle的时候,其电平的值是低电平0还是高电平1:
CPOL=0,时钟空闲idle时候的电平是低电平,所以当SCLK有效的时候,就是高电平,就是所谓的active-high;
CPOL=1,时钟空闲idle时候的电平是高电平,所以当SCLK有效的时候,就是低电平,就是所谓的active-low;

CPHA=0,表示第一个边沿
对于CPOL=0,idle时候的是低电平,第一个边沿就是从低变到高,所以是上升沿;
对于CPOL=1,idle时候的是高电平,第一个边沿就是从高变到低,所以是下降沿;

CPHA=1,表示第二个边沿
对于CPOL=0,idle时候的是低电平,第二个边沿就是从高变到低,所以是下降沿;
对于CPOL=1,idle时候的是高电平,第一个边沿就是从低变到高,所以是上升沿;

SPI通讯协议的4种模式如下,通讯模式时序图,具体见下图 :
模式0:CPOL= 0,CPHA=0。空闲状态时SCK串行时钟为低电平;数据采样在SCK时钟的上升沿;数据更新在SCK时钟的下降沿。
模式1:CPOL= 0,CPHA=1。空闲状态时SCK串行时钟为低电平;数据采样在SCK时钟的下降沿;数据更新在SCK时钟的上升沿。
模式2:CPOL= 1,CPHA=0。空闲状态时SCK串行时钟为高电平;数据采样在SCK时钟的下降沿;数据更新在SCK时钟的上升沿。
模式3:CPOL= 1,CPHA=1。空闲状态时SCK串行时钟为高电平;数据采样在SCK时钟的上升沿;数据更新在SCK时钟的下降沿。
spi通讯mosi,# FPGA协议与接口,fpga开发,spi协议
模式的判断:
如果起始的SCLK的电平是0,那么CPOL=0,如果是1,那么CPOL=1,
然后看数据采样时刻,对应到上面SCLK时钟的位置,对应着是第一个边沿或是第二个边沿,即CPHA是0或1

时序需求

tSLCH:cs_n拉低到sck高的时间
tCHSH:sck高到cs_n拉高的时间
SCK上升沿MOSI的建立时间保持时间需求
tSHSL:取消选择的时间,两串数据间隔时间
spi通讯mosi,# FPGA协议与接口,fpga开发,spi协议

SPI通用模块

实现功能

用于将任意宽度向量型数据转换为SPI串行输出,模式0:CPOL= 0,CPHA=0;
默认串行数据mosi数据的建立时间和保持时间均为2个clk(0.5*DIV_FREQUENCY)周期,即sck上升沿的前后2个(0.5*DIV_FREQUENCY)clk数据稳定,串行时钟sck周期为4*clk(DIV_FREQUENCY)的周期;
默认tSLCH(cs_n拉低到sck高的时间为6*clk(1.5*DIV_FREQUENCY)周期),tCHSH(sck高到cs_n拉高的时间为2*clk(0.5*DIV_FREQUENCY)周期);
默认tSHSL为10个clk的周期;
若时序满足此模块可以不做修改。若需要修改在外部例化时修改DIV_FREQUENCY(只能偶分频)和PERIOD_WIDTH_MAX,CNT_SHSL_MAX和CNT_SHSL_WIDTH即可。

使用方法

输入data的位宽和计数器位宽在外部进行例化时修改参数的值即可,不必修改SPI模块
DATA_WIDTH_MAX修改为输入数据的位宽,如[31:0]的数据则DATA_WIDTH_MAX=32
CNT_DATA_WIDTH_MAX修改为输入数据的位宽计数器需要的位宽上限,即DATA_WIDTH_MAX=32对应的二进制位宽32=6’b10_0000,所以CNT_DATA_WIDTH_MAX=6

输入输出端口说明:

//input
input 		wire 						clk 			, //系统时钟,spi串行时钟的分频基准 			
input 		wire						clr_n 			, //spi信号标志信号,允许发送时一直拉高,重新发送时拉低复位再拉高
input 	  	wire  [DATA_WIDTH_MAX-1:0] 	data 			, //需要data与clr_n一同进入			
	                                                    
//output	                                            
output		reg							cs_n 			, //片选信号
output 	  	reg			 				sck 			, //串行时钟
output		reg							mosi 			, //主输出从输入数据
output		reg							flag 			  //spi发送完成标志位,完成则一直拉高;clr_n置0时拉低

例化模板:

spi #(
.DATA_WIDTH_MAX 	(8	 	),
.CNT_DATA_WIDTH_MAX	(4		) 
)
u_spi(
	.clk 	(clk			),
	.clr_n  (clr_n			),
	.data   (data_in		),
		
	.cs_n   (cs_n			),
	.sck    (sck 			),
	.mosi   (mosi			),
	.flag   (flag			)
); 

SPI模块

//========================================================================
// 	module_name.v	:spi.v
// 	Author			:YprgDay
// 	Description		:用于将任意宽度向量型数据转换为SPI串行输出,模式0:CPOL= 0,CPHA=0。
//========================================================================
module spi
 #(
	//=========================< Parameter >==============================
	parameter 				DATA_WIDTH_MAX		=	32				,//例化时修改为输入数据的位宽,如[31:0]的数据则DATA_WIDTH_MAX	=32
	parameter 				CNT_DATA_WIDTH_MAX	=	6				,//例化时修改为输入数据的位宽计数器需要的位宽上限,即DATA_WIDTH_MAX=32对应的二进制位宽32=6'b10_0000,所以CNT_DATA_WIDTH_MAX=6

	parameter 				DIV_FREQUENCY		=	4				,//分频数(只允许偶分频),串行时钟sck周期为DIV_FREQUENCY*clk的周期
	parameter 				PERIOD_WIDTH_MAX	=	2				,//(DIV_FREQUENCY-1)对应的二进制位宽即为PERIOD_WIDTH_MAX
	parameter 				CNT_PERIOD_MAX		=	DIV_FREQUENCY-1	,
	parameter 				CNT_HALF_PERIOD_MAX	=	CNT_PERIOD_MAX >> 1	,//计数分频中值
	parameter 				CNT_SHSL_MAX		=   10				,//tSHSL计数10个clk周期
	parameter 				CNT_SHSL_WIDTH		=   4				 //CNT_SHSL_MAX的二进制位宽
) 
(
	//=========================< Port Name >==============================
	//input
	input 		wire 						clk 			, //系统时钟,spi串行时钟的分频基准 			
	input 		wire						clr_n 			, //spi信号标志信号,允许发送时一直拉高,重新发送时拉低复位再拉高		
	input 	  	wire  [DATA_WIDTH_MAX-1:0] 	data 			, //需要data与clr_n一同进入			
		                                                    
	//output	                                            
	output		reg							cs_n 			, //片选信号
	output 	  	reg			 				sck 			, //串行时钟
	output		reg							mosi 			, //主输出从输入数据
	output		reg							flag 			  //spi发送完成标志位,完成则一直拉高;clr_n置0时拉低
	
);

	//=========================< Always block >===========================
	reg [CNT_DATA_WIDTH_MAX-1:0] 	cnt_data_width			;//输出到第几位计数
	reg [PERIOD_WIDTH_MAX-1:0] 		cnt_spi_period			;//时钟分频计数
	reg [DATA_WIDTH_MAX-1:0] 		data_reg	  			;//存输入数据,保证一个spi发送周期数据不改变
	reg [CNT_SHSL_WIDTH-1:0]		cnt_shsl				;//SHSL时间计数,保证两串spi的时序需求
	
	//输出的cs_n片选信号
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			cs_n <= 1'b1;
		end
		else if(cnt_data_width == DATA_WIDTH_MAX && cnt_spi_period == CNT_PERIOD_MAX)begin
            cs_n <= 1'b1;
		end
		else begin
			cs_n <= 1'b0;
		end
	end	
	
	//输出的sck串行时钟信号,
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			sck <= 0;
		end
		else if(cnt_data_width > 0 && cnt_spi_period == CNT_PERIOD_MAX)begin
            sck <= 0;
		end
		else if(cnt_data_width > 0 && cnt_spi_period == CNT_HALF_PERIOD_MAX)begin
			sck <= 1;
		end
		else begin
			sck <= sck;
		end
	end
	
	//mosi的串行输出
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			mosi <= 0;
		end
		else if(cnt_data_width == DATA_WIDTH_MAX && cnt_spi_period == CNT_PERIOD_MAX)begin
            mosi <= 0;
		end
		else if(cnt_spi_period == CNT_PERIOD_MAX)begin
            mosi <= data_reg[DATA_WIDTH_MAX-1-cnt_data_width];
		end
		else begin
			mosi <= mosi;
		end
	end 
	
	
	//输出的串行数据发送完成标志信号,发送完成即拉高
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			flag <= 0;
		end
		else if(cnt_shsl == CNT_SHSL_MAX)begin
            flag <= 1;
		end
		else begin
			flag <= 0;
		end
	end
	
	//输入数据寄存,保证data在一串SPI数据发完之间不发生变化
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			data_reg <= 0;
		end
		else if(cnt_data_width == 0 && cnt_spi_period == 1)begin
            data_reg <= data;
		end
		else begin
			data_reg <= data_reg;
		end
	end
	
	//时钟四分频计数
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			cnt_spi_period <= 0;
		end
		else if(cnt_data_width == DATA_WIDTH_MAX && cnt_spi_period == CNT_PERIOD_MAX)begin
			cnt_spi_period <= cnt_spi_period;
		end
		else if(cnt_spi_period == CNT_PERIOD_MAX)begin
			cnt_spi_period <= 0;
		end
		else if(cs_n == 0)begin
			cnt_spi_period <= cnt_spi_period + 1'b1;
		end
		else;
	end	
	
	//计数表示此时输出到[DATA_WIDTH_MAX:0] data的第几位位置
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			cnt_data_width <= 0;
		end
		else if(cnt_data_width == DATA_WIDTH_MAX && cnt_spi_period == CNT_PERIOD_MAX)begin
			cnt_data_width <= cnt_data_width;
		end
		else if(cnt_spi_period == CNT_PERIOD_MAX)begin
            cnt_data_width <= cnt_data_width + 1'b1;
		end
		else;
	end
	
	
	//SHSL时间计数,保证两串spi的时序需求,用于对flga信号拉高判断
	always @(posedge clk or negedge clr_n)begin
		if(clr_n == 1'b0)begin
			cnt_shsl <= 0;
		end
		else if(cnt_shsl == CNT_SHSL_MAX)begin
            cnt_shsl <= cnt_shsl;
		end
		else if(cnt_data_width == DATA_WIDTH_MAX && cnt_spi_period == CNT_PERIOD_MAX)begin
			cnt_shsl <= cnt_shsl + 1'b1;
		end
		else;
	end
	
endmodule

仿真模块

`timescale 1ns / 1ps
//
// Module Name: tb_spi
// Dependencies: spi模块仿真
//
module tb_spi();

	//=========================< Parameter >==============================
	parameter 				SPI_CLK_PERIOD		=	2			    ;//设置spi时钟信号周期
	parameter 				HALF_SPI_CLK_PERIOD	=	SPI_CLK_PERIOD/2;//生成spi时钟信号半周期

	//=========================< Port Name >==============================
	//input
	reg						clk								;
	reg    					clr_n							;
	reg 		[7:0]		data_in							;
	//output
	wire					mosi							;
	wire					cs_n							;
	wire					sck								;
	wire					flag							;
	
	//==========================< Clock block >============================
	always 	  	#HALF_SPI_CLK_PERIOD		clk = ~clk	;
	
	//==========================< Reset block >============================
	 initial begin
		clk 		= 	1'b1	;
		clr_n  		<= 	1'b0	;
		data_in     <=	0		;
		#HALF_SPI_CLK_PERIOD
		clr_n  		<= 	1'b1	;
		data_in     <=	8'h83	;
		#30
		data_in     <=	8'h54	;
		#300
		clr_n  		<= 	1'b0	;
		data_in     <=	8'hc7	;
		#10
		clr_n  		<= 	1'b1	;
	end
	
	//==========================< Module Instance >============================
	spi #(
	.DATA_WIDTH_MAX 	(8	 	),
	.CNT_DATA_WIDTH_MAX	(4		)				
	)
	u_spi(
		.clk 	(clk			),
		.clr_n  (clr_n			),
		.data   (data_in		),
			
		.cs_n   (cs_n			),
		.sck    (sck 			),
		.mosi   (mosi			),
		.flag   (flag			)
	); 

endmodule

仿真时序图

以8位输入数据[7:0]data的SPI时序图为例
spi通讯mosi,# FPGA协议与接口,fpga开发,spi协议文章来源地址https://www.toymoban.com/news/detail-824371.html

到了这里,关于SPI简介及FPGA通用MOSI模块实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA模块——SPI协议(读写FLASH)

    芯片引脚图: 内部结构图: 存储区域总共分成了32块,每块64KB。每块又分成了16个部分,每个部分4KB。方便进行读取和局部操作。 电路设计 SPI的四种模式 这里使用这个模式: 主机和从机在时钟上升沿放入要输出的数据,在时钟下降沿读取要输入的数据。 8个时钟后交换一个

    2024年02月05日
    浏览(48)
  • 基于SPI的FPGA-MCU通用通信界面设计与技术详解

    FPGA与MCU之间的通信想必是很多异构人极为头疼的难题。如果每次写一个工程都要大费周章重写通信逻辑、通信协议之类的东西,不仅耗费心神,而且浪费时间。本文基于安陆PH1A90SBG484,提出一个已经通过门级仿真验证的通用通信界面解决方案。详细代码见以下链接: Github代

    2024年02月04日
    浏览(51)
  • FPGA实现SPI接口(1)--什么是SPI接口?

    目录 1、什么是SPI协议 2、SPI协议详述 2.1、SPI协议物理层 2.2、SPI 协议层 2.3、SPI协议通信过程 2.4、SPI协议的特性 2.5、SPI协议的优势、劣势 3、驱动代码的设计实现 3.1、接口定义与整体设计 3.2、Verilog代码 4、Testbench及仿真结果 4.1、单个BYTE的仿真 4.2、多个BYTE的仿真 5、其他  

    2024年02月09日
    浏览(45)
  • FPGA——实现三线SPI和UART

    目录 逻辑框图(原理图) 端口约束和ILA  ILA waveform  实测波形 串口调试工具 源代码 顶层  FPGA和芯片之间通过三线SPI接口通信(DATA复用一个IO端口),FPGA和PC之间通过UART串口通信。 原理图包含4个模块,分别为:内建模块IBUFDS(用于将外部差分时钟转换为内部单端时钟)、

    2024年02月09日
    浏览(36)
  • FPGA常见接口及逻辑实现(三)—— SPI

    一、SPI协议简介         SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种同步串行接口,相对于之前介绍过的UART和I2C,SPI的速率就高出很多,最高能到100M左右,SPI协议比较简单,就不多做介绍,主要介绍下与UART和I2C的不同,SPI是一主多从协议,每个从机通过

    2024年04月26日
    浏览(35)
  • 【LabVIEW FPGA入门】LabVIEW FPGA 实现SPI通信协议

            该实现由两个组件组成:在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口,同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA(直接内存访问

    2024年01月17日
    浏览(58)
  • 基于SPI实现stm32与fpga通信(一)

    SPI通信协议有以下4种模式: 模式0:时钟极性为0,时钟相位为0,数据在时钟下降沿捕获,数据在时钟上升沿改变。 模式1:时钟极性为0,时钟相位为1,数据在时钟上升沿捕获,数据在时钟下降沿改变。 模式2:时钟极性为1,时钟相位为0,数据在时钟上升沿捕获,数据在时钟

    2024年04月16日
    浏览(46)
  • 孩子都能学会的FPGA:第三十一课——用FPGA实现SPI主机发送数据

    (原创声明:该文是 作者的原创 ,面向对象是 FPGA入门者 ,后续会有进阶的高级教程。宗旨是 让每个想做FPGA的人轻松入门 , 作者不光让大家知其然,还要让大家知其所以然 !每个工程作者都搭建了全自动化的仿真环境,只需要双击 top_tb.bat 文件就可以完成整个的仿真(前

    2024年02月04日
    浏览(43)
  • SPI总线通讯协议学习

    目录 什么是SPI 信号线 理解通讯原理 采样  SPI的推广 SPI是芯片与芯片之间的通讯,准确得说是 串行同步通讯 。既然都说了同步,那发送数据当然要和时钟线SCK配合才能发数据. 采用一主多从的模式,主机只有一个,而从机可以有若干个。     需要四条信号线:(SS(CS),SCK,MOSI,MOS

    2024年02月06日
    浏览(45)
  • FPGA实现SPI协议基于ADC128S022进行模拟信号采集

    使用vivado联合modelsim实现SPI协议基于ADC128S022进行模拟信号连续采集。 SPI是串行外设接口,是一种同步/全双工/主从式接口。通常由四根信号线构成: CS_N :片选信号,主从式接口,可以有多个从机,用片选信号进行从机选择; SCLK :串行时钟线,由主机提供给从机; MISO :主机

    2024年02月14日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包