~ruther/vhdl-spi

f38c6a3c3619aad6e31e28b41c8a63f2247a7022 — František Boháček 1 year, 7 months ago 5fcbd24
feat: add spi transmit and receive
2 files changed, 148 insertions(+), 0 deletions(-)

A src/spi_recv.vhd
A src/spi_transmit.vhd
A src/spi_recv.vhd => src/spi_recv.vhd +43 -0
@@ 0,0 1,43 @@
library ieee;
use ieee.std_logic_1164.all;

entity spi_recv is

  generic (
    WIDTH : integer := 8);

  port (
    clk_i : in std_logic;
    rst_in : in std_logic;
    data_i : in std_logic;
    recv_o : out std_logic;
    recv_data_o : out std_logic_vector(WIDTH - 1 downto 0));
end entity spi_recv;

architecture a1 of spi_recv is
  signal bit_index_reg : integer range 0 to WIDTH;
  signal initialized : std_logic;
begin  -- architecture a1
  recv_o <= '1' when bit_index_reg = 0 and initialized = '1' else
            '0';

  set_bit_index: process (clk_i) is
  begin  -- process set_bit_index
    if rst_in = '0' then            -- synchronous reset (active low)
      bit_index_reg <= 0;
      initialized <= '0';
    elsif rising_edge(clk_i) then        -- rising clock edge
      initialized <= '1';
      bit_index_reg <= (bit_index_reg + 1) mod WIDTH;
    end if;
  end process set_bit_index;

  sr: entity work.sipo_shift_register
    generic map (
      WIDTH => WIDTH)
    port map (
      clk_i  => clk_i,
      data_i => data_i,
      q_o => recv_data_o);

end architecture a1;

A src/spi_transmit.vhd => src/spi_transmit.vhd +105 -0
@@ 0,0 1,105 @@
library ieee;
use ieee.std_logic_1164.all;

entity spi_transmit is

  generic (
    WIDTH : integer := 8);

  port (
    clk_i           : in  std_logic;    -- Clock
    rst_in          : in  std_logic;    -- Asynchronous reset, active low
    transmit_data_i : in  std_logic_vector(WIDTH - 1 downto 0);  -- The data to
                                                                 -- transmit.
                                                                 -- Change only
                                                                 -- if ready_o
                                                                 -- is '1'.
    transmit_i      : in  std_logic;    -- Pulse to signal new data are present
                                        -- in transmit_data. Data has to change
                                        -- only if ready_o is '1'
    ready_o         : out std_logic;    -- Signals that the transmitter is
                                        -- ready for new data on `transmit_data_i``.
    transmitting_o  : out std_logic;    -- Signals that the transmitter is
                                        -- currently transmitting data
    transmit_bit_o  : out std_logic);   -- The bit to transmit (on master MOSI)

end entity spi_transmit;

architecture a1 of spi_transmit is
  signal ready_reg : std_logic;         -- is the transmitter ready for new data?
  signal ready_next : std_logic;

  signal data_prepared_reg : std_logic;  -- is there data prepared for next transmission?
  signal data_prepared_next : std_logic;
  signal store_data_in_sr_reg : std_logic;  -- should data be stored in the
                                            -- shift register next clock cycle?
  signal store_data_in_sr_next : std_logic;

  signal data_bit_index_reg : integer range 0 to WIDTH;
  signal data_bit_index_next : integer range 0 to WIDTH;

  signal transmitting_reg : std_logic;  -- is there an ongoing transmission?
  signal transmitting_next : std_logic;

  signal continue_in_ongoing_transmission : std_logic;  -- at the end of
                                                        -- transmission, are
                                                        -- next data ready and
                                                        -- should the transmission continue?
begin  -- architecture a1
  ready_o <= ready_reg;
  transmitting_o <= transmitting_reg;

  ready_next <= '0' when ready_reg = '1' and transmit_i = '1' and transmitting_reg = '1' else
                '0' when ready_reg = '0' and data_prepared_next = '1' else
                '1';

  data_bit_index_next <= (data_bit_index_reg + 1) mod WIDTH when transmitting_reg = '1' else
                         0;

  continue_in_ongoing_transmission <= '1' when transmitting_reg = '1' and data_bit_index_next = 0 and store_data_in_sr_next = '1' else
                              '0';

  transmitting_next <= '1' when continue_in_ongoing_transmission = '1' else
                       '0' when transmitting_reg = '1' and data_bit_index_next = 0 else
                       '1' when transmitting_reg = '1' else
                       '1' when store_data_in_sr_next = '1' else
                       '0';

  store_data_in_sr_next <= '0' when store_data_in_sr_reg = '1' else
                           '1' when transmitting_reg = '0' and transmit_i = '1' else
                           '1' when transmitting_reg = '0' and data_prepared_reg = '1' else
                           '1' when transmitting_reg = '1' and data_bit_index_next = 0 and data_prepared_reg = '1' else
                           '0';

  data_prepared_next <= '1' when transmit_i = '1' and ready_reg = '1' and transmitting_reg = '1' else
                        '1' when data_prepared_reg = '1' and store_data_in_sr_next = '0' else
                        '0';

  store_next: process (clk_i) is
  begin  -- process store_next
    if rst_in = '0' then              -- synchronous reset (active low)
      ready_reg <= '0';
      data_prepared_reg <= '0';
      store_data_in_sr_reg <= '0';
      data_bit_index_reg <= 0;
      transmitting_reg <= '0';
    elsif rising_edge(clk_i) then          -- rising clock edge
      ready_reg <= ready_next;
      data_prepared_reg <= data_prepared_next;
      store_data_in_sr_reg <= store_data_in_sr_next;
      data_bit_index_reg <= data_bit_index_next;
      transmitting_reg <= transmitting_next;
    end if;
  end process store_next;

  sr: entity work.piso_shift_register
    generic map (
      WIDTH => WIDTH)
    port map (
      clk_i => clk_i,
      data_i => transmit_data_i,
      store_i => store_data_in_sr_next,
      q_o => transmit_bit_o
    );

end architecture a1;

Do not follow this link