library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity u_spi is port ( CLK : in std_logic; -- CLK input RXD : out std_logic_vector (7 downto 0); -- RX data TXD : in std_logic_vector (7 downto 0); -- TX data LOAD : in std_logic; -- Load TX data DONE : out std_logic; -- Done Transfer CPOL : in std_logic; -- Clock polarity CPHA : in std_logic; -- Clock phase MISO : in std_logic; -- Master In Slave Out SPI pin MOSI : out std_logic; -- Master Out Slave In SPI pin SCK : out std_logic -- Serial ClocK SPI pin ); end entity; architecture rtl of u_spi is signal REG : std_logic_vector (7 downto 0) := "00000000"; -- shift register signal COUNT : std_logic_vector (3 downto 0); -- count stage of sending signal SDONE : std_logic :='0'; -- transfer completed signal START : std_logic :='0'; -- start transfer signal SCLK : std_logic; -- internal clk (phase changing) begin start_stop: process (LOAD,SDONE,START) -- internal status flip-flop begin if LOAD='1' then START <= '1'; else if SDONE = '1' then START <= '0'; else START <= START; end if; end if; end process; SCLK <= CLK XOR CPHA; -- change phase mosi_buf: process (SCLK,REG,START) -- MOSI pin changed half clock after strobed MISO begin if START='1' AND falling_edge(SCLK) then MOSI <= REG(7); end if; end process; RXD <= REG; mosi_shift: process (SCLK,REG,TXD,START,LOAD) -- SPI register transfer and load begin if LOAD='1' then -- LOAD data REG <= TXD; else if START='1' and rising_edge(SCLK) then -- Transfer data REG <= MISO & REG(7 downto 1); end if; end if; end process; clock_count: process (SCLK,START,COUNT) -- stage counting begin if START = '0' then COUNT <= "0000"; SDONE <= '0'; else if COUNT = "1000" then SDONE <= '1'; else if falling_edge(SCLK) then COUNT <= COUNT + 1; SDONE <= '0'; end if; end if; end if; end process; SCK <= (SCLK AND NOT SDONE) XOR CPOL; -- change polarity DONE <= SDONE; end;