SPI详解——原理及Verilog实现

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

前置信息

全双工/半双工/单工通信协议

单工通信:数据流只能从发送端到接收端,为单向通道。如:键盘和显示屏之间的通信为单工通信,显示屏只能接收键盘的输入,无法向键盘反馈。
SPI详解——原理及Verilog实现
半双工通信:数据流可以在发送端和接收端双向流动,即:发送端既能发送数据,也能接收数据;接收端既能接收数据,也能发送数据。但是发送端发送数据和接收数据(接收端接收数据和发送数据)不能在同一时刻进行。如:对讲机通信为半双工通信,对讲机两端都可以说话,但是他们不能同时讲话,得一个一个讲。
SPI详解——原理及Verilog实现
全双工通信:数据流可以在发送端和接收端同时双向流动。发送端和接收端均具有独立的TX(发送数据)和RX(接收数据)通道。如:电话通信为全双工通信,电话两端可以同时讲话。

SPI详解——原理及Verilog实现

一、SPI协议

1.SPI传输原理介绍

SPI(Serial Peripheral Interface,串行外围设备接口),是一种全双工通信协议,同步通信。其基本通信模式为
SPI详解——原理及Verilog实现

SPI通信接口为:
SPI_CS_N:片选信号,一般低电平有效。由主机(master)产生,选择与之通信的从机(slaver),低电平表示从机被选中。
SPI_SCLK:时钟信号,由主机产生,用于控制数据传输速率和时机(即:数据采样时间)
SPI_MOSI:SPI接口的TX通道,主机发送给从机的数据(Master Output Slaver Input)
SPI_MISO:SPI接口的RX通道,从机发送给主机的数据(Master Input Slaver Output)

SPI传输特点

1.SPI通信为主从模式。支持一主多从的通信方式,主机通过片选CS信号选中从机。其中需要注意的是:时钟信号CLK只能由主机产生
SPI详解——原理及Verilog实现
2.SPI为同步通信协议:SPI在传输数据的同时传输时钟信号。主机根据将要交换的数据产生时钟脉冲信号,时钟信号通过时钟极性(Clock Polarity)和时钟相位(Clock Phase)规定两个SPI设备在何时进行数据交换和数据采样,实现两个SPI设备的同步传输。
3.SPI为全双工通信协议:SPI同时拥有TX(MOSI)数据通道和RX(MISO)数据通道,为全双工通信。

SPI与I2C/UART的对比

1.硬件接口差异

IIC,拥有两根线,sda(双向端口)/scl(最大4Mbits/s).
SPI,拥有4根线,sclk/SDI(串行输入)/SDO(串行输出)/CS(片选:当接多个从设备时,需要用到该信号)
UART,拥有3根线,RX(接受数据)/TX(发送数据)/GND(地线)

2.协议差异

1.IIC和SPI均为先传输MSB,UART为LSB先传输
2.IIC的速度比SPI的速度更慢一些,协议更复杂一些,线也比标准的SPI少。
3.IIC通过地址选择从设备,SPI通过片选信号选择从设备
4.SPI和UART可以实现全双工通信,IIC为半双工通信(IIC只有一根数据线)
5.IIC需要上拉电阻,抗干扰的能力更弱。一般用于同一板卡上芯片之间的通信,较少用于远距离通信
6.UART需要固定的波特率,也就是说两位数据之间的间隔要相等。SPI无所谓,因为自己有时钟
7.UART为异步通信,一帧可以传送5/6/7/8位数据,SPI为同步通信可以一位一位的传送,IIC为同步通信传送8位连续数据

2.SPI传输模式

SPI协议规定SPI有四种传输模式,由CPOL(时钟极性:Clock Polarity)和CPHA(时钟相位:Clock Phase)决定

作用
CPOL 决定空闲时SCLK电平
CPOL=0:空闲时SCLK为低电平
CPOL=1:空闲时SCLK为高电平
CPHA 决定SPI采样数据是第几个时钟沿
CPHA=0:第一个时钟沿采样
CPHA=1:第二个时钟沿采样

SPI详解——原理及Verilog实现
因此四种模式为:

Mode CPOL/CPHA 行为
Mode 0 CPOL=0
CPHA=0
SCLK空闲时为低电平,上升沿采样数据,下降沿切换数据
Mode 1 CPOL=0
CPHA=1
SCLK空闲时为低电平,下降沿采样数据,上升沿切换数据
Mode 2 CPOL=1
CPHA=0
SCLK空闲时为高电平,下降沿采样数据,上升沿切换数据
Mode 3 CPOL=1
CPHA=1
SCLK空闲时为高电平,上升沿采样数据,下降沿切换数据

其中模式0和模式3比较常用

二、SPI Verilog实现

1.设计时序

Mode 0设计时序:
模式0:sclk空闲时为低电平,数据在上升沿采样
以传输8bit数据为例,数据传输可以分为0-15共16个状态;
发送方向——MOSI(Master Output Slaver Input):
主机发送数据,从机要在上升沿采集数据,为了保证从机进行采样时数据稳定,因此主机在时钟下降沿切换数据(sclk下降沿时,mosi切换),因此各个状态SCLK和MOSI的行为可总结为:
状态0:SCLK为0,MOSI保持不变
状态1:SCLK为1,MOSI进行数据切换
状态2:SCLK为0,MOSI保持不变
状态3:SCLK为1,MOSI进行数据切换
状态4:SCLK为0,MOSI保持不变
状态5:SCLK为1,MOSI进行数据切换
状态6:SCLK为0,MOSI保持不变
状态7:SCLK为1,MOSI进行数据切换
状态8:SCLK为0,MOSI保持不变
状态9:SCLK为1,MOSI进行数据切换
状态10:SCLK为0,MOSI保持不变
状态11:SCLK为1,MOSI进行数据切换
状态12:SCLK为0,MOSI保持不变
状态13:SCLK为1,MOSI进行数据切换
状态14:SCLK为0,MOSI保持不变
状态15:SCLK为1,MOSI进行数据切换,数据传输完毕
接收方向——MISO(Master Iutput Slaver Onput):
主机接收数据,为了保证主机进行采样时数据稳定,因此主机在时钟上降沿c采样(mode 0:数据在上升沿被采样),因此各个状态SCLK和MISO的行为可总结为:
状态0:SCLK为0,采样MISO
状态1:SCLK为1,不采样
状态2:SCLK为0,采样MISO
状态3:SCLK为1,不采样
状态4:SCLK为0,采样MISO
状态5:SCLK为1,不采样
状态6:SCLK为0,采样MISO
状态7:SCLK为1,不采样
状态8:SCLK为0,采样MISO
状态9:SCLK为1,不采样
状态10:SCLK为0,采样MISO
状态11:SCLK为1,不采样
状态12:SCLK为0,采样MISO
状态13:SCLK为1,不采样
状态14:SCLK为0,采样MISO
状态15:SCLK为1,不采样,数据传输完毕
SPI详解——原理及Verilog实现

2.设计框图

SPI详解——原理及Verilog实现

发送方向:
data_in[7:0]:主机需要向从机发送的8bit数据
data_vld:data_in有效指示
tx_en:主机向从机的发送使能
tx_done:主机发送数据完成标志
接收方向:
data_ou[7:0]:主机接受到的来自从机的8bit数据
rx_en:主机接收数据使能
rx_done:主机接收数据完成标志
SPI接口:
spi_cs_n:片选信号
spi_sclk:spi时钟信号
spi_mosi(master output slave input):主机输出数据,从机输入数据
spi_miso(master input slaver output):主机输入数据,从机输出数据
系统接口:
sys_clk:系统时钟
sys_rst_n:系统复位信号

3.verilog代码

1.设计过程中,使用shift_in/shift_ou指示发送和接收方向数据切换与采样时刻。
2.片选信号和时钟信号在状态机结束后立即处于默认值(片选拉高,时钟拉低)

`timescale	1ns/1ns
module spi_module	#(parameter	WORD_SIZE=8)(
	input		wire						sclk,
	input		wire						rst_n,
	input		wire						tx_en,
	input		wire						rx_en,
	input		wire [WORD_SIZE-1:0]		data_in,
	input		wire						data_vld,
	output		wire [WORD_SIZE-1:0]		data_ou,
	output		reg							tx_done,
	output		reg							rx_done,
	//spi interface
	output		reg							spi_cs_n,
	output		reg							spi_clk,
	output		wire						spi_mosi,//MSI first send
	input		wire						spi_miso
);

reg	[3:0]	tx_state;
reg	[3:0]	rx_state;

reg	[WORD_SIZE-1:0]	shift_in_reg;
reg	[WORD_SIZE-1:0] shift_ou_reg;
reg					shift_in;
reg					shift_ou;

reg					tx_done_r;
reg					rx_done_r;

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	begin
		tx_done_r<=1'b0;
		rx_done_r<=1'b0;
		spi_cs_n<=1'b1;
		spi_clk<=1'b0;//mode 0
		//spi_mosi<=1'bz;
		tx_state<=4'd0;
		rx_state<=4'd0;
		shift_in<=1'b0;
		shift_ou<=1'b0;
	end
	else	if(tx_en==1'b1)begin
		spi_cs_n<=1'b0;
		case(tx_state)
			4'd1,4'd3,4'd5,4'd7,4'd9,4'd11,4'd13:begin
				spi_clk<=1'b1;
				tx_state<=tx_state+1'b1;
				shift_in<=1'b1;
			end
			4'd0,4'd2,4'd4,4'd6,4'd8,4'd10,4'd12,4'd14:begin
				spi_clk<=1'b0;
				tx_state<=tx_state+1'b1;
				shift_in<=1'b0;
			end
			4'd15:begin
				spi_clk<=1'b1;
				tx_state<=4'd0;
				shift_in<=1'b1;
				tx_done_r<=1'b1;
			end
			default:tx_state<=4'd0;
		endcase
	end
	else	if(rx_en==1'b1)begin
		spi_cs_n<=1'b0;
		case(rx_state)
			4'd1,4'd3,4'd5,4'd7,4'd9,4'd11,4'd13:begin
				spi_clk<=1'b1;
				rx_state<=rx_state+1'b1;
				shift_ou<=1'b0;
			end
			4'd0,4'd2,4'd4,4'd6,4'd8,4'd10,4'd12,4'd14:begin
				spi_clk<=1'b0;
				rx_state<=rx_state+1'b1;
				shift_ou<=1'b1;
			end
			4'd15:begin
				spi_clk<=1'b1;
				rx_state<=rx_state+1'b1;
				shift_ou<=1'b0;
				rx_done_r<=1'b1;
			end
			default:rx_state<=4'd0;
		endcase
	end
	else	begin
		tx_done_r<=1'b0;
		rx_done_r<=1'b0;
		spi_cs_n<=1'b1;
		spi_clk<=1'b0;//mode 0
		//spi_mosi<=1'bz;
		tx_state<=4'd0;
		rx_state<=4'd0;
		shift_in<=1'b0;
		shift_ou<=1'b0;
	end
end

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	shift_in_reg<='d0;
	else	if(data_vld==1'b1)
		shift_in_reg<=data_in;
	else	if(shift_in==1'b1)
		shift_in_reg<=shift_in_reg<<1;
end
assign	spi_mosi=shift_in_reg[WORD_SIZE-1];

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	shift_ou_reg<=4'd0;
	else	if(shift_ou==1'b1)
		shift_ou_reg<={shift_ou_reg[WORD_SIZE-2:0],spi_miso};
end

assign	data_ou=(rx_done==1'b1)? shift_ou_reg:{{WORD_SIZE{1'hz}}};

always	@(posedge	sclk or	negedge	rst_n)begin
	if(rst_n==1'b0)	begin
		tx_done<=1'b0;
		rx_done<=1'b0;
	end
	else	begin
		tx_done<=tx_done_r;
		rx_done<=rx_done_r;
	end
end

endmodule

testbench文件为:
注:仿真过程中只验证发送方向,未验证接收方向。

`timescale	1ns/1ns
module tb_spi_module #(parameter	WORD_SIZE=8)();

reg					sclk;
reg					rst_n;
reg					tx_en;
reg					rx_en;
reg	[WORD_SIZE-1:0]	data_in;
reg					data_vld;
wire [WORD_SIZE-1:0]	data_ou;
wire				tx_done;
wire				rx_done;
wire				spi_cs_n;
wire				spi_clk;
wire				spi_mosi;
reg					spi_miso;

initial	begin
	sclk=1'b0;
	forever	#10	sclk=~sclk;
end

initial	begin
	rst_n=1'b0;
	#100	rst_n=1'b1;
end

initial	begin
	rx_en=1'b0;
//	tx_en=1'b1;//send data
	spi_miso=1'b0;
end

initial	begin
	#100	data_in=8'haa;data_vld=1'b1;
	#20		data_vld=1'b0;
	#400	data_in=8'hfb;data_vld=1'b1;
	#20		data_vld=1'b0;
	#400	data_in=8'h99;data_vld=1'b1;
	#20		data_vld=1'b0;
end

initial	begin
	tx_en=1'b0;
	#150	tx_en=1'b1;
	@(tx_done)	tx_en=1'b0;
    #150	tx_en=1'b1;
	@(tx_done)	tx_en=1'b0;
	#150	tx_en=1'b1;
	@(tx_done)	tx_en=1'b0;
end


spi_module	spi_module_inst(
.	sclk	(	sclk	)	,
.	rst_n	(	rst_n	)	,
.	tx_en	(	tx_en	)	,
.	rx_en	(	rx_en	)	,
.	data_in	(	data_in	)	,
.	data_vld(	data_vld)	,
.	data_ou	(	data_ou	)	,
.	tx_done	(	tx_done	)	,
.	rx_done	(	rx_done	)	,
.	spi_cs_n(	spi_cs_n)	,
.	spi_clk	(	spi_clk	)	,
.	spi_mosi(	spi_mosi)	,//MSI first send
.	spi_miso(	spi_miso)	
);


endmodule

仿真结果为:
SPI详解——原理及Verilog实现

参考文献

SPI总线的原理与Verilog实现
SPI协议_Verilog实现
单工通信、半双工通信和全双工通信有何区别和联系?文章来源地址https://www.toymoban.com/news/detail-428243.html

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

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

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

相关文章

  • Verilog实现的SPI通信

    SPI,Serial Peripheral Interface,串行外设接口,高速的、全双工、同步通信总线。SPI以主从方式工作,一般需要至少4根线(单向传输时可用3根): (1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出; (2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;

    2023年04月08日
    浏览(28)
  • STM32F103单片机通过SPI全双工通信协议与W25Q64(FLASH)进行通信【串行同步通信(数据线与时钟线配合),(一主多从模式)】附相关驱动代码详解

    1.W25Qxx系列是一种低成本、小型化、使用简单的 非易失性存储器 ,常应用于数据存储、字库存储、固件程序存储等场景 2.存储介质: Nor Flash(闪存) 3.时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI) 4.存储容量(24位地址): W25Q40: 4Mbit / 512KByte W25Q80: 8Mbit / 1MByte W25Q16: 16

    2024年04月13日
    浏览(61)
  • CRC校验码生成逻辑的实现原理详解——结合C语言和Verilog语言代码分析

    因为前段时间用到CRC校验码,所以在网上找到了很多有关CRC校验码计算原理以及生成CRC校验码的代码实现(包括C语言和Verilog语言的实现)的文章,但关于CRC校验码代码实现的原理未能找到相关文章,于是自己结合C语言和Veirlog语言的实现代码以及CRC校验码的计算原理,对CR

    2023年04月22日
    浏览(101)
  • A.图机器学习(GML)&图神经网络(GNN)原理和代码实现(前置学习系列二)

    图学习图神经网络算法专栏简介:主要实现图游走模型(DeepWalk、node2vec);图神经网络算法(GCN、GAT、GraphSage),部分进阶 GNN 模型(UniMP标签传播、ERNIESage)模型算法等,完成项目实战 专栏链接 :图学习图神经网络算法专栏简介:含图算法(图游走模型、图神经网络算法等)原

    2024年02月01日
    浏览(41)
  • Java SPI概念、实现原理、优缺点、应用场景、使用步骤、实战SPI案例

    在当今互联网时代,应用程序越来越复杂,对于我们开发人员来说,如何实现高效的组件化和模块化已经成为了一个重要的问题。而 Java SPI (Service Provider Interface)机制,作为一种基于接口的服务发现机制,可以帮助我们更好地解决这个问题。这样会程序具有高度的 灵活性、

    2024年02月13日
    浏览(47)
  • Springboot集成SSE实现消息推送之单工通信

    通常在一些web项目中,会涉及到想客户端推送消息,常见的有Ajax轮询、webSocket,本篇文章主要使用Springboot集成SSE实现向客户端持续推送信息。 服务发送事件SSE(Sever-Sent Event),就是基于 HTTP 的技术,浏览器向服务器发送一个保持长连接HTTP请求,服务器单向地向客户端以流形

    2024年01月17日
    浏览(45)
  • 【Verilog】同步FIFO原理及verilog实现(参数化)

            旨在学习理解,项目中还是用成熟IP靠谱~ 目录 一、FIFO原理 二、同步FIFO设计 2.1 位宽和深度 2.2 空、满标志 2.3 FIFO计数 2.4 ram模型 2.5 读/写操作 三、​​​​​​​verilog代码 四、仿真验证 后记 FIFO( First Input First Output)是指先进先出。模型如下:           F

    2024年02月05日
    浏览(34)
  • 推排序 Verilog实现原理

    推排序常常应用在操作系统的任务调度中,尝试使用硬件对堆排序进行实现,在实现的过程中不使用 function 和 tasks 语法,即真·硬件实现 也就这一个博客有介绍 堆排序的 Verilog 实现 堆排序还需要复习一遍吗? 我肯定是要的 菜鸟-堆排序 图解排序算法(三)之堆排序 可以看到,

    2023年04月19日
    浏览(29)
  • 【Verilog】CRC校验码生成器原理及verilog实现

    目录 一、CRC的基本原理  二、CRC生成步骤 2.1举个栗子 三、Verilog实现 四、参考资料 4.1 CRC在线计算器 CRC :Cyclic Redundancy Check循环冗余校验码         将被处理的报文比特序列当做一个二进制多项式A(x)的系数,任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和

    2024年02月11日
    浏览(36)
  • 视觉信息处理与FPGA实现第八次作业——verilog实现亮度调节

    HxD下载链接:https://download.csdn.net/download/weixin_44357071/89045331 解压直接打开exe就能使用。 将需要查看二进制数据的图片拖到软件框里就能读取 从000Eh(h是16进制的意思)到0035是真的有40byte.横坐标是零到16,竖坐标是像十进制一样,把个位数空出来,然后是10,20,30..... 图中框框里

    2024年04月16日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包