library ieee; use ieee.std_logic_1164.all; entity spi_transmit is generic ( WIDTH : integer := 8; ALIGN_START : std_logic := '1'); 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'. valid_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 store_data_in_sr : std_logic; -- should data be stored in the -- shift register next clock cycle? signal transmit_bit_falling : std_logic; signal sr_q_o : std_logic; signal data_bit_index_reg : integer range 0 to WIDTH; signal data_bit_index_next : integer range 0 to WIDTH; type state is (IDLE, WAITING, SINGLE_TRANSMISSION, CONTINUOUS_TRANSMISSION); -- IDLE - not sending anything -- WAITING - waiting for the right moment to send - data_bit_index = 0 -- SINGLE_TRANSMISSION - just one data currently loaded into the shift register -- CONTINUOUS_TRANSMISSION - one data currently being sent, and another data -- loaded into the shift register, and another ready to be sent signal state_reg : state; signal state_next : state; signal can_begin_transmission_next : std_logic; begin -- architecture a1 transmit_bit_o <= sr_q_o when state_reg = SINGLE_TRANSMISSION and data_bit_index_reg = 1 else transmit_bit_falling when state_reg /= IDLE else sr_q_o; can_begin_transmission_next <= '1' when data_bit_index_reg = 0 else '0'; -- in IDLE, go to -- -- SINGLE_TRANSMISSION if data valid, and can start transmission -- -- WAITING if data valid, and cannot start transmission -- -- IDLE -- in WAITING, go to -- -- SINGLE_TRANSMISSION if can start transmission -- -- WAITING -- in SINGLE_TRANSMISSION, go to -- -- CONTINUOUS_TRANSMISSION if data valid and cannot begin new transmission -- -- SINGLE_TRANSMISSION if data valid and can begin new transmission -- -- IDLE if transmission done -- -- SINGLE_TRANSMISSION if transmission ongoing -- in CONTINUOUS_TRANSMISSION, go to -- -- CONTINUOUS_TRANSMISSION if cannot begin new transmission -- -- SINGLE_TRANSMISSION if can begin new transmission state_next <= SINGLE_TRANSMISSION when state_reg = IDLE and valid_i = '1' and can_begin_transmission_next = '1' else WAITING when state_reg = IDLE and valid_i = '1' else SINGLE_TRANSMISSION when state_reg = WAITING and can_begin_transmission_next = '1' else WAITING when state_reg = WAITING else SINGLE_TRANSMISSION when state_reg = SINGLE_TRANSMISSION and valid_i = '1' and can_begin_transmission_next = '1' else CONTINUOUS_TRANSMISSION when state_reg = SINGLE_TRANSMISSION and valid_i = '1' else SINGLE_TRANSMISSION when state_reg = SINGLE_TRANSMISSION and data_bit_index_reg /= 0 else CONTINUOUS_TRANSMISSION when state_reg = CONTINUOUS_TRANSMISSION and can_begin_transmission_next = '0' else SINGLE_TRANSMISSION when state_reg = CONTINUOUS_TRANSMISSION and can_begin_transmission_next = '1' else IDLE; store_data_in_sr <= '1' when data_bit_index_reg = 0 and state_next /= IDLE else '0'; ready_o <= '1' when state_reg /= CONTINUOUS_TRANSMISSION else '0'; transmitting_o <= '1' when state_next = SINGLE_TRANSMISSION or state_next = CONTINUOUS_TRANSMISSION else '0'; data_bit: if ALIGN_START = '1' generate data_bit_index_next <= (data_bit_index_reg + 1) mod WIDTH; else generate data_bit_index_next <= (data_bit_index_reg + 1) mod WIDTH when state_reg /= IDLE else 0; end generate data_bit; store_next: process (clk_i) is begin -- process store_next if rst_in = '0' then -- synchronous reset (active low) data_bit_index_reg <= 0; state_reg <= IDLE; elsif rising_edge(clk_i) then -- rising clock edge data_bit_index_reg <= data_bit_index_next; state_reg <= state_next; end if; end process store_next; store_falling: process (clk_i) is begin -- process store_falling if falling_edge(clk_i) then transmit_bit_falling <= sr_q_o; end if; end process store_falling; 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, q_o => sr_q_o ); end architecture a1;