From f38c6a3c3619aad6e31e28b41c8a63f2247a7022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Mon, 28 Aug 2023 11:14:18 +0200 Subject: [PATCH] feat: add spi transmit and receive --- src/spi_recv.vhd | 43 ++++++++++++++++++ src/spi_transmit.vhd | 105 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/spi_recv.vhd create mode 100644 src/spi_transmit.vhd diff --git a/src/spi_recv.vhd b/src/spi_recv.vhd new file mode 100644 index 0000000000000000000000000000000000000000..2d8f22b44131ddb15c10f248cbf6bb6e8ee004d9 --- /dev/null +++ b/src/spi_recv.vhd @@ -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; diff --git a/src/spi_transmit.vhd b/src/spi_transmit.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f39940db6cf620c6189baee470eb158aeb7cfebb --- /dev/null +++ b/src/spi_transmit.vhd @@ -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;