SPI接口电路的学习

1、SPI接口电路原理

SPI, Serial Perripheral Interface, 串行外围设备接口, 是Motorola 公司推出的一种同步串行接口技术。 SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式, 与各种外围设备进行高速数据通信。

SPI 主要应用在EEPROM, Flash, 实时时钟(RTC), 数模转换器(ADC),
数字信号处理器(DSP) 以及数字信号解码器之间。 它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的 pin 数目, 同时为 PCB 在布局上节省了空间. 正是出于这种简单易用的特性, 现在越来越多的芯片上都集成了 SPI技术。

特点

①采用主-从模式(Master-Slave)的控制方式:

  • SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制次设备 (Slave). 一个 Master
    设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI
    协议还规定 Slave 设备的 Clock 由 Master 设备通过SCK 管脚提供给 Slave 设备, Slave
    设备本身不能产生或控制 Clock, 没有 Clock 则Slave 设备不能正常工作。

②采用同步方式(Synchronous)传输数据:

  • Master 设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal)
    , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样,
    来保证数据在两个设备之间是同步传输的。

③数据交换(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设备的四个信号:

Serial Clock, 主要的作用是 Master 设备往 Slave 设备传输时钟信号, 控制数据交换的时机以及速率;

SS/CS, Slave Select/Chip Select, 用于 Master 设备片选
Slave 设备, 使被选中的 Slave 设备能够被 Master 设备所访问;

SDO/MOSI, Serial Data Output/Master Out Slave In, 在 Master 上面也被称为Tx-Channel, 作为数据的出口, 主要用于 SPI 设备发送数据;

SDI/MISO, Serial Data Input/Master In Slave Out, 在 Master 上面也被称为
Rx-Channel, 作为数据的入口, 主要用于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;

在主设备这边配置SPI接口时钟的时候一定要弄清楚从设备的时钟要求,因为主设备这边的时钟极性和相位都是以从设备为基准的。因此在时钟极性的配置上一定要搞清楚从设备是在时钟的上升沿还是下降沿接收数据,是在时钟的下降沿还是上升沿输出数据。但要注意的是,由于主设备的SDO连接从设备的SDI,从设备的SDO连接主设备的SDI,从设备SDI接收的数据是主设备的SDO发送过来的,主设备SDI接收的数据是从设备SDO发送过来的,所以主设备这边SPI时钟极性的配置(即SDO的配置)跟从设备的SDI接收数据的极性是相反的,跟从设备SDO发送数据的极性是相同的。

当从机增多时我们可以采用芯片来进行辅助控制。

③数据传输:

在一个SPI时钟周期内,会完成如下操作:

1)主机通过MOSI线发送1位数据,从机通过该线读取这1位数据;

2)从机通过MISO线发送1位数据,主机通过该线读取这1位数据。

这是通过移位寄存器来实现的。如下图所示,主机和从机各有一个移位寄存器,且二者连接成环。随着时钟脉冲,数据按照从高位到低位的方式依次移出主机寄存器和从机寄存器,并且依次移入从机寄存器和主机寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。

(4)Slave从机的实现:

SPI接口一端的信号有选通信号cs, 串行输入时钟信号sclk, 串行输入数据信号sdi, 串行输出数据信号sdo。它另一端与存储器进行连接,这端的信号有读写控制信号wr_rd, 读写地址信号addr,写数据并行输出信号dataout,
读数据并行输入信号datain。

SPI接口一端的信号中,串行输入数据信号sdi和串行输出数据信号sdo可以进行复用,即共用一个信号SDIO,此时称为三线制的SPI接口。下面是三线制SPI接口的示意波形。为了描述方便,我们往往用四线制的SPI接口,即SPI接口一端的信号有选通信号cs, 串行输入时钟信号sclk, 串行输入数据信号sdi, 串行输出数据信号sdo等共4根信号线。


写操作

读操作

2、仿真测试

本次使用的软件还是Quartus,由于前一周已经详细了解过了,所以这里就不演示每一步的创建过程了,主要侧重于代码的实现及仿真结果的分析。

(1) 假设某阶段SPI一端的端口信号在一个传输周期共传输24bit信息,其中16比特是指令信息,8比特是数据信息。第一个比特为1表示写操作,否则为读操作。

module spi (reset, cs, sclk, sdi, sdo,wr_rd, addr, rdata, wdata);
input     reset;
input           cs;
input          sclk;
input          sdi;
output        sdo;
output         wr_rd;
output  [14:0]  addr;
input   [7:0]   rdata;
output  [7:0]   wdata;
reg     [ 2:0] cnt_bit;always @(posedge sclk or negedge reset)if (!reset)cnt_bit <= 3'b0;else if (!cs)
cnt_bit <= cnt_bit + 3'b1;
elsecnt_bit <= 3'b0;wire   cnt_full;assign     cnt_full = (cnt_bit==3'd7);parameter IDLE    = 2'd0;   //初始状态parameter INSTR_H = 2'd1;    //接收指令16比特中的高8位比特状态parameter INSTR_L = 2'd2;    //接收指令16比特中的低8位比特状态parameter DATA    = 2'd3;   //传输8比特数据状态reg     [ 1:0] current_state, next_state;always @(posedge sclk or negedge reset)if (!reset)current_state <= IDLE;else if (cs)current_state <= IDLE;elsecurrent_state <= next_state;always @(*)begincase (current_state)IDLE: beginif (cs)next_state = IDLE;elsenext_state = INSTR_H;endINSTR_H : beginif (cnt_full)next_state = INSTR_L;elsenext_state = INSTR_H;endINSTR_L : beginif (cnt_full)next_state = DATA;else
next_state = INSTR_L
endDATA : begin
if (cs)
next_state = IDLE;
else
next_state = DATA;
end
default: next_state = IDLE;endcaseend
reg     [15:0] shift_reg_din;always @(posedge sclk or negedge reset)if (!reset)
shift_reg_din <= 15'd0;else if (cs)
shift_reg_din <= 15'd0;
elseshift_reg_din <= {shift_reg_din[14:0],sdi};wire    cstate;
assign      cstate = (current_state==INSTR_L);reg     cnt_full_d, cstate_d;
always @(posedge sclk or negedge reset)if (!reset)
begin
cnt_full_d <= 0;cstate_d <= 0;end
else begincnt_full_d <= cnt_full;cstate_d <= cstate;endreg      [14:0]  addr;always @(negedge sclk or negedge reset)if (!reset)addr <= 15'd0;
else if (cnt_full_d && cstate_d)//表示地址读取完了addr <= shift_reg_din[14:0];//将15位地址赋值给addr
elseaddr <= addr;reg               wr_rd;//写相对于spi来说是输出
always @(negedge sclk or negedge reset)if (!reset)
wr_rd <= 1'b0;
else if (cnt_full_d && cstate_d)wr_rd <= shift_reg_din[15];//地址读取完后将最高位赋值给写,若为1则表明是进行写操作reg      [7:0]  wdata;always @(posedge cs or negedge reset)if (!reset)wdata <= 8'd0;elsewdata <= shift_reg_din[7:0];reg    [ 7:0] shift_reg_dout;always @(negedge sclk or negedge reset)if (!reset)shift_reg_dout <= 8'b0;else if ((cnt_bit==3'd0) && (current_state==DATA))shift_reg_dout <= rdata;else shift_reg_dout <= {shift_reg_dout[6:0],1'b0};//串行输出assign sdo  = ((!wr_rd)&&(!cs)) ?
shift_reg_dout[7] : 1'b0;endmodule

测试激励如下:

module spi_tb();
reg    reset;
reg  cs  ;
reg  sclk;
reg  sdi  ;
wire sdo  ;
reg   [7:0]   rdata;
wire    wr_rd ;
wire    [14:0]  addr;
wire  [7:0]   wdata;spi u0(reset, cs, sclk, sdi, sdo, wr_rd,addr, rdata, wdata);always  #5sclk=~sclk;initial begin   sclk = 0;reset=0; cs = 1;sdi = 0;rdata=8'b00001111;#27 reset=1;#14 cs = 0;sdi = 1;
//写操作repeat(1) @(negedge sclk);sdi = 0;repeat(11) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(1) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(2) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(1) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(1) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(1) @(negedge sclk);sdi = 1;#11 cs = 1;//-------以上完成一个写传输操作---------repeat(5) @(negedge sclk);cs = 0;sdi = 0;
//读操作repeat(1) @(negedge sclk);sdi = 0;repeat(11) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(1) @(negedge sclk);sdi = 1;repeat(1) @(negedge sclk);sdi = 0;repeat(1) @(negedge sclk);sdi = 1'bz;
repeat(7) @(negedge sclk);
#11 cs = 1;
//-------以上完成一个读传输操作---------
#200
$stop;

仿真结果:

基于Verilog的SPI接口设计相关推荐

  1. 基于verilog贪吃蛇游戏设计

    概述 基于verilog贪吃蛇游戏设计.使用verilog语言 小游戏主要分为以下几个模块:顶层模块.VGA显示模块.蛇身控制模块.苹果控制模块. 系统主要分为顶层模块.VGA显示模块.蛇身控制模块. ...

  2. 基于FPGA实现SPI接口(配置或通信)

    基于FPGA实现SPI接口(配置或通信总线) 1)总线简介 串行外设接口(SPI)是微控制器(FPGA)和外围IC(如传感器.ADC.DAC.移位寄存器.SRAM等)之间使用最广泛的接口之一.主要用于 ...

  3. (50)Verilog HDL SPI发送设计

    (50)Verilog HDL SPI发送设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL SPI发送设计 5)结语 1.2 FPGA简介 F ...

  4. (49)Verilog HDL SPI接收设计

    (49)Verilog HDL SPI接收设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL SPI接收设计 5)结语 1.2 FPGA简介 F ...

  5. 基于 SoC 的卷积神经网络车牌识别系统设计(4-2)基于 Verilog 的 RGB2HSV IP 设计

    引言         这是车牌识别预处理(RGB2HSV + 二值化 + 形态学)的 IP 设计之一.主要功能是针对从 OV5640 IP 输出的 RGB888 真彩色车牌识别数据(视频传输格式:64 ...

  6. 基于 SoC 的卷积神经网络车牌识别系统设计(4-3)基于 Verilog 的 HSV2Binary IP 设计

    引言         这是车牌识别预处理(RGB2HSV + 二值化 + 形态学)的 IP 设计之一.主要功能是针对从 RGB2HSV IP 的输出数据转换成 Binary 二值化格式的数据,为之后的 ...

  7. 基于FPGA的VGA接口设计(三)

    关于VGA系列文章的所有链接: 基于FPGA的VGA接口设计(一) 基于FPGA的VGA接口设计(二) 基于FPGA的VGA接口设计(三) 结篇   在之前的文章中介绍了有关VGA的扫描方式.行场同步 ...

  8. 基于Verilog的跑马灯设计

    基于Verilog的跑马灯设计 一.设计要求 二.设计思路 1. 总体框图 2. 按功能模块的分模块结构图 3. 状态图 三.代码实现 1. Verilog代码 2. Testbench关键代码 3. ...

  9. ft232h引脚_基于FT232R的USBUART接口设计.pdf

    基于FT232R的USBUART接口设计 b舶≤≯----------.. [摘要] 鉴于PC机USB接口的通用性以及充分发挥USB/ 基于FT232R桥接芯片开发USB/UART接口是一种较为简 便 ...

最新文章

  1. php的基本语法和数据类型
  2. 腾讯获赔 475 万!首例“微信自动抢红包”不正当竞争案宣判
  3. 开源 | App 开发神仙工具:帮你抓 Bug
  4. Java迭代器contains的问题
  5. jQuery实现表格隔行换颜色:
  6. python concat_python的concat等多种用法详解
  7. 接管客厅第一步:联想智能音箱体验评测
  8. 7.大数据架构详解:从数据获取到深度学习 --- 批处理技术
  9. 1.Jenkins 安装
  10. pytorch中torch.max和F.softmax函数的维度解释
  11. 利用python调用谷歌翻译API
  12. python贝叶斯网络预测模型_概率图模型之:贝叶斯网络
  13. vue-JsMind思维导图实现(包含鼠标右键自定义菜单)
  14. 对封装的ajax的应用-查询商铺
  15. U盘做系统时如何设置USB为第一启动盘
  16. ABAQUS如何输出应力应变曲线(XY曲线)
  17. iOS基础——通过案例学知识之UITableView
  18. 微型计算机原理第二章作图题,工程制图第二章习题答案解析.doc
  19. 全志R16_Camera支持列表芯片资料(Allwinner R16 Camera Support List)
  20. 中国超算行业投资模式分析及发展规划建议报告2022-2028年版

热门文章

  1. Tasks Assessing Protein Embeddings (TAPE)
  2. STL之queque队列
  3. A Little Love
  4. 快速复制浏览器控制台接口传参数据的小技巧
  5. 关于在Fragment下onActivityResult回调无结果的问题
  6. 智慧治理 成都郫都区创新城市发展管理的有效抓手
  7. 雷军对待华为鸿蒙系统有什么看法,鸿蒙OS太诱人?魅族和雷军遭遇道德绑架,米粉回击:想用买华为去...
  8. ACM-ICPC 2018 北京网络赛:K-Dimensional Foil II
  9. [2018北京ICPC网络赛H] HihoCoder - 1835 K-Dimensional Foil II(点到平面的距离)
  10. CTU Open Contest 2017