Advertisement
runsiv

spi_inf

May 22nd, 2015
572
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VHDL 9.54 KB | None | 0 0
  1. ----------------------------------------------------------------------------------
  2. ----------------------------------------------------------------------------
  3. -- Author:  Albert Fazakas
  4. --          Copyright 2014 Digilent, Inc.
  5. ----------------------------------------------------------------------------
  6. --
  7. -- Create Date:    17:55:33 02/17/2014
  8. -- Design Name:
  9. -- Module Name:    SPI_If - Behavioral
  10. -- Project Name:
  11. -- Target Devices:
  12. -- Tool versions:
  13. -- Description:
  14. --       This module represents an SPI controller. The controller transfers 8 bits of data, MSB first.
  15. --    Data is read on the positive edge of SCLK and also stable on the positive edge of SCLK.
  16. --    When there is no data transfer, SCLK = 0, therefore CPOL = 0, CPHA = 0.
  17. --       Data transfer starts by activating the "Start" signal, and, when data transfer is done, the
  18. --    "Done" signal is activated for one SYSCLK period.
  19. --
  20. --       The module is also capable to transfer multiple bytes, if the "HOLD_SS" signal is active.
  21. --    In this case SS is not raised between byte transfers and a new transfer can begin
  22. --    if the "Start" signal is activated. This feature is used in conjunction with the ADXL 362 accelerometer
  23. --    or any device which needs multiple-byte transfers for sending commands and/or reading data
  24. --
  25. -- Revision:
  26. -- Revision 0.01 - File Created
  27. -- Additional Comments:
  28. --
  29. ----------------------------------------------------------------------------------
  30. library IEEE;
  31. use IEEE.STD_LOGIC_1164.ALL;
  32.  
  33. -- Uncomment the following library declaration if using
  34. -- arithmetic functions with Signed or Unsigned values
  35. --use IEEE.NUMERIC_STD.ALL;
  36.  
  37. -- Uncomment the following library declaration if instantiating
  38. -- any Xilinx primitives in this code.
  39. --library UNISIM;
  40. --use UNISIM.VComponents.all;
  41.  
  42. entity SPI_If is
  43. generic
  44. (
  45.    SYSCLK_FREQUENCY_HZ : integer:= 100000000;
  46.    SCLK_FREQUENCY_HZ : integer:= 1000000
  47. );
  48. port
  49. (
  50.  SYSCLK     : in STD_LOGIC; -- System Clock
  51.  RESET      : in STD_LOGIC;
  52.  Din        : in STD_LOGIC_VECTOR (7 downto 0); -- Data to be transmitted
  53.  Dout       : out STD_LOGIC_VECTOR (7 downto 0); -- Data received;
  54.  Start      : in STD_LOGIC; -- used to start the transmission
  55.  Done       : out STD_LOGIC; -- Signaling that transmission ended
  56.  HOLD_SS   : in STD_LOGIC; -- Signal that forces SS low in the case of multiple byte
  57.                            -- transmit/receive mode
  58.  --SPI Interface Signals
  59.  SCLK       : out STD_LOGIC;
  60.  MOSI       : out STD_LOGIC;
  61.  MISO       : in STD_LOGIC;
  62.  SS         : out STD_LOGIC
  63. );
  64. end SPI_If;
  65.  
  66. architecture Behavioral of SPI_If is
  67.  
  68. -- Determine the division rate in order to create the 2X SCLK tick
  69. constant DIV_RATE : integer := ((SYSCLK_FREQUENCY_HZ / ( 2 * SCLK_FREQUENCY_HZ)) - 1);
  70.  
  71. -- To generate the 2X SCLK tick, then SCLK
  72. signal SCLK_2X_DIV      : integer range 0 to DIV_RATE := 0;
  73. signal SCLK_2X_TICK     : STD_LOGIC := '0';
  74. -- Internal SCLK signal
  75. signal SCLK_INT         : STD_LOGIC := '0';
  76.  
  77. -- Enable Output Signals
  78. signal EN_SCLK    : STD_LOGIC := '0';
  79. signal EN_SS      : STD_LOGIC := '0';
  80.  
  81. -- Control Signals
  82. signal EN_SHIFT      : STD_LOGIC := '0';  -- Enable shifting the MOSI_REG and MISO_REG registers
  83. signal EN_LOAD_DOUT  : STD_LOGIC :='0';   -- Enable loading the Dout register
  84.                                           -- from the shift register for MISO
  85. signal EN_LOAD_DIN   : STD_LOGIC := '0'; -- Load the MOSI shift register
  86.  
  87. signal SHIFT_TICK_IN     : STD_LOGIC; -- the moment at which the shifting is made,
  88. signal SHIFT_TICK_OUT    : STD_LOGIC; -- i.e. at the SCLK frequency
  89.  
  90. -- State machine internal condition signals
  91. signal Start_Shifting : STD_LOGIC := '0';
  92. signal Shifting_Done  : STD_LOGIC := '0';
  93.  
  94. --Counter for number of bits sent/received
  95. signal CntBits: integer range 0 to 7 := 0;
  96. signal Reset_Counters: STD_LOGIC; -- to reset all the counters, when in the Idle State
  97.  
  98. -- Shift In and Shift Out Registers
  99. signal MOSI_REG   : STD_LOGIC_VECTOR (7 downto 0) := X"00";
  100. signal MISO_REG   : STD_LOGIC_VECTOR (7 downto 0) := X"00";
  101.  
  102. -- Pipe Done signal to ensure that data is stable at the output
  103. signal DONE_1  : STD_LOGIC := '0';
  104.  
  105. -- Define Control Signals and States. From MSB: 7:EN_LOAD_DIN, 6:EN_SHIFT, 5:Reset_Counters,
  106. --                                          4:EN_SCLK, 3:EN_SS, 2:EN_LOAD_DOUT, 1:STC(1), 0:STC(0)
  107. constant stIdle    : STD_LOGIC_VECTOR (7 downto 0) := "10100000";
  108. constant stPrepare : STD_LOGIC_VECTOR (7 downto 0) := "00001001";
  109. constant stShift   : STD_LOGIC_VECTOR (7 downto 0) := "01011011";
  110. constant stDone    : STD_LOGIC_VECTOR (7 downto 0) := "00001110";
  111.  
  112. --State Machine Signal Definitions
  113. signal StC, StN   :  STD_LOGIC_VECTOR (7 downto 0) := stIdle;
  114.  
  115. --Force User Encoding for the State Machine
  116. attribute FSM_ENCODING : string;
  117. attribute FSM_ENCODING of StC: signal is "USER";
  118.  
  119. begin
  120.  
  121. -- Assign the control signals first
  122. EN_LOAD_DIN    <= StC(7);
  123. EN_SHIFT       <= StC(6);
  124. Reset_Counters <= StC(5);
  125. EN_SCLK        <= StC(4);
  126. EN_SS          <= StC(3);
  127. EN_LOAD_DOUT   <= StC(2);
  128.  
  129. -- Assign the outputs
  130. SS <= '0' when RESET = '0' and (HOLD_SS = '1' or EN_SS = '1') else '1';
  131. MOSI  <= MOSI_REG(7);
  132. SCLK <= SCLK_INT when EN_SCLK = '1' else '0';
  133.  
  134. --Assign the outputs: Register Dout
  135. Load_Output: process (SYSCLK, EN_LOAD_DOUT, MISO_REG)
  136. begin
  137.    if RISING_EDGE (SYSCLK) then
  138.       if EN_LOAD_DOUT = '1' then
  139.          Dout <= MISO_REG;
  140.       end if;
  141.    end if;
  142. end process Load_Output;
  143.  
  144. -- Set the Done signal, delayed with one clock period
  145. -- after data is assigned
  146. Set_Done: process (SYSCLK, EN_LOAD_DOUT, DONE_1)
  147. begin
  148.    if RISING_EDGE (SYSCLK) then
  149.       DONE_1 <= EN_LOAD_DOUT;
  150.       Done   <= DONE_1;
  151.    end if;
  152. end process Set_Done;
  153.  
  154. -- Divider to generate the 2X SCLK tick
  155. Div_2X_SCLK: process (SYSCLK, Reset_Counters, SCLK_2X_DIV)
  156. begin
  157.    if RISING_EDGE (SYSCLK) then
  158.       if Reset_Counters = '1'
  159.          or SCLK_2X_DIV = DIV_RATE then
  160.             SCLK_2X_DIV <= 0;
  161.       else
  162.             SCLK_2X_DIV <= SCLK_2X_DIV + 1;
  163.       end if;
  164.    end if;
  165. end process Div_2X_SCLK;
  166.  
  167. -- SCLK_2X_TICK will be active at both the rising and falling edges
  168. -- of SCLK_INT
  169. SCLK_2X_TICK <= '1' when SCLK_2X_DIV = DIV_RATE else '0';
  170.  
  171. --Generate SCLK_INT;
  172. Gen_SCLK_INT: process (SYSCLK, Reset_Counters, SCLK_2X_TICK, SCLK_INT)
  173. begin
  174.    if RISING_EDGE (SYSCLK) then
  175.       if Reset_Counters = '1' then
  176.          SCLK_INT <= '0';
  177.       elsif SCLK_2X_TICK = '1' then
  178.          SCLK_INT <= not SCLK_INT;
  179.       end if;
  180.    end if;
  181. end process Gen_SCLK_INT;
  182.  
  183. -- SHIFT_TICK_IN will be active at the rising edge of SCLK
  184. -- At that moment MOSI will be read
  185. SHIFT_TICK_IN  <= '1' when EN_SHIFT = '1' and SCLK_INT = '0' and SCLK_2X_TICK = '1' else '0';
  186.  
  187. -- SHIFT_TICK_OUT will be active at the falling edge of SCLK
  188. -- At that moment the next bit will be shifted out
  189. SHIFT_TICK_OUT <= '1' when EN_SHIFT = '1' and SCLK_INT = '1' and SCLK_2X_TICK = '1' else '0';
  190.  
  191. -- Create the shift in register, MSB First, so shift left
  192. SHIFT_IN: process (SYSCLK, SHIFT_TICK_IN, MISO_REG)
  193. begin
  194.    if RISING_EDGE (SYSCLK) then
  195.       if SHIFT_TICK_IN = '1' then
  196.          MISO_REG (7 downto 0) <= MISO_REG (6 downto 0) & MISO;
  197.       end if;
  198.    end if;
  199. end process SHIFT_IN;
  200.  
  201. -- Create the shift out register, MSB out first, so shift left
  202. -- MOSI_REG is constantly loaded with Din when in idle state;
  203. SHIFT_OUT: process (SYSCLK, EN_LOAD_DIN, Din, SHIFT_TICK_OUT, MOSI_REG)
  204. begin
  205.    if RISING_EDGE (SYSCLK) then
  206.       if EN_LOAD_DIN = '1' then
  207.          MOSI_REG <= Din;
  208.       elsif SHIFT_TICK_OUT = '1' then
  209.          MOSI_REG (7 downto 0) <= MOSI_REG (6 downto 0) & '0';
  210.       end if;
  211.    end if;
  212. end process SHIFT_OUT;
  213.  
  214. -- CntBits will be incremented at the falling edge of SCLK
  215. -- i.e. when SHIFT_TICK_OUT is active
  216. Count_Bits: process (SYSCLK, Reset_Counters, SHIFT_TICK_OUT, CntBits)
  217. begin
  218.    if RISING_EDGE (SYSCLK) then
  219.       if Reset_Counters = '1' then
  220.          CntBits <= 0;
  221.       elsif SHIFT_TICK_OUT = '1' then
  222.          if CntBits = 7 then
  223.             CntBits <= 0;
  224.          else
  225.             CntBits <= CntBits + 1;
  226.          end if;
  227.       end if;
  228.    end if;
  229. end process Count_Bits;
  230.  
  231. -- Assign the State machine internal condition signals
  232.  
  233. -- Start Shifting in the stPrepare state, after
  234. -- either a falling edge of SCLK_INT comes in a single byte transfer mode
  235. -- or immediately after a Start command received, in multiple byte transfer mode
  236. Start_Shifting <= '1' when StC = stPrepare and (HOLD_SS = '1' or (SCLK_INT = '1' and SCLK_2X_TICK = '1'))
  237.                       else '0';
  238.  
  239. -- Shifting ends when 8 bits has been transferred,
  240. -- at the falling edge of SCLK_INT
  241. Shifting_Done <= '1' when StC = stShift and CntBits = 7 and SCLK_INT = '1' and SCLK_2X_TICK = '1' else '0';
  242.  
  243. -- State machine register process
  244. Reg_Statem: process (SYSCLK, RESET, StN)
  245. begin
  246.    if RISING_EDGE (SYSCLK) then
  247.       if RESET = '1' then
  248.          StC <= stIdle;
  249.       else
  250.          StC <= StN;
  251.       end if;
  252.    end if;
  253. end process Reg_Statem;
  254.  
  255. -- State machine transition process
  256. Cmb_Statem: process (StC, Start, Start_Shifting, Shifting_Done)
  257. begin
  258.    StN <= StC; -- default: stay in the current state if no other
  259.                -- condition for transition occurs
  260.    case StC is
  261.    when stIdle => if Start = '1' then StN <= stPrepare; end if;
  262.    when stPrepare => if Start_Shifting = '1' then StN <= stShift; end if;
  263.    when stShift => if Shifting_Done = '1' then StN <= stDone; end if;
  264.    when stDone => StN <= stIdle;
  265.    when others => StN <= stIdle;
  266.    end case;
  267. end process Cmb_Statem;
  268.  
  269.  
  270. end Behavioral;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement