- Started implementing SPI controller
This commit is contained in:
270
src/spi.vhd
Normal file
270
src/spi.vhd
Normal file
@@ -0,0 +1,270 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Title : SPI Controller
|
||||
-- Project :
|
||||
-------------------------------------------------------------------------------
|
||||
-- File : spi.vhd
|
||||
-- Author : Matthias Blankertz <matthias@blankertz.org>
|
||||
-- Company :
|
||||
-- Created : 2013-06-05
|
||||
-- Last update: 2013-06-05
|
||||
-- Platform :
|
||||
-- Standard : VHDL'93/02
|
||||
-------------------------------------------------------------------------------
|
||||
-- Description:
|
||||
-------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2013
|
||||
-------------------------------------------------------------------------------
|
||||
-- Revisions :
|
||||
-- Date Version Author Description
|
||||
-- 2013-06-05 1.0 matthias Created
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
use work.intercon_package.all;
|
||||
|
||||
-- Register map
|
||||
-- 0 : data in/out register
|
||||
-- 1 : status register
|
||||
-- 2 : config1 register
|
||||
-- 7..6: reserved
|
||||
-- 5..0: output clock divider
|
||||
|
||||
entity spi is
|
||||
generic (
|
||||
dontcare : std_logic := '-';
|
||||
clock_pol : std_logic := '1';
|
||||
clock_phase : std_logic := '0'
|
||||
);
|
||||
port (
|
||||
clk_i : in std_logic;
|
||||
rst_i : in std_logic;
|
||||
|
||||
-- Wishbone slave port
|
||||
dat_i : in std_logic_vector(7 downto 0);
|
||||
we_i : in std_logic;
|
||||
cyc_i : in std_logic;
|
||||
stb_i : in std_logic;
|
||||
adr_i : in std_logic_vector(1 downto 0);
|
||||
|
||||
dat_o : out std_logic_vector(7 downto 0);
|
||||
ack_o : out std_logic;
|
||||
|
||||
-- SPI Master
|
||||
miso : in std_logic;
|
||||
mosi : out std_logic;
|
||||
sclk : out std_logic;
|
||||
ss : out std_logic
|
||||
);
|
||||
end spi;
|
||||
|
||||
architecture Behavioral of spi is
|
||||
constant sclk_obuf_init : std_logic := not clock_pol;
|
||||
|
||||
signal spi_clk, spi_clk_dly : std_logic := '0';
|
||||
signal spi_clk_inv : std_logic;
|
||||
|
||||
type spi_states is (S_IDLE, S_XFER_START, S_XFER, S_WAITFALLING, S_WAITINFIFO);
|
||||
signal spi_state : spi_states := S_IDLE;
|
||||
|
||||
signal clk_divider, clk_ctr : unsigned(5 downto 0) := to_unsigned(0, 6);
|
||||
begin
|
||||
spi_clk_gen : process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
if spi_clk_rst = '1' then
|
||||
clk_ctr <= to_unsigned(0, 6);
|
||||
spi_clk <= '0';
|
||||
elsif clk_ctr >= clk_divider then
|
||||
clk_ctr <= to_unsigned(0, 6);
|
||||
spi_clk <= not spi_clk;
|
||||
else
|
||||
clk_ctr <= clk_ctr + 1;
|
||||
end if;
|
||||
spi_clk_dly <= spi_clk;
|
||||
end if;
|
||||
end process spi_clk_gen;
|
||||
spi_clk_inv <= not spi_clk_dly;
|
||||
|
||||
sclk_obuf : ODDR2
|
||||
generic map (
|
||||
DDR_ALIGNMENT => "C0",
|
||||
INIT => sclk_obuf_init
|
||||
)
|
||||
port map (
|
||||
Q => sclk,
|
||||
C0 => spi_clk_dly,
|
||||
C1 => spi_clk_inv,
|
||||
CE => sclk_o_en,
|
||||
D0 => sclk_o_d0,
|
||||
D1 => sclk_o_d1,
|
||||
R => '0',
|
||||
S => '0'
|
||||
);
|
||||
|
||||
sclk_o_d0 <= not clock_pol;
|
||||
sclk_o_d1 <= clock_pol;
|
||||
|
||||
spi_sreg : process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
infifo_wr <= '0';
|
||||
infifo_din <= (others => dontcare);
|
||||
outfifo_rd <= '0';
|
||||
|
||||
case spi_state is
|
||||
when S_IDLE =>
|
||||
if outfifo_empty = '0' then
|
||||
sreg(8 downto 1) <= outfifo_dout;
|
||||
outfifo_rd <= '1';
|
||||
if clock_phase = '0' then
|
||||
mosi <= outfifo_dout(7);
|
||||
end if;
|
||||
spi_state <= S_XFER_START;
|
||||
end if;
|
||||
when S_XFER_START =>
|
||||
if spi_clk_dly = '1' and spi_clk = '0' then
|
||||
sclk_o_en <= '1';
|
||||
spi_state <= S_XFER;
|
||||
end if;
|
||||
when S_XFER =>
|
||||
if ((spi_clk_dly = '0' and spi_clk = '1' and clock_phase = '0') or
|
||||
(spi_clk_dly = '1' and spi_clk = '0' and clock_phase = '1')) then
|
||||
-- Data in
|
||||
sreg(0) <= miso;
|
||||
if spi_ctr = 7 then
|
||||
-- 8 bits latched, i.e. transfer complete
|
||||
if outfifo_empty = '0' and infifo_full = '0' then
|
||||
-- data for new transfer available
|
||||
-- save received data
|
||||
infifo_din <= sreg(7 downto 1) & miso;
|
||||
infifo_wr <= '1';
|
||||
-- load new data
|
||||
sreg(8 downto 1) <= outfifo_dout;
|
||||
outfifo_rd <= '1';
|
||||
spi_ctr <= 0;
|
||||
else
|
||||
-- stop transfer
|
||||
if infifo_full = '0' then
|
||||
-- save received data
|
||||
infifo_din <= sreg(7 downto 1) & miso;
|
||||
infifo_wr <= '1';
|
||||
end if;
|
||||
if clock_phase = '1' then
|
||||
sclk_o_en <= '0';
|
||||
if infifo_full = '1' then
|
||||
spi_state <= S_WAITINFIFO;
|
||||
else
|
||||
spi_state <= S_IDLE;
|
||||
end if;
|
||||
else
|
||||
indata_pending <= infifo_full;
|
||||
spi_state <= S_WAITFALLING;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
elsif (spi_clk_dly = '1' and spi_clk = '0' and clock_phase = '0') then
|
||||
-- Data out
|
||||
mosi <= sreg(8);
|
||||
sreg <= sreg(7 downto 0) & "0";
|
||||
elsif (spi_clk_dly = '0' and spi_clk = '1' and clock_phase = '1') then
|
||||
-- Data out
|
||||
mosi <= sreg(8);
|
||||
sreg <= sreg(7 downto 0) & "0";
|
||||
end if;
|
||||
when S_WAITFALLING =>
|
||||
if spi_clk_dly = '1' and spi_clk = '0' then
|
||||
sclk_o_en <= '0';
|
||||
if indata_pending = '1' then
|
||||
if infifo_full = '0' then
|
||||
-- save received data
|
||||
infifo_din <= sreg(7 downto 0);
|
||||
infifo_wr <= '1';
|
||||
spi_state <= S_IDLE;
|
||||
else
|
||||
spi_state <= S_WAITINFIFO;
|
||||
end if;
|
||||
else
|
||||
spi_state <= S_IDLE;
|
||||
end if;
|
||||
end if;
|
||||
when S_WAITINFIFO =>
|
||||
if infifo_full = '0' then
|
||||
-- save received data
|
||||
infifo_din <= sreg(7 downto 0);
|
||||
infifo_wr <= '1';
|
||||
spi_state <= S_IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end process spi_sreg;
|
||||
|
||||
spi_idle <= '1' when spi_state = S_IDLE and outfifo_empty = '1' else
|
||||
'0';
|
||||
|
||||
wb : process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
outfifo_wr <= '0';
|
||||
infifo_rd <= '0';
|
||||
outfifo_din <= (others => dontcare);
|
||||
|
||||
if rst_i = '1' then
|
||||
wbs_o.ack_o <= '0';
|
||||
wb_in_cyc <= '0';
|
||||
wbs_o.dat_o <= (others => dontcare);
|
||||
else
|
||||
if wb_in_cyc = '1' and wbs_i.stb_i = '0' then
|
||||
wbs_o.dat_o <= (others => dontcare);
|
||||
wb_in_cyc <= '0';
|
||||
elsif wb_in_cyc = '0' and wbs_i.stb_i = '1' and wbs_i.cyc_i = '1' then
|
||||
wb_in_cyc <= '1';
|
||||
wbs_o.ack_o <= '1';
|
||||
|
||||
if wbs_i.we_i = '0' then
|
||||
if wbs_i.adr_i = "00" then
|
||||
-- read data i/o reg
|
||||
wbs_o.dat_o <= infifo_dout;
|
||||
if infifo_empty = '0' then
|
||||
infifo_rd <= '1';
|
||||
end if;
|
||||
elsif wbs_i.adr_i = "01" then
|
||||
-- read status reg
|
||||
wbs_o.dat_o(7 downto 3) <= (others => dontcare)
|
||||
wbs_o.dat_o(2 downto 0) <= infifo_empty & outfifo_full & spi_idle;
|
||||
elsif wbs_i.adr_i = "10" then
|
||||
-- read config reg
|
||||
wbs_o.dat_o(7 downto 6) <= (others => dontcare);
|
||||
wbs_o.dat_o(5 downto 0) <= std_logic_vector(clk_divider);
|
||||
else
|
||||
wbs_o.dat_o <= (others => dontcare);
|
||||
end if;
|
||||
else
|
||||
wbs_o.dat_o <= (others => dontcare);
|
||||
if wbs_i.adr_i = "00" then
|
||||
-- write data i/o reg
|
||||
outfifo_din <= wbs_i.dat_i;
|
||||
if outfifo_full = '0' then
|
||||
outfifo_wr <= '1';
|
||||
end if;
|
||||
elsif wbs_i.adr_i = "10" then
|
||||
-- write config reg
|
||||
clk_divider <= unsigned(wbs_i.dat_i(5 downto 0));
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process wb;
|
||||
|
||||
end Behavioral;
|
||||
Reference in New Issue
Block a user