[原创]SPI 协议介绍以及基于 Verilog 的 IP 核实现

最近工程需要使用一款 SPI 协议的芯片,虽说之前也有写过 SPI 从机的 Verilog 实现,但是仍然对 SPI 协议了解的不是很充分,这次详细的了解了下 SPI 协议,并尽最大可能实现了 SPI 的通用 IP 核,但是现有程序缺点是:长度略长,不够精简;优点是易于理解。

SPI协议及其时序

有关SPI协议的资料网络上可不少,一搜一大堆,讲得也都很详细。在这里我推荐。

  • 百科,用于简单直观的了解,由于可以看中文百科,所以阅读起来最直观快捷。
  • 链接:I2C & SPI,本文主要介绍了 I2C 和 SPI 两种协议,还做了一定的优劣对比,其中的 SPI 部分值的研读。当然,本文的译文在网上也是比较轻易找到的,不想看原文的可以找找看。
  • 链接:SPI_Tutorial,这是一个简单的 Tutorial,我只是觉得其中的时序图画的很不错,相对于其他的一些文档易于理解。

SPI(Serial Peripheral Interface),中文为串行外设接口。是一种由摩托罗拉公司开发出来的一种全双工、同步的高速串行总线。其有三线制和四线制两种,下面对其接口各信号来做一个简单的介绍。

  • SCLK:串行设备的时钟,其用于数据信号的同步、传出与采集。
  • CS:片选信号,用于选择使能该 SPI 接口设备。当然其可以为高电平使能或低电平使能,根据器件不同而不同。
  • MOSI:Master output and slave input,主机向从机发送的数据信号。
  • MISO:Master input and slave output,从机向主机发送的数据信号。
  • DIO:用于三线制,是 inout 类型信号,即 MISO 和 MOSI 的结合。

注:三线制中为 SCLK、CS、DIO;四线制中为 SCLK、CS、MISO、MOSI。由于三线制复用了数据线,因此此时其只能工作进行半双工的数据通信。减少了一根数据线于此对应的是吞吐量的下降。

由于 SPI 接口并没有定义数据交换时的通信协议,只是通过 SCLK 与 DIO 来进行高速数据的读写,因此其中为了增加 SPI 的可适用性与兼容性,其有四种工作模式。其中有两个知识点需要讲解一下,一个是 CPLO(clock polarity) 时钟极性,一个是 CPHA(clock phase) 时钟相位,分别可以被设定为 '0'和'1'。其中,

  • CPOL 表示时钟在 SPI 总线空闲时的工作状态
    • '0'表示空闲时 SCLK 为低电平
    • '1'表示空闲时 SCLK 为高电平
  • CPHA 表示在时钟的第几个跳变沿(上升或下降沿)数据可以被采样
    • '0'表示数据在 SCLK 的第一个跳变沿可以被采样
    • '1'表示数据在 SCLK 的第二个跳变沿可以被采样

下表展示了各模式下两个信号的取值。四种模式中,模式 0 是 SPI 协议中使用最广泛的模式。下图展示了各模式下 SPI 总线的时序图(个人感觉这幅图相对于其他的一些更加易于理解)。

| Mode | CPOL | CPHA |
||||
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 2 | 1 | 0 |
| 3 | 1 | 1 |

SPI 时序

基于 Verilog 的 IP 核实现

由于 SPI 总线也是一种通用的数据交换方式,在此为了后续的拓展性方便,想自行设计编写其 IP 核,供自己使用。

根据其时序图,我决定使用状态机来进行实现,将其分为四个状态。大致上如下图所示(以传输 1 个 Byte 数据为例)。

SPI时序状态机
(该图中 clk_in 为模块的输入时钟,SCLK 的频率为 clk_in 的一半。)

  • IDLE:表示空闲状态,此时 SCLK 无效,CS 也无效。
  • CS_N:表示 CS 拉低一定的时间,至少是一个 SCLK 时钟的时间宽度。此时 SCLK 仍然无效,CS 使能。
  • DIO :表示数据传输,其中 SCLK 有效,并且在 SCLK 相应的跳变沿进行数据的采集。CS 保持使能。
  • CS_P:表示表示 CS 拉低一定的时间,至少是一个 SCLK 时钟的时间宽度。此时 SCLK 无效,CS 保持使能。

下面为自己编写的IP核的一些参数和输入输出信号。

| 参数 | 位宽 | 说明 |
|||-|
| C_SPI3 | 1 | 表示 SPI 总线为三线制还是四线制
0:四线制
1:三线制 |
| C_CPOL | 1 | 表示 SPI 总线的 CPOL 属性
0:总线空闲时 SCLK 为低电平
1:空闲时 SCLK 为高电平 |
| C_CPHA | 1 | 表示 SPI 总线的 CPHA 属性
0:表示数据在 SCLK 的第一个跳变沿可以被采样
1:表示数据在 SCLK 的第二个跳变沿可以被采样 |
| C_DATA_LEN | 4 | 表示 SPI 总线传输的数据长度,单位为 Byte |
| C_MSB | 1 | 表示 SPI 总线数据传输时的高低位
0:表示低位在前
1:表示高位在前 |

| 信号 | 位宽 | 方向 | 说明 |
|-||----|-----|
| I_clk | 1 | 输入 | 模块时钟信号 |
| I_rst_n | 1 | 输入 | 模块复位信号,低有效 |
| I_en | 1 | 输入 | 模块使能信号,高使能 |
| O_spi_clk | 1 | 输出 | SPI的时钟信号SCLK |
| O_spi_cs_n | 1 | 输出 | SPI的片选使能信号CSn |
| IO_spi_data | 1 | 双向端口 | SPI的数据信号(三线制) |
| I_tx_flag | 1 | 输入 | SPI的发送信号,高有效 |
| I_tx_data | 由配置决定 | 输入 | SPI的发送数据 |
| I_rx_flag | 1 | 输入 | SPI的接收信号,高有效 |
| O_rx_data | 由配置决定 | 输出 | SPI的接收数据 |
| O_rx_dval | 1 | 输出 | SPI接收数据的数据有效信号,高有效 |

下面直接给出代码的下载链接[点此]好了,其中三线制下模式 0 已经经过验证,其它各种情况还未进行验证,后续验证后将更新文件。

原文地址:https://www.cnblogs.com/airbird/p/11455202.html