深入浅出理解SPI协议
SPI,全称(Serial Peripheral interface)是由摩托罗拉公司首先定义的协议,中文名为串型外围设备接口。SPI是一种高速全双工的总线协议
Serial(串型):与并型相对应,单向数据通路只需要一根线,而同样常见的AMBA则为并型总线
Peripheral(外围):指此总线多用来连接如“AD转换、EEPROM、PWM”等外围设备,即对应于AMBA的APB部分
Interface(总线接口):很好理解,不再赘述。
通信协议可以按照通信方式分为单工,半双工,全双工三种。
单工:发射端和接收端固定,有一条数据通路,通路上数据单向流动。
半双工:发射端和接收端可变,有一条数据通路,通路上数据双向流动。
全双工:发射端和接收端,有两条数据通路,一条从TX到RX,另一条从RX到TX。
一张形象的图片表示如下

比如说我们在从零开始的Verilog UART设计中所实现的就是一个单工UART
因为SPI是全双工总线协议,因此SPI的数据通路上存在从主设备到从设备的数据通道和从从设备到主设备的数据通道
SPI需要四条线才能完成数据的发送,分为3条总线和1条片选线

SCK:Serial Clock, 串行时钟信号,SPI需要依靠着这个信号的边沿进行数据的传递
MOSI:Master output Slave input,对于主设备来说,是发送数据的端口,对于从设备来说,是接收数据的端口。
MISO:Master input Slave output,对于从设备来说,是接收数据的端口,对于主设备来说,是发送数据的端口。
NSS: N Slave connect,一般情况下是由主机发送,从机接收,表示哪一个从设备有效的信号
因为MOSI和MISO的存在,因此SPI才是一个全双工的协议(即分别对于主设备和从设备来说,既可以发送数据,又可以接收数据)
根据从设备之间是否存在联系,我们可以将SPI的连接方式分为“多NSS形式”和”菊花链形式”。
SPI的第一种连接方式是“多NSS形式”的连接,比如说从设备1是一个AD转换模块,从设备2是一个比较器,设备3是一块液晶,他们之间没有联系,主设备需要操控哪个从设备,就拉低对应NSS上面的信号,使能从设备进行数据转换

SPI协议的第二种形式是菊花链的形式,比如说从设备1是一块EEPROM,从设备2是一个DSP,从设备3是一个比较器,三个从设备之间存在联系,当来自主设备的地址信号到来时,先从EEPROM中读出数据,数据放到DSP中进行处理,处理后的数据,最终在从设备3中进行比较

时钟极性(CPOL)指通讯设备处于空闲状态(SPI开始通讯前、nSS线无效)时,SCK的状态。
| CPOL | 对应电平 |
|---|---|
| 0 | SCK在空闲时为低电平 |
| 1 | SCK在空闲时为高电平 |
这里的CPOL实际上对应于状态机IDLE状态时的SCK的值是0是1,即三段式状态机IDLE时的输出
时钟相位(CPHA)指数据的采样时刻位于SCK的偶数边沿采样还是奇数边沿采样。
| CPHA | 对应电平 |
|---|---|
| 0 | MOSI或MISO数据线上的信号在“奇数边沿”被采样 |
| 1 | MOSI或MISO数据线上的信号在”偶数边沿”被采样 |
举例:假如CPOL = 0时,CPHA=0,对应1,3,5处采样,即为上升沿采样,CPHA=1,对应2,4,6处采样,即为下降沿采样。

这里的CPHA也同样能在状态机的跳变中得到体现,即对应某些状态的采样行为

根据这个图,我们可以发现
Case1:CPOL=0, CPHA=0
Case2:CPOL=1, CPHA=1,Case1和Case2都对应上升沿触发
Case3:CPOL=0, CPHA=1
Case4:CPOL=1, CPHA=0,Case3和Case4都对应下降沿触发
为了保证采样的时候数据稳定,我们还需要做些什么?
我们需要保证采样的时候数据是稳定的,才不会发生建立时间和保持时间的违例,因此,当我们在上升沿的时候进行采样,我们可以在前一个相差半个时钟周期的下降沿,切换数据。
同样,当我们在下降沿的时候进行采样,我们也可以在前一个相差半个时钟周期的上升沿,切换数据,以此来保证采样时的数据稳定性。
有一张非常形象的图片来形容SPI的数据发送与接收,即每当Master发送一位数据的时候,他还会接收到一位数据,因此对于SPI来说,数据传输的本质其实是两个寄存器的移位操作,寄存器的位宽,就是我们所说的数据大小,一般情况下,SPI的数据大小是一个字节或者两个字节(8位或16位)

图片引用自《SPI Block Guide, motorola Inc,14 JUL 2004》
对于全局时钟来讲,频率可能会很高,比如常见的CPU是GHz级别,常见的MCU也有近百MHz级别,但是对于所连接的外设,受限于建立时间和保持时间的限制,可能没有办法跑到MCU主频的级别,因此我们可能需要波特率分频系数来对高速全局时钟进行处理,以此来确保不发生data的violation。
参考作者之前的文章,我们可以获知分频电路的设计方法
【数字IC手撕代码】Verilog奇数分频|题目|原理|设计|仿真
【数字IC手撕代码】Verilog偶数分频|题目|原理|设计|仿真
【数字IC手撕代码】Verilog半整数分频|题目|原理|设计|仿真
【数字IC手撕代码】Verilog小数分频|题目|原理|设计|仿真
以上参数可以保证SPI的基本功能,但一个更为完善的SPI当然不仅限于以上参数,以下参数仅作基本梳理,感兴趣的同学可自行了解相关内容。
SPI_FirstBit,决定SPI是MSB还是LSB的传输形式
SPI_CRCPolynomial,决定SPI是否采用CRC校验的形式进行数据传输
SPI_Direction; 传输方向,两向全双工或单向接收
接下来的文章,我们将从零开始使用Verilog设计一个SPI出来,并进行不那么充分的验证工作,其中SPI具体满足的参数如下
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5
在Ruby中,是否有一种简单的方法可以将n维数组中的每个元素乘以一个数字?这样:[1,2,3,4,5].multiplied_by2==[2,4,6,8,10]和[[1,2,3],[1,2,3]].multiplied_by2==[[2,4,6],[2,4,6]]?(很明显,我编写了multiplied_by函数以区别于*,它似乎连接了数组的多个副本,不幸的是这不是我需要的)。谢谢! 最佳答案 它的长格式等价物是:[1,2,3,4,5].collect{|n|n*2}其实并没有那么复杂。你总是可以使你的multiply_by方法:c
由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0
我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排