Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ----------------------------------------------------------------------------------
- ----------------------------------------------------------------------------
- -- Author: Albert Fazakas
- -- Copyright 2014 Digilent, Inc.
- ----------------------------------------------------------------------------
- --
- -- Create Date: 17:55:33 02/17/2014
- -- Design Name:
- -- Module Name: SPI_If - Behavioral
- -- Project Name:
- -- Target Devices:
- -- Tool versions:
- -- Description:
- -- This module represents an SPI controller. The controller transfers 8 bits of data, MSB first.
- -- Data is read on the positive edge of SCLK and also stable on the positive edge of SCLK.
- -- When there is no data transfer, SCLK = 0, therefore CPOL = 0, CPHA = 0.
- -- Data transfer starts by activating the "Start" signal, and, when data transfer is done, the
- -- "Done" signal is activated for one SYSCLK period.
- --
- -- The module is also capable to transfer multiple bytes, if the "HOLD_SS" signal is active.
- -- In this case SS is not raised between byte transfers and a new transfer can begin
- -- if the "Start" signal is activated. This feature is used in conjunction with the ADXL 362 accelerometer
- -- or any device which needs multiple-byte transfers for sending commands and/or reading data
- --
- -- Revision:
- -- Revision 0.01 - File Created
- -- Additional Comments:
- --
- ----------------------------------------------------------------------------------
- library IEEE;
- use IEEE.STD_LOGIC_1164.ALL;
- -- Uncomment the following library declaration if using
- -- arithmetic functions with Signed or Unsigned values
- --use IEEE.NUMERIC_STD.ALL;
- -- Uncomment the following library declaration if instantiating
- -- any Xilinx primitives in this code.
- --library UNISIM;
- --use UNISIM.VComponents.all;
- entity SPI_If is
- generic
- (
- SYSCLK_FREQUENCY_HZ : integer:= 100000000;
- SCLK_FREQUENCY_HZ : integer:= 1000000
- );
- port
- (
- SYSCLK : in STD_LOGIC; -- System Clock
- RESET : in STD_LOGIC;
- Din : in STD_LOGIC_VECTOR (7 downto 0); -- Data to be transmitted
- Dout : out STD_LOGIC_VECTOR (7 downto 0); -- Data received;
- Start : in STD_LOGIC; -- used to start the transmission
- Done : out STD_LOGIC; -- Signaling that transmission ended
- HOLD_SS : in STD_LOGIC; -- Signal that forces SS low in the case of multiple byte
- -- transmit/receive mode
- --SPI Interface Signals
- SCLK : out STD_LOGIC;
- MOSI : out STD_LOGIC;
- MISO : in STD_LOGIC;
- SS : out STD_LOGIC
- );
- end SPI_If;
- architecture Behavioral of SPI_If is
- -- Determine the division rate in order to create the 2X SCLK tick
- constant DIV_RATE : integer := ((SYSCLK_FREQUENCY_HZ / ( 2 * SCLK_FREQUENCY_HZ)) - 1);
- -- To generate the 2X SCLK tick, then SCLK
- signal SCLK_2X_DIV : integer range 0 to DIV_RATE := 0;
- signal SCLK_2X_TICK : STD_LOGIC := '0';
- -- Internal SCLK signal
- signal SCLK_INT : STD_LOGIC := '0';
- -- Enable Output Signals
- signal EN_SCLK : STD_LOGIC := '0';
- signal EN_SS : STD_LOGIC := '0';
- -- Control Signals
- signal EN_SHIFT : STD_LOGIC := '0'; -- Enable shifting the MOSI_REG and MISO_REG registers
- signal EN_LOAD_DOUT : STD_LOGIC :='0'; -- Enable loading the Dout register
- -- from the shift register for MISO
- signal EN_LOAD_DIN : STD_LOGIC := '0'; -- Load the MOSI shift register
- signal SHIFT_TICK_IN : STD_LOGIC; -- the moment at which the shifting is made,
- signal SHIFT_TICK_OUT : STD_LOGIC; -- i.e. at the SCLK frequency
- -- State machine internal condition signals
- signal Start_Shifting : STD_LOGIC := '0';
- signal Shifting_Done : STD_LOGIC := '0';
- --Counter for number of bits sent/received
- signal CntBits: integer range 0 to 7 := 0;
- signal Reset_Counters: STD_LOGIC; -- to reset all the counters, when in the Idle State
- -- Shift In and Shift Out Registers
- signal MOSI_REG : STD_LOGIC_VECTOR (7 downto 0) := X"00";
- signal MISO_REG : STD_LOGIC_VECTOR (7 downto 0) := X"00";
- -- Pipe Done signal to ensure that data is stable at the output
- signal DONE_1 : STD_LOGIC := '0';
- -- Define Control Signals and States. From MSB: 7:EN_LOAD_DIN, 6:EN_SHIFT, 5:Reset_Counters,
- -- 4:EN_SCLK, 3:EN_SS, 2:EN_LOAD_DOUT, 1:STC(1), 0:STC(0)
- constant stIdle : STD_LOGIC_VECTOR (7 downto 0) := "10100000";
- constant stPrepare : STD_LOGIC_VECTOR (7 downto 0) := "00001001";
- constant stShift : STD_LOGIC_VECTOR (7 downto 0) := "01011011";
- constant stDone : STD_LOGIC_VECTOR (7 downto 0) := "00001110";
- --State Machine Signal Definitions
- signal StC, StN : STD_LOGIC_VECTOR (7 downto 0) := stIdle;
- --Force User Encoding for the State Machine
- attribute FSM_ENCODING : string;
- attribute FSM_ENCODING of StC: signal is "USER";
- begin
- -- Assign the control signals first
- EN_LOAD_DIN <= StC(7);
- EN_SHIFT <= StC(6);
- Reset_Counters <= StC(5);
- EN_SCLK <= StC(4);
- EN_SS <= StC(3);
- EN_LOAD_DOUT <= StC(2);
- -- Assign the outputs
- SS <= '0' when RESET = '0' and (HOLD_SS = '1' or EN_SS = '1') else '1';
- MOSI <= MOSI_REG(7);
- SCLK <= SCLK_INT when EN_SCLK = '1' else '0';
- --Assign the outputs: Register Dout
- Load_Output: process (SYSCLK, EN_LOAD_DOUT, MISO_REG)
- begin
- if RISING_EDGE (SYSCLK) then
- if EN_LOAD_DOUT = '1' then
- Dout <= MISO_REG;
- end if;
- end if;
- end process Load_Output;
- -- Set the Done signal, delayed with one clock period
- -- after data is assigned
- Set_Done: process (SYSCLK, EN_LOAD_DOUT, DONE_1)
- begin
- if RISING_EDGE (SYSCLK) then
- DONE_1 <= EN_LOAD_DOUT;
- Done <= DONE_1;
- end if;
- end process Set_Done;
- -- Divider to generate the 2X SCLK tick
- Div_2X_SCLK: process (SYSCLK, Reset_Counters, SCLK_2X_DIV)
- begin
- if RISING_EDGE (SYSCLK) then
- if Reset_Counters = '1'
- or SCLK_2X_DIV = DIV_RATE then
- SCLK_2X_DIV <= 0;
- else
- SCLK_2X_DIV <= SCLK_2X_DIV + 1;
- end if;
- end if;
- end process Div_2X_SCLK;
- -- SCLK_2X_TICK will be active at both the rising and falling edges
- -- of SCLK_INT
- SCLK_2X_TICK <= '1' when SCLK_2X_DIV = DIV_RATE else '0';
- --Generate SCLK_INT;
- Gen_SCLK_INT: process (SYSCLK, Reset_Counters, SCLK_2X_TICK, SCLK_INT)
- begin
- if RISING_EDGE (SYSCLK) then
- if Reset_Counters = '1' then
- SCLK_INT <= '0';
- elsif SCLK_2X_TICK = '1' then
- SCLK_INT <= not SCLK_INT;
- end if;
- end if;
- end process Gen_SCLK_INT;
- -- SHIFT_TICK_IN will be active at the rising edge of SCLK
- -- At that moment MOSI will be read
- SHIFT_TICK_IN <= '1' when EN_SHIFT = '1' and SCLK_INT = '0' and SCLK_2X_TICK = '1' else '0';
- -- SHIFT_TICK_OUT will be active at the falling edge of SCLK
- -- At that moment the next bit will be shifted out
- SHIFT_TICK_OUT <= '1' when EN_SHIFT = '1' and SCLK_INT = '1' and SCLK_2X_TICK = '1' else '0';
- -- Create the shift in register, MSB First, so shift left
- SHIFT_IN: process (SYSCLK, SHIFT_TICK_IN, MISO_REG)
- begin
- if RISING_EDGE (SYSCLK) then
- if SHIFT_TICK_IN = '1' then
- MISO_REG (7 downto 0) <= MISO_REG (6 downto 0) & MISO;
- end if;
- end if;
- end process SHIFT_IN;
- -- Create the shift out register, MSB out first, so shift left
- -- MOSI_REG is constantly loaded with Din when in idle state;
- SHIFT_OUT: process (SYSCLK, EN_LOAD_DIN, Din, SHIFT_TICK_OUT, MOSI_REG)
- begin
- if RISING_EDGE (SYSCLK) then
- if EN_LOAD_DIN = '1' then
- MOSI_REG <= Din;
- elsif SHIFT_TICK_OUT = '1' then
- MOSI_REG (7 downto 0) <= MOSI_REG (6 downto 0) & '0';
- end if;
- end if;
- end process SHIFT_OUT;
- -- CntBits will be incremented at the falling edge of SCLK
- -- i.e. when SHIFT_TICK_OUT is active
- Count_Bits: process (SYSCLK, Reset_Counters, SHIFT_TICK_OUT, CntBits)
- begin
- if RISING_EDGE (SYSCLK) then
- if Reset_Counters = '1' then
- CntBits <= 0;
- elsif SHIFT_TICK_OUT = '1' then
- if CntBits = 7 then
- CntBits <= 0;
- else
- CntBits <= CntBits + 1;
- end if;
- end if;
- end if;
- end process Count_Bits;
- -- Assign the State machine internal condition signals
- -- Start Shifting in the stPrepare state, after
- -- either a falling edge of SCLK_INT comes in a single byte transfer mode
- -- or immediately after a Start command received, in multiple byte transfer mode
- Start_Shifting <= '1' when StC = stPrepare and (HOLD_SS = '1' or (SCLK_INT = '1' and SCLK_2X_TICK = '1'))
- else '0';
- -- Shifting ends when 8 bits has been transferred,
- -- at the falling edge of SCLK_INT
- Shifting_Done <= '1' when StC = stShift and CntBits = 7 and SCLK_INT = '1' and SCLK_2X_TICK = '1' else '0';
- -- State machine register process
- Reg_Statem: process (SYSCLK, RESET, StN)
- begin
- if RISING_EDGE (SYSCLK) then
- if RESET = '1' then
- StC <= stIdle;
- else
- StC <= StN;
- end if;
- end if;
- end process Reg_Statem;
- -- State machine transition process
- Cmb_Statem: process (StC, Start, Start_Shifting, Shifting_Done)
- begin
- StN <= StC; -- default: stay in the current state if no other
- -- condition for transition occurs
- case StC is
- when stIdle => if Start = '1' then StN <= stPrepare; end if;
- when stPrepare => if Start_Shifting = '1' then StN <= stShift; end if;
- when stShift => if Shifting_Done = '1' then StN <= stDone; end if;
- when stDone => StN <= stIdle;
- when others => StN <= stIdle;
- end case;
- end process Cmb_Statem;
- end Behavioral;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement