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源碼】即可領取資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM