SPI协议介绍
一、概述
SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式, 与各种外围设备进行高速数据通信.
SPI 主要应用在 EEPROM, Flash, 实时时钟(RTC), 数模转换器(ADC), 数字信号处理器(DSP) 以及数字信号解码器之间. 它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的 pin 数目, 同时为 PCB 在布局上节省了空间. 正是出于这种简单易用的特性, 现在越来越多的芯片上都集成了 SPI技术。
二、 特点
1. 采用主-从模式(Master-Slave) 的控制方式
SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制次设备 (Slave). 一个 Master 设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI 协议还规定 Slave 设备的 Clock 由 Master 设备通过 SCK 管脚提供给 Slave 设备, Slave 设备本身不能产生或控制 Clock, 没有 Clock 则 Slave 设备不能正常工作.
2. 采用同步方式(Synchronous)传输数据
Master 设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal) , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样, 来保证数据在两个设备之间是同步传输的.
3. 数据交换(Data Exchanges)
SPI 设备间的数据传输之所以又被称为数据交换, 是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 "发送者(Transmitter)" 或者 "接收者(Receiver)". 在每个 Clock 周期内, SPI 设备都会发送并接收一个 bit 大小的数据, 相当于该设备有一个 bit 大小的数据被交换了.
一个 Slave 设备要想能够接收到 Master 发过来的控制信号, 必须在此之前能够被 Master 设备进行访问 (Access). 所以, Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上.
在数据传输的过程中, 每次接收到的数据必须在下一次数据传输之前被采样. 如果之前接收到的数据没有被读取, 那么这些已经接收完成的数据将有可能会被丢弃, 导致 SPI 物理模块最终失效. 因此, 在程序中一般都会在 SPI 传输完数据后, 去读取 SPI 设备里的数据, 即使这些数据(Dummy Data)在我们的程序里是无用的.
SPI优点:支持全双工通信、通信简单、数据传输速率块。缺点:没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据 ,可靠性上有一定的缺陷。
三、结构
SPI包含四根线:
1、SS(Slave Select):片选信号线,当有多个SPI设备与SPI模块相连时,每个设备的这个片选信号线是与不同的ss相连的,而其他SCK,MOSI,MISO线则为多个设备l连接到相同的SPI总线上,当SS信号线为低电平时,片选有效,开始SPI通信
2、SCK(Serial Clock):时钟信号线,由主通信设备产生,不同的设备支持的时钟频率不一样。
3、MOSI(Master Output,Slave Input):主设备输出、从设备输入引脚
4、MISO(Master Input,Slave Output):主设备输入、从设备输出引脚
SPI内部结构如下图:
上图只是对 SPI 设备间通信的一个简单的描述, 下面就来解释一下图中所示的几个组件(Module):
SSPBUF, Synchronous Serial Port Buffer, 泛指 SPI 设备里面的内部缓冲区, 一般在物理上是以 FIFO 的形式, 保存传输过程中的临时数据;
SSPSR, Synchronous Serial Port Register, 泛指 SPI 设备里面的移位寄存器(Shift Regitser), 它的作用是根据设置好的数据位宽(bit-width) 把数据移入或者移出 SSPBUF;
Controller, 泛指 SPI 设备里面的控制寄存器, 可以通过配置它们来设置 SPI 总线的传输模式.
四、时序
上图通过 Master 设备与 Slave 设备之间交换1 Byte 数据来说明 SPI 协议的工作机制.
首先, 在这里解释一下两个概念:
CPOL: 时钟极性, 表示 SPI 在空闲时, 时钟信号是高电平还是低电平. 若 CPOL 被设为 1, 那么该设备在空闲时 SCK 管脚下的时钟信号为高电平. 当 CPOL 被设为 0 时则正好相反.
CPOL = 0: SCK idle phase is low;
CPOL = 1: SCK idle phase is high;
CPHA: 时钟相位, 表示 SPI 设备是在 SCK 管脚上的时钟信号变为上升沿时触发数据采样, 还是在时钟信号变为下降沿时触发数据采样. 若 CPHA 被设置为 1, 则 SPI 设备在时钟信号变为下降沿时触发数据采样, 在上升沿时发送数据. 当 CPHA 被设为 0 时也正好相反.
CPHA = 0: Output data at negedge of clock while receiving data at posedge of clock;
CPHA = 1: Output data at posedge of clock while receiving data at negedge of clock;
上图里的 "Mode 1, 1" 说明了本例所使用的 SPI 数据传输模式被设置成 CPOL = 1, CPHA = 1. 这样, 在一个 Clock 周期内, 每个单独的 SPI 设备都能以全双工(Full-Duplex) 的方式, 同时发送和接收 1 bit 数据, 即相当于交换了 1 bit 大小的数据. 如果 SPI 总线的 Channel-Width 被设置成 Byte, 表示 SPI 总线上每次数据传输的最小单位为 Byte, 那么挂载在该 SPI 总线的设备每次数据传输的过程至少需要 8 个 Clock 周期(忽略设备的物理延迟). 因此, SPI 总线的频率越快, Clock 周期越短, 则 SPI 设备间数据交换的速率就越快.
五、测试
待测试SPI模块地址及寄存器设置:
实现七路SPI,主模式,基地址如下:
SPI0_F_addr<17:2>:0x1d00;
SPI1_F_addr<17:2>:0x1e00;
SPI2_F_addr<17:2>:0x1f00;
SPI3_F_addr<17:2>:0x2000;
SPI4_F_addr<17:2>:0x2100;
SPI5_F_addr<17:2>:0x2200;
SPI6_F_addr<17:2>:0x2300;
偏移地址F_addr<9:2> |
寄存器名称 |
读写属性 |
寄存器功能 |
00H |
数据寄存器RBR |
R |
接收缓冲区,D[15:0],读:接收FIFO数据 |
00H |
数据寄存器TBR |
W |
发送缓冲区,D[15:0],写:发送FIFO数据 |
01H |
中断控制寄存器ICR |
R/W |
D[0]=’1’ 使能接收中断 D[1]=’1’ 使能发送缓冲区空中断 |
02H |
中断状态寄存器ISR |
R/W |
D[0]=’1’ 接收中断有效 D[1]=’1’ 发送缓冲区空中断有效 |
03H |
接收缓冲区数据个数寄存器RBN |
R/W |
只读,D[7:0]接收缓冲区中的数据个数 |
04H |
发送缓冲区数据个数寄存器TBN |
R/W |
只读,发送缓冲区中的数据个数 |
05H |
接收中断条件寄存器RIC |
R/W |
ICR[0]=’1’,且RBN>RIC+1时,ISR[0]会被置位,同时中断输出信号被置位 |
06H |
状态寄存器STR |
R |
D[0]:’1’表示接收缓冲区空 D[1]:’1’表示接收缓冲区满 D[2]:’1’表示接收缓冲区溢出 D[3]:’1’表示发送缓冲区空 D[4]:’1’表示发送缓冲区满 D[5]:’1’表示发送缓冲区溢出 |
07H |
配置寄存器CFR |
R/W |
配置寄存器 D[0]:’1’表示使能发送 D[1]:写’1’表示清空接收缓冲区,读为’0’ D[2]:写’1’表示清空发送缓冲区,读为’0’ D[4]:’1’SPI时钟相位寄存器CPHA设置位,‘1’表示在时钟第2个跳变沿采样数据,‘0’表示在时钟第1个跳变沿采样数据 D[7]:‘1’表示拓展配置模式,‘0’表示非拓展配置模式 |
- //test SPI module 2019.03.11 zhou
- //7路 SPI
- spi_slave u0_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- spi_slave u1_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- spi_slave u2_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- spi_slave u3_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- spi_slave u4_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- spi_slave u5_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- spi_slave u6_spi_slave(~F_spi_ss[], F_spi_sdo[], F_spi_sdi[],F_spi_sclk[]);
- task CPU_READ_SPI_FIFO;
- input [:] addr;
- output [:] rddata;
- begin
- #120ns
- @(posedge S_cpu_clk)
- F_nrd = 'b1;
- F_nwr = 'b1;
- F_ncs = 'b1;
- F_addr =addr;
- @(posedge S_cpu_clk)
- F_nrd = 'b0;
- F_nwr = 'b1;
- F_ncs = 'b0;
- F_addr =addr;
- @(posedge S_cpu_clk)
- wait (F_nrdy==);
- # //one clock delay then read
- rddata = F_data_o;
- @(posedge S_cpu_clk)
- F_nrd = 'b1;
- F_nwr = 'b1;
- F_ncs = 'b1;
- F_addr =;
- end
- endtask
- task TEST_CASE_SPI;
- logic [:] spi_reg;
- logic [:] spi_rec_data;
- logic [:] addr;
- int i,spi_rec_fifonum;
- begin
- RST_ASIC();
- $display("Testing SPI 0-6...");
- for(addr = 'h1d00;addr <= 16'h2300;addr += 'h0100)
- begin
- //寄存器复位值自检
- CPU_READ(addr+'h01,spi_reg); //ICR 0
- if(spi_reg != 'h0000) $display("%h:ICR error:%h(0x0000)",addr,spi_reg);
- CPU_READ(addr+'h02,spi_reg); //ISR 0
- if(spi_reg != 'h0000) $display("%h:ISR error:%h(0x0000)",addr,spi_reg);
- CPU_READ(addr+'h03,spi_reg); //RBN 0
- if(spi_reg != 'h0000) $display("%h:RBN error:%h(0x0000)",addr,spi_reg);
- CPU_READ(addr+'h04,spi_reg); //TBN 0
- if(spi_reg != 'h0000) $display("%h:TBN error:%h(0x0000)",addr,spi_reg);
- CPU_READ(addr+'h05,spi_reg); //RIC 0
- if(spi_reg != 'h0000) $display("%h:RIC error:%h(0x0000)",addr,spi_reg);
- CPU_READ(addr+'h06,spi_reg); //STR 09
- if(spi_reg != 'h0009) $display("%h:STR error:%h(0x0009)",addr,spi_reg);
- CPU_READ(addr+'h07,spi_reg); //CFR 0
- if(spi_reg != 'h0000) $display("%h:CFR error:%h(0x0000)",addr,spi_reg);
- //写SPI的配置寄存器
- CPU_WRITE(addr+'h07,8'h06); //clear fifo
- CPU_WRITE(addr+'h07,8'h01); //enable sending
- //向发送缓冲寄存器写数据
- CPU_WRITE(addr+'h00,16'h7654);
- CPU_WRITE(addr+'h00,16'h3210);
- #10us;
- //接收数据
- CPU_READ(addr+'h03,spi_rec_fifonum);
- for(i = ; i < spi_rec_fifonum;i++)
- begin
- CPU_READ_SPI_FIFO(addr+'h00,spi_rec_data);
- $display("spi_rec_data:%h",spi_rec_data);
- end
- end //end for
- $display("Testing SPI Sending & Receiving is Finished!");
- end
- endtask
SPI测试代码
- `timescale 1ns/10ps
- module spi_slave( ncs, mosi, miso, sck);
- input ncs, mosi, sck;
- output miso;
- reg nrst;
- initial
- begin
- nrst=;
- # //related to the number of data
- nrst=;
- end
- //SPI接收状态机
- reg[:] byte_received;
- reg[:] bit_received_cnt;
- reg[:] rec_data;
- always @ (negedge nrst or posedge sck) //每次sck都会接收数据,spi的顶端模块状态机决定是否取用
- begin
- if(~nrst)
- begin
- byte_received <= 'h0000;
- bit_received_cnt <= 'h0;
- end
- else
- begin
- if(~ncs)
- begin
- byte_received = {byte_received[:], mosi};
- if(bit_received_cnt == 'hF)
- begin
- rec_data = byte_received;
- $display("spi_test_outer_module received data 0x%h at %t",rec_data,$time);
- bit_received_cnt = 'h0;
- end
- else bit_received_cnt = bit_received_cnt + ;
- end
- end
- end
- //SPI发送状态机
- reg miso;
- reg[:] byte_sended; //发送移位寄存器
- reg[:] bit_sended_cnt; //SPI发送位计数器
- always @ (negedge nrst)
- begin
- if(~nrst)
- begin
- byte_sended <= 'h89ab;
- bit_sended_cnt <= ;
- end
- end
- always @ (negedge sck or negedge ncs)
- begin
- if(~ncs && nrst)
- begin
- miso = byte_sended[];
- byte_sended = {byte_sended[:],'b0};
- if(bit_sended_cnt == 'hF)
- begin
- byte_sended <= 'hcdef;
- bit_sended_cnt <= ;
- end
- else bit_sended_cnt += ;
- end
- end
- endmodule
SPI简易从模块代码
测试结果
SPI协议介绍的更多相关文章
- [SPI&I2C]I2C和SPI协议介绍
IIC vs SPI 现今,在低端数字通信应用领域,我们随处可见IIC (Inter-Integrated Circuit) 和 SPI (Serial Peripheral Interface)的身 ...
- SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)
SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...
- SPI协议及IO模拟
SPI协议 SPI协议网上资料比较多,但是也比较乱,当初在网上搜集的错误资料导致现在比较混乱. SPI协议资料比较正规的是: 1.SPI的规约协议英文文档,例如<摩托罗拉spi协议规范> ...
- FPGA作为从机与STM32进行SPI协议通信---Verilog实现 [转]
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...
- 模拟SPI协议时序
SPI是串行外设接口总线,摩托罗拉公司开发的一种全双工,同步通信总线,有四线制和三线制. 在单片机系统应用中,单片机常常是被用来当做主机(MASTER),外围器件被当做从机(SLAVE). 所以,在以 ...
- FPGA作为从机与STM32进行SPI协议通信---Verilog实现
一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...
- [SPI]SPI协议详解
转自:https://my.oschina.net/freeblues/blog/67400 1.SPI协议简介 1.1.SPI协议概括 SPI,是英语Serial Peripheral interf ...
- SPI协议及工作原理分析
说明.文章摘自:SPI协议及其工作原理分析 http://blog.csdn.net/skyflying2012/article/details/11710801 一.概述. SPI, Serial ...
- TCP/IP 协议介绍
转自http://blog.jobbole.com/104886/ 一.TCP/IP 协议介绍 在介绍 HTTP 协议之前,先简单说一下TCP/IP协议的相关内容.TCP/IP协议是分层的,从底层至应 ...
随机推荐
- 八. 输入输出(IO)操作1.输入输出基本概念
输入输出(I/O)是指程序与外部设备或其他计算机进行交互的操作.几乎所有的程序都具有输入与输出操作,如从键盘上读取数据,从本地或网络上的文件读取数据或写入数据等.通过输入和输出操作可以从外界接收信息, ...
- SQLServer To MySQL 解决方案
最近在忙一个项目,就不详写了.过两天不忙了把项目总结一下. 思路: Access作为桥梁 1.SQLServer To Access 2007 在access里直接导入 2.Use t ...
- 在Spring MVC Controller中注入HttpServletRequest对象会不会造成线程安全的问题
做法: 1.比如我们在Controller的方法中,通常是直接将HttpServletRequest做为参数,而为了方便节省代码,通常会定义为全局变量,然后使用@Autowire注入. 说明: 1.观 ...
- delphi 设置开机自动启动函数
有些程序要设置为开机启动,所以自己写了个函数方便以后使用,供大家参考 procedure TMainForm.SetAutoRun(ok: boolean); var Reg:TRegistry; ...
- openfire源码修改后如何打包部署到linux服务器上
原文:http://blog.csdn.net/jinzhencs/article/details/50457152 1.linux版本的3.10.3解压部署启动(过程略,参考我的另一篇博文http: ...
- Overview of iOS Crash Reporting Tools: Part 1/2
Believe it or not, developers are not perfect, and every once in a while you might have a (gasp!) bu ...
- 【SVN】删除SVN上的历史资源路径和SVN上的历史用户信息
1.删除svn上历史资源路径 window--show view--other--svn资源库 可以右键选择删除 . ----------------------------------------- ...
- kubernetes1.5.2--部署dashboard服务
本文基于kubernetes 1.5.2版本编写 使用http方式访问api server的部署 cat dashboard-controller.yaml apiVersion: extension ...
- A folder failed to be renamed or moved--安装Android SDK的问题
对于Android是一直想学却一直未学,行动跟不上想法.现在,终于付诸于行动了. 首先,我找的第一个Android的资料是大话企业级Android,前阵子刚看完大话设计模式,通俗易懂,还是比较喜欢这一 ...
- selenium 自动化测试 测试报告 生成
https://www.cnblogs.com/yoyoketang/p/6140439.html https://www.cnblogs.com/testyao/p/5658200.html 一.下 ...