SPI
SPI 简介
SPI全称为Seriel Peripheral Interface (串行外设接口),是 MCU 中常用的外设接口。SPI 通信原理很简单,它是以主从方式进行工作,通常有一个主设备和一个或多个从设备,至少需要4根线(支持全双工)工作,分别为 MISO(主入从出),MOSI(主出从入),SCLK(时钟),SS(片选)。
Standard-SPI
基本的 SPI 协议也被称为 Standard-SPI,Standard-SPI 是串行通信协议,数据是逐位进行传输,在 SCLK 的边沿进行 MOSI 和 MISO 的传输。数据输出通过 MOSI 线进行传输,数据在时钟上升沿或者下降沿改变,在紧接着的下降沿或者上升沿被采样完成一位数据传输,输入同理。
Dual-SPI
由于在实际应用中较少使用全双工模式,因此为了能够充分利用数据线,引入了 Dual-SPI 和 Quad-SPI ,在 Dual-SPI 协议中,MOSI、MISO 数据线被重命名为 SD0、SD1 ,变为既可以输入也可以输出的 inout 信号。
Dual-SPI 由于同时使用两根数据线进行传输,一个时钟周期可以传输2 bit数据,因此可以将 Standard-SPI的吞吐率提高一倍。
Quad-SPI
Quad-SPI 是在 Dual-SPI 的基础上再添加了两根数据线,所以数据线变为了SD0、SD1、SD2、SD3。
Quad-SPI 由于同时使用四根数据线进行传输,一个时钟周期可以传输4 bit数据,因此可以在 Dual-SPI 基础上将吞吐率提高一倍。
SPI 总线四种工作方式
SPI 在数据传输的时候,需要确定两件事情
- 数据是在时钟的上升沿采集还是下降沿采集
- 时钟的初始(空闲)状态是为高电平还是低电平
CPOL:时钟极性, 表示 SPI 在空闲时, 时钟信号是高电平还是低电平。
CPHA:时钟相位, 表示 SPI 设备是在 SCK 管脚上的时钟信号变为上升沿时触发数据采样, 还是在时钟信号变为下降沿时触发数据采样。
那么CPOL 有两种可能,CPHA 有两种可能,则 SPI 传输就有四种模式。
传输方式 |
描述 |
---|---|
方式1 |
CPOL= 0,CPHA=0。SCK串行时钟线空闲是为低电平,数据在SCK时钟的上升沿被采样,数据在SCK时钟的下降沿切换 |
方式2 |
CPOL= 0,CPHA=1。SCK串行时钟线空闲是为低电平,数据在SCK时钟的下降沿被采样,数据在SCK时钟的上升沿切换 |
方式3 |
CPOL= 1,CPHA=0。SCK串行时钟线空闲是为高电平,数据在SCK时钟的下降沿被采样,数据在SCK时钟的上升沿切换 |
方式4 |
CPOL= 1,CPHA=1。SCK串行时钟线空闲是为高电平,数据在SCK时钟的上升沿被采样,数据在SCK时钟的下降沿切换 |
SPI通信协议
通讯的起始信号:SS 信号线由高变低,是 SPI 通讯的起始信号。SS 是每个从机各自独占的信号线,当从机在自己的 SS 线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。
通讯的停止信号:SS 信号由低变高,是 SPI 通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。
数据有效性:SPI 使用 MOSI 及 MISO 信号线来传输数据,使用 SCLK 信号线进行数据同步。MOSI 及 MISO 数据线在 SCLK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。数据传输时,MSB 先行或 LSB 先行并没有作硬性规定,但要保证两个 SPI 通讯设备之间使用同样的协定,一般采用 MSB 先行的方式。
_ _ _ _ _ _ _ _ _
inClk _/ _/ _/ _/ _/ _/ ....._/ _/ _/ _
___ _____
inReset_EnableB _________________________________/
_____ ___
outSpiCsB _________________________________/
_______ ___
inData8Send[7:0] _______XD8SXXX...
___ ___ ___ ___ _________
inSpiMosi XD7_XD6_XD5_X.....XD0_X_________
___________ _ _ _ _ ___________
outSpiClk _/ _/ _/ ....._/
___________
outData8Receive[7:0] XD8SX XXXD8R*D8SX___
image
FPGA 程序实现
一个用了好多年的 SPI 程序,很健壮,小编抛出来。
library ieee;
--Library UNISIM;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
--use UNISIM.vcomponents.all;
entity SpiSerDes is
port
(
-- SerDes clock and control signals
inClk : in std_logic; -- System clock. Fmax <= SPI peripheral Fmax.
inReset_EnableB : in std_logic; -- Active-high, synchronous reset.
inStartTransfer : in std_logic; -- Active-high, initiate transfer of data
outTransferDone : out std_logic; -- DONE='1' when transfer is done
-- Parallel data ports
inData8Send : in std_logic_vector(7 downto 0); -- Sent to SPI device
outData8Receive : out std_logic_vector(7 downto 0); -- Received from SPI device
-- SPI ports and tristate control - Connect these to the SPI bus
outSpiCsB : out std_logic; -- SPI chip-select to SPI device
-- or all SPI outputs control enable
outSpiClk : out std_logic; -- SPI clock to SPI device
outSpiMosi : out std_logic; -- SPI master-out, slave-in to SPI device
inSpiMiso : in std_logic -- SPI master-in, slave-out from SPI device
);
end SpiSerDes;
architecture behavioral of SpiSerDes is
-- Constants
constant cShiftCountInit : std_logic_vector(8 downto 0) := B"000000001";
-- Registers
signal regShiftCount : std_logic_vector(8 downto 0) := cShiftCountInit;
signal regShiftData : std_logic_vector(7 downto 0) := B"00000000";
signal regSpiCsB : std_logic := '1';
signal regSpiMosi : std_logic := '1';
signal regTransferDoneDelayed : std_logic := '1';
-- Signals
signal intTransferDone : std_logic;
-- Attributes
attribute clock_signal : string;
attribute clock_signal of inClk : signal is "yes";
begin
-- Internal signals
intTransferDone <= regShiftCount(0);
-- TransferDone delayed by half clock cycle
processTransferDone : process (inClk)
begin
if (falling_edge(inClk)) then
regTransferDoneDelayed <= intTransferDone;
end if;
end process processTransferDone;
-- SPI chip-select (active-Low) is always inverse of inReset_EnableB.
processSpiCsB : process (inClk)
begin
if (rising_edge(inClk)) then
regSpiCsB <= inReset_EnableB;
end if;
end process processSpiCsB;
-- Track transfer of serial data with barrel shifter.
processShiftCount : process (inClk)
begin
if (rising_edge(inClk)) then
if (inReset_EnableB='1') then
regShiftCount <= cShiftCountInit;
elsif ((intTransferDone='0') or (inStartTransfer='1')) then
-- Barrel shift (rotate right)
regShiftCount <= regShiftCount(0) & regShiftCount(8 downto 1);
end if;
end if;
end process processShiftCount;
-- Simultaneous serialize outgoing data & deserialize incoming data. MSB first
processShiftData : process (inClk)
begin
if (rising_edge(inClk)) then
if (intTransferDone='0') then
-- SHIFT-left while not outTransferDone
regShiftData <= regShiftData(6 downto 0) & inSpiMiso;
elsif (inStartTransfer='1') then
-- Load data to start a new transfer sequence from a done state
regShiftData <= inData8Send;
end if;
end if;
end process processShiftData;
-- SPI MOSI register outputs on falling edge of inClk. MSB first.
processSpiMosi : process (inClk)
begin
if (falling_edge(inClk)) then
if (inReset_EnableB='1') then
regSpiMosi <= '1';
elsif (intTransferDone='0') then
regSpiMosi <= regShiftData(7);
end if;
end if;
end process processSpiMosi;
-- Assign outputs
outSpiClk <= (inClk or intTransferDone or regTransferDoneDelayed);
outSpiCsB <= regSpiCsB;
outSpiMosi <= regSpiMosi;
outTransferDone <= intTransferDone;
outData8Receive <= regShiftData;
end behavioral;
假设上升沿发送、下降沿接收、高位先发送。
假设主机8位寄存器装的是待发送的数据10101010
参考链接
https://blog.csdn.net/weiqifa0/article/details/82765892
https://mp.weixin.qq.com/s/h1xco58oRDbIq8z3zaP_pA
- springboot的Web开发-Web相关配置
- Centos7下yum安装配置nginx与php
- CentOS7安装MySQL
- 分布式系统唯一ID生成方案汇总
- 操作系统底层技术——CPU亲和性
- AngularJS例子 ng-repeat遍历输出 通过js的splice方法删除当前行
- mongoDB报错Cannot find module '../build/Release/bson'
- 计算机视觉处理三大任务:分类、定位和检测
- Windows下RabbitMQ安装及入门
- 计算机视觉任务:图像梯度和图像完成
- Yarn【label-based scheduling】实战总结(一)
- 配置sonarqube+maven
- Yarn【label-based scheduling】实战总结(二)
- HDFS学习:HDFS机架感知与副本放置策略
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- git文件管理心得分享
- Linux如何实现断点续传文件功能
- Xshell实现Windows上传文件到Linux主机的方法
- Linux中的EXT系列文件系统格式详解
- Linux中hexdump命令用法
- CentOS7挂载新数据盘的完整步骤
- Linux下安装Keepalived及原理分析
- centos6搭建gitlab的方法步骤
- Linxu服务器上安装JDK 详细步骤
- linux 不改变目录结构移动 home 目录到新分区的操作方法
- ubuntu14.04安装opencv3.0.0的操作方法
- Linux中让alias设置永久生效的方法详解
- Centos系统下“无法打开并写入文件”问题的解决
- 如何在Linux下设置录音笔时间
- Linux下ZooKeeper分布式集群安装教程