SPI协议_Verilog实现「建议收藏」

SPI协议_Verilog实现「建议收藏」SPI协议_Verilog实现概述:通过Verilog代码+仿真的形式来理解SPI的时序,此处只写了主机发送,从机接收的代码,后待续。。。SPI协议简介●SPI接口介绍  SCK:时钟信号,由主设备产生,所以主设备SCK信号为输出模式,从设备的SCK信号为输入模式。  CS:使能信号,由主设备控制从设备,,所以主设备CS信号为输出模式,从设备的CS信号为输入模式。  MOSI:主设备数据输出,从设备数据输入,所以主设备MOSI信号为输出模式,从设备的MOSI信号为输入模式。  MISO:主设

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

SPI协议_Verilog实现

概述:
通过Verilog代码+仿真的形式来理解SPI的时序,此处只写了主机发送,从机接收的代码,后待续。。。


## **SPI协议简介**

●SPI接口介绍

SCK:时钟信号,由主设备产生,所以主设备SCK信号为输出模式,从设备的SCK信号为输入模式。
  CS:使能信号,由主设备控制从设备,,所以主设备CS信号为输出模式,从设备的CS信号为输入模式。
  MOSI:主设备数据输出,从设备数据输入,所以主设备MOSI信号为输出模式,从设备的MOSI信号为输入模式。
  MISO:主设备数据输入,从设备数据输出,所以主设备MISO信号为输入模式,从设备的MISO信号为输出模式。

●SPI接口连接图

在这里插入图片描述
  注意:MOSI和MISO不能交叉连接(可以把主从机理解为一个整体系统,MOSI为系统主机发送从机接收的数据线,MISO为主机接收从机发送的数据线)。

●SPI数据传输方向

SPI作为全双工的的串行通信协议,数据传输时高位在前,低位在后。主机和从机公用由主机产生的SCK信号,所以在每个时钟周期内主机和从机有1bit的数据交换(因为MOSI和MISO数据线上的数据都是在时钟的边沿处被采样)。
  如下图:
 在这里插入图片描述
 SPI协议规定数据采样是在SCK的上升沿或下降沿时刻(由SPI模式决定,下面会说到),观察上图,在SCK的边沿处,主机会在MISO处采样(接收来从机的数据),从机会在MOSI处采样(接收来自主机的数据),所以每个时钟周期中会有一bit的数据交换。
 SPI数据交换

●SPI传输模式

SPI总线传输一共有4种模式,这4种模式分别由时钟极性(CPOL)和时钟相位(CPHA)来定义。
   在这里插入图片描述

CPOL CPHA
规定了SCK时钟信号空闲状态的电平 规定了数据是在SCK时钟的上升沿还是下降沿被采样
———– ————————————
模式0:CPOL=0,CPHA =0 SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据)
模式1:CPOL=0,CPHA =1 SCK空闲为低电平,数据在SCK的下降沿被采样(提取数据)
模式2:CPOL=1,CPHA =0 SCK空闲为高电平,数据在SCK的下降沿被采样(提取数据)
模式3:CPOL=1,CPHA =1 SCK空闲为高电平,数据在SCK的上升沿被采样(提取数据)

以模式0为例:
SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据)。
在这里插入图片描述
  ◐在时钟的第1个上升沿(游标1处)(采样点)
  MOSI上数据为1,则在此边沿从机采样(提取)数据为1,采样点在MOSI数据线的中间(游标1处)。
  MISO上数据为0,则在此边沿主机采样(提取)数据为0,采样点在MISO数据线的中间(游标1处)。
  ◐在时钟的第1个下降沿(游标2处)(切换点)
  MOSI上数据由1切换为0,数据在时钟下降沿时切换数据。
  MISO上数据由0切换为1,数据在时钟下降沿时切换数据。
  ◐在时钟的第2~8个上升沿(采样点),主机在MISO上采样数据,从机在MOSI上采样数据。
  ◐在时钟的第2~8个下降沿(切换点),主机在MISO上切换数据,从机在MOSI上切换数据。

SPI_verilog实现

✯主机发送代码

//采用SPI模式0:上升沿采样数据,下降沿切换数据
module SPI_MasterToSlave(CLK_50M,RST_N,SCK,CS,MOSI);
input CLK_50M;
input RST_N;
output reg SCK;
output reg CS;
output reg MOSI;
reg[7:0] Send_Data = 8'hA5;//所要发送的数据
/*构造状态机*/
reg[3:0] Data_State = 4'd0;
parameter D7_State = 4'd0;//发送最高位数据-状态
parameter D6_State = 4'd2;
parameter D5_State = 4'd4;
parameter D4_State = 4'd6;
parameter D3_State = 4'd8;
parameter D2_State = 4'd10;
parameter D1_State = 4'd12;
parameter D0_State = 4'd14;//发送最低位数据-状态
always@(posedge CLK_50M or negedge RST_N)
begin
if(RST_N == 0)//复位
begin
SCK <= 1'b0;    //SCK初始电平为低
CS <= 1'b1;     //CS初始电平为高
MOSI <= 1'b0;   //MOSI初始电平为低
end
else//产生SPI时序
begin
CS <= 0;//CS拉低准备数据传输
case(Data_State)
4'd1,4'd3,4'd5,4'd7,4'd9,4'd11,4'd13,4'd15://每次放置数据完毕后 在此拉高时钟线,便于下次的下降沿产生
begin
SCK <= 1'b1;//准备在下降沿放置数据,提前将SCK拉高
Data_State <= Data_State + 4'd1;//切换为数据放置状态(每发完1bit数据进入此一次,将时钟线拉高)
end
D7_State://7位数据发送状态
begin
MOSI <= Send_Data[7];//D7数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D6_State://6位数据发送状态
begin
MOSI <= Send_Data[6];//D6数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D5_State://5位数据发送状态
begin
MOSI <= Send_Data[5];//D5数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D4_State://4位数据发送状态
begin
MOSI <= Send_Data[4];//D4数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D3_State://3位数据发送状态
begin
MOSI <= Send_Data[3];//D3数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D2_State://2位数据发送状态
begin
MOSI <= Send_Data[2];//D2数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D1_State://1位数据发送状态
begin
MOSI <= Send_Data[1];//D1数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
D0_State://0位数据发送状态
begin
MOSI <= Send_Data[0];//D0数据
SCK <= 1'b0;//在下降沿放置数据
Data_State <= Data_State + 4'd1;//切换状态
end
default: Data_State <= D7_State;
endcase
end
end
/*链接从机模块*/
SlaveGetMaster u2
(
.CLK_50M(CLK_50M),
.RST_N(RST_N),
.MOSI(MOSI),
.CS(CS),
.SCK(SCK)
);
endmodule

代码解析见代码注释,整体代码思路即SPI的模式0:SCK的上升沿采样数据,SCK的下降沿切换数据。

✯发送波形

在这里插入图片描述
  ★波形解析:主机发送的数据为0xA5,主机所执行的操作为将所要发送的8bit数据从高到低位依次在SCK的下降沿放置在MOSI数据线上,观察波形在图中①-⑧序号点为SCK的下降沿,在此下降沿时MOSI的数据进行了切换(因为从机要在时钟沿的上升沿采集数据,所以上升沿之前数据保持了稳定)。

✯从机接收代码

//从机接收MOSI的数据 在上升沿的时候采样数据
module SlaveGetMaster(CLK_50M,RST_N,SCK,CS,MOSI);
input CLK_50M;
input RST_N;
input SCK;
input CS;
input MOSI;
reg [7:0] Rec_Data=8'd0;
reg[3:0] Data_State = 4'd0;
parameter D7_State = 4'd0;
parameter D6_State = 4'd1;
parameter D5_State = 4'd2;
parameter D4_State = 4'd3;
parameter D3_State = 4'd4;
parameter D2_State = 4'd5;
parameter D1_State = 4'd6;
parameter D0_State = 4'd7;
always@(posedge SCK)
begin
if(CS == 1)  //CS为高,从机不响应
Rec_Data <= 8'b0000_0000;
else        //CS为低,从机开始接收数据
begin
if(SCK == 1)
begin
case(Data_State)
D7_State:begin Rec_Data[7] <= MOSI; Data_State<= D6_State;end
D6_State:begin Rec_Data[6] <= MOSI; Data_State<= D5_State;end
D5_State:begin Rec_Data[5] <= MOSI; Data_State<= D4_State;end
D4_State:begin Rec_Data[4] <= MOSI; Data_State<= D3_State;end
D3_State:begin Rec_Data[3] <= MOSI; Data_State<= D2_State;end
D2_State:begin Rec_Data[2] <= MOSI; Data_State<= D1_State;end   
D1_State:begin Rec_Data[1] <= MOSI; Data_State<= D0_State;end
D0_State:begin Rec_Data[0] <= MOSI; Data_State<= D7_State;end          
default:Data_State<= D7_State;                          
endcase
end
end
end
endmodule

代码解析见代码注释,整体代码思路即SPI的模式0:SCK的上升沿采样数据。

✯从机接收波形

在这里插入图片描述
  ★波形解析:从机执行的操作为在SCK的上升沿对MOSI数据进行采样,即图中①-⑧序号点为从机对MOSI数据线的采样点。仔细观察采样点在每bit数据的中间点,满足采样定理。8bit数据均接收完毕后所得的数据为0xA5,正是主机发送的数据。
  
★注意:若从机发送主机接收:则从机将数据放置在MISO数据线,主机从MISO数据线上采样数据。
经过以上描述应该明白MISO,MOSI数据线不能交叉连接的原因了*–*。

附:SPI协议_STM32实现

★★★如有错误欢迎指导。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181668.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Javascript获取select下拉框选中的的值[通俗易懂]

    Javascript获取select下拉框选中的的值[通俗易懂]现在有一id=test的下拉框,怎么拿到选中的那个值呢?分别使用javascript原生的方法和jquery方法    text1    text2    code:一:javascript原生的方法  1:拿到select对象:var myselect=document.getElementById(“test”); 2:拿到

  • c语言自定义BOOL函数

    c语言自定义BOOL函数C语言中没有BOOL类型变量,它是C++独有的,由于使用BOOL类型可以使代码更具有可读性,很多编程者都在C中自己定义了类似的应用,一般方法有两种:第一种:采用宏定义方式typedefintBOOL;#definetrue1#definefalse0或写为:#ifndefbool#defineboolint#endif#ifndeftrue…

  • mybatis log plugin激活码激活流程[最新免费获取][通俗易懂]

    (mybatis log plugin激活码激活流程)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html1STL5S9V8F-eyJsaWNlbnNlSWQi…

  • web激活码【中文破解版】[通俗易懂]

    (web激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~DB…

  • pycharm设置pip镜像_pycharm添加镜像源

    pycharm设置pip镜像_pycharm添加镜像源python的pip默认是官方源,查找与安装包都很缓慢,一般切换为国内源,可以快速访问与安装需要的包。pycham版本:2019.3.3使用pycharm,File-Settings,打开图中的界面选择projectinterpreter点击managerepositories将已有的源修改,保留修改后的源,点击确认,注意:只保留一个源然后在安装包界面,…

  • javascript 页面后退并刷新

    javascript 页面后退并刷新javascript做页面后退常使用的方法是window.history.back();这样确实可以做到后退的功能,但是项目中,常常并不只是后退就行完成需求,往往需要在后退的同时,刷新后退的页面信息,比如后退到首页同时刷新首页的最新数据,这样的需求通过上面这种方法就没法满足了,为了实现这个需求,我们需要使用到document.referrer这个方法可以取到上一个页面的具体路径

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号