热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SPI总线介绍和verilog实现

这篇文章讲SPI总线,SPI是serialperipheralinterface的缩写,即串行外围设备接口。该接口是摩托罗拉公司提出的全双工同步通信的接口,该接口只有四根信号线,在芯片的管脚上只

这篇文章讲SPI总线,SPI是serial peripheral interface 的缩写,即串行外围设备接口。该接口是摩托罗拉公司提出的全双工同步通信的接口,该接口只有四根信号线,在芯片的管脚上只占用4根线,节约了芯片的管脚。

这四根信号信如下:

1、MOSI:主器件数据输出,从器件数据输入。

2、MISO:主器件数据输入,从器件数据输出。

3、SCLK:时钟线,有主器件控制。

4、CS:从器件的片选线,由主器件控制。

在点对点的通信当中:无须寻址工作,使用该接口实现全双工通信,高效简单,一个主器件可以连接多个从设备,每个从设备有独立的片选信号。不过该接口有一个缺点,就是没有应答机制。

该接口的工作机制:主设备启动,连接多个从设备,在sdo端输出,si端输入数据,均在sclk的上升沿传输数据,则经过8/16次时钟的改变,就能够完成8/16 bit的数据传输。

一般情况下,对有该接口的时钟会有两方面的设置:一方面是时钟极性,主要是用来规定空闲状态下sclk的值,0代表空闲状态下是低电平,1代表空闲状态下是高电平;另一方面是时钟相位的设置,主要是规定数据是在第一个跳变沿被采样还是第二个跳变沿被采样,0是代表第一个跳变沿,1是代表第二个跳变沿。下面两幅图给出不同相位下,不同极性的传输效果:

相位为0:


相位为1:


以上就是SPI接口的工作原理,下面给出其verilog实现,这里主器件用读命令和写命令来控制数据的输入和输出,并且对于一个字节的数据读和写分别用一个任务实现,如下:

module spi(clk,rd,wr,rst,data_in,si,so,sclk,cs,data_out);
parameter bit7=4'd0,bit6=4'd1,bit5=4'd2,bit4=4'd3,bit3=4'd4,bit2=4'd5,bit1=4'd6,bit0=4'd7,bit_end=4'd8;
parameter bit70=4'd0,bit60=4'd1,bit50=4'd2,bit40=4'd3,bit30=4'd4,bit20=4'd5,bit10=4'd6,bit00=4'd7,bit_end0=4'd8;

parameter size=8;
input clk,rst;
input wr,rd;//读写命令
input si;//spi数据输入端
input [size-1:0]data_in;//待发送的数据

output[size-1:0]data_out;//待接收的数据
output sclk;//spi中的时钟
output so;//spi的发送端
output cs;//片选信号

wire [size-1:0]data_out;
reg [size-1:0]dout_buf;
reg FF;
reg sclk;
reg so;
reg cs;


reg [3:0]send_state;//发送状态寄存器
reg [3:0]receive_state;//接收状态寄存器

always@(posedge clk)
begin
if(!rst)
begin
sclk<=0;
cs<=1;
end
else
begin
if(rd|wr)
begin
sclk<=~sclk;//当开始读或者写的时候,需要启动时钟
cs<=0;
end
else
begin
sclk=0;
cs<=1;
end
end
end


always@(posedge sclk)//发送数据
begin
if(wr)
begin
send_state<=bit7;
send_data;
end
end

always@(posedge sclk)//接收数据
begin
if(rd)
begin
receive_state<=bit70;
FF<=0;
receive_data;
end
end

assign data_out=(FF==1)?dout_buf:8'hz;

task send_data;//发送数据任务
begin
case(send_state)
bit7:
begin
so<=data_in[7];
send_state<=bit6;
end
bit6:
begin
so<=data_in[6];
send_state<=bit5;
end
bit5:
begin
so<=data_in[5];
send_state<=bit4;
end
bit4:
begin
so<=data_in[4];
send_state<=bit3;
end
bit3:
begin
so<=data_in[3];
send_state<=bit2;
end
bit2:
begin
so<=data_in[2];
send_state<=bit1;
end
bit1:
begin
so<=data_in[1];
send_state<=bit0;
end
bit0:
begin
so<=data_in[0];
send_state<=bit_end;
end
bit_end:
begin
so=1'bz;
send_state<=bit7;
end
endcase
end
endtask

task receive_data;
begin
case (receive_state)
bit70:
begin
dout_buf[7]<=si;
receive_state<=bit60;
end
bit60:
begin
dout_buf[6]<=si;
receive_state<=bit50;
end
bit50:
begin
dout_buf[5]<=si;
receive_state<=bit40;
end
bit40:
begin
dout_buf[4]<=si;
receive_state<=bit30;
end
bit30:
begin
dout_buf[3]<=si;
receive_state<=bit20;
end
bit20:
begin
dout_buf[2]<=si;
receive_state<=bit10;
end
bit10:
begin
dout_buf[1]<=si;
receive_state<=bit00;
end
bit00:
begin
dout_buf[0]<=si;
receive_state<=bit_end;
FF<=1;
end
bit_end0:
begin
dout_buf<=8'hzz;
receive_state<=bit70;
end
endcase
end
endtask
endmodule
测试代码:

`timescale 1ns/1ns
`define half_period 10
module spi_test;
parameter size=8;
wire so;
wire sclk;
wire [size-1:0]data_out;
wire cs;

reg [size-1:0]data_in;
reg wr,rd;
reg si;

reg rst;
reg [size-1:0]si_buf;
reg clk;

always#(`half_period) clk=~clk;
initial
begin
clk=0;
rst=1;
si_buf=8'b1001_1010;
data_in=8'b0101_0011;
#5
rst=0;
#10
rst=1;
wr=1;
rd=1;
#380 rd=0;
#1000 $stop;
end
always@(posedge clk)
begin
si_buf=si_buf<<1;
si<=si_buf[7];

end

spi m(clk,rd,wr,rst,data_in,si,so,sclk,cs,data_out);
endmodule
最后得到的仿真图,这里数据没有传输完都设置为高阻状态:






推荐阅读
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 配置IPv4静态路由实现企业网内不同网段用户互访
    本文介绍了通过配置IPv4静态路由实现企业网内不同网段用户互访的方法。首先需要配置接口的链路层协议参数和IP地址,使相邻节点网络层可达。然后按照静态路由组网图的操作步骤,配置静态路由。这样任意两台主机之间都能够互通。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
author-avatar
as123466_866
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有