zoukankan      html  css  js  c++  java
  • 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数据,因此可以将 Standard-SPI的吞吐率提高3倍。

    SPI 总线四种工作方式

    SPI 在数据传输的时候,需要确定两件事情

    1. 数据是在时钟的上升沿采集还是下降沿采集

    2. 时钟的初始(空闲)状态是为高电平还是低电平

    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

    工程源码获取

    获取资料方法一:集赞

    关注小编公众号后,将本文转发至朋友圈,集齐3个赞,截图发送到后台,小编会在24小时之内回复。备注:【领取SPI源码】即可领取资料

    获取资料方法二:转发群

    关注小编公众号后,将本文转发至不低于100人的群(FPGA相关行业),截图发送到后台,小编会在24小时之内回复。备注:【领取SPI源码】即可领取资料

  • 相关阅读:
    rabbitmq安装详解
    linux下安装rabbitmq的rpm包问题记录
    在 CentOS 6.4上安装Erlang
    redis配置认证密码(转)
    Redis单台的安装部署及主备、哨兵部署
    查看linux系统版本的命令
    Js 实现ajax
    json的相关操作
    Diango思维图
    服务系统 server端
  • 原文地址:https://www.cnblogs.com/xiguazai/p/13353082.html
Copyright © 2011-2022 走看看