library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; use ieee.math_real.all; library work; entity master_endat is generic ( CLK_FREQ: integer ); port ( -- local clock clk: in std_logic; rst: in std_logic; -- master clock edges ma_clk_fedge: in std_logic; ma_clk_redge: in std_logic; -- the edge we are interested in ma_clk_edge: out std_logic; -- master clock reset -- if ma_clk_rst_en, use ma_clk_rst_level ma_clk_rst_en: out std_logic; ma_clk_rst_val: out std_logic; -- master out, slave in mosi: out std_logic; miso: in std_logic; -- gate to drive output (1 to drive it) gate: out std_logic; -- desired data length len: in unsigned; -- timeout counter tm_match: in std_logic; tm_top: out unsigned; -- general purpose counter count_top: out unsigned; count_match: in std_logic; count_rst: out std_logic; -- sipo register sipo_val: in std_logic_vector; sipo_latch: out std_logic; -- enable data conversion stages gray_to_bin_en: out std_logic; lsb_to_msb_en: out std_logic ); end entity; architecture absenc_master_endat_rtl of master_endat is -- -- default timeout value. standard says: 10 to 30 us constant TM_VAL: integer := work.absenc_pkg.us_to_count (work.absenc_pkg.MASTER_DEFAULT_TM_US, CLK_FREQ, tm_top'length); -- -- main state machine type endat_state_t is ( ENDAT_INIT, ENDAT_T0, ENDAT_T1, ENDAT_MODE, ENDAT_T3, ENDAT_T4, ENDAT_T5, ENDAT_START, ENDAT_F1, ENDAT_DATA, ENDAT_CRC5_FIRST, ENDAT_CRC5_CONT, ENDAT_DONE ); constant ENDAT_TMOUT: endat_state_t := ENDAT_DONE; constant ENDAT_ERR: endat_state_t := ENDAT_DONE; signal curr_state: endat_state_t; signal next_state: endat_state_t; -- -- right shifted parallel in, serial out register -- loaded values are in reverse order constant piso_ini: std_logic_vector := "111000"; signal piso_val: std_logic_vector(piso_ini'length - 1 downto 0); signal piso_load: std_logic; begin -- -- state automaton process begin wait until rising_edge(clk); if (rst = '1') then curr_state <= ENDAT_TMOUT; elsif ((tm_match or ma_clk_fedge) = '1') then curr_state <= next_state; end if; end process; process(curr_state, count_match, tm_match, miso) begin next_state <= curr_state; case curr_state is when ENDAT_INIT => next_state <= ENDAT_T0; when ENDAT_T0 => next_state <= ENDAT_T1; when ENDAT_T1 => next_state <= ENDAT_MODE; when ENDAT_MODE => if (count_match = '1') then next_state <= ENDAT_T3; end if; when ENDAT_T3 => next_state <= ENDAT_T4; when ENDAT_T4 => next_state <= ENDAT_T5; when ENDAT_T5 => next_state <= ENDAT_START; when ENDAT_START => if (miso = '1') then next_state <= ENDAT_F1; elsif (tm_match = '1') then next_state <= ENDAT_TMOUT; end if; when ENDAT_F1 => next_state <= ENDAT_DATA; when ENDAT_DATA => if (count_match = '1') then next_state <= ENDAT_CRC5_FIRST; end if; when ENDAT_CRC5_FIRST => next_state <= ENDAT_CRC5_CONT; when ENDAT_CRC5_CONT => if (count_match = '1') then next_state <= ENDAT_DONE; end if; when ENDAT_DONE => -- wait for at least one timeout next_state <= ENDAT_INIT; when others => next_state <= ENDAT_ERR; end case; end process; process begin wait until rising_edge(clk); ma_clk_rst_en <= '0'; count_top <= (count_top'range => '0'); count_rst <= '0'; sipo_latch <= '0'; gate <= '0'; mosi <= '0'; piso_load <= '0'; case curr_state is when ENDAT_INIT => gate <= '1'; when ENDAT_T0 => gate <= '1'; when ENDAT_T1 => piso_load <= '1'; gate <= '1'; count_top <= to_unsigned(6, count_top'length); count_rst <= '1'; when ENDAT_MODE => mosi <= piso_val(0); gate <= '1'; when ENDAT_T3 => mosi <= '0'; gate <= '1'; when ENDAT_T4 => mosi <= '0'; gate <= '1'; when ENDAT_T5 => when ENDAT_START => when ENDAT_F1 => count_top <= len(count_top'range); count_rst <= '1'; when ENDAT_DATA => -- sent LSb first when ENDAT_CRC5_FIRST => count_top <= to_unsigned(integer(5 - 1), count_top'length); count_rst <= '1'; sipo_latch <= '1'; when ENDAT_CRC5_CONT => when ENDAT_DONE => ma_clk_rst_en <= '1'; when others => end case; end process; -- -- right shifted piso register -- set at falling edge, sample by slave at redge process begin wait until rising_edge(clk); if (piso_load = '1') then piso_val <= piso_ini; elsif (ma_clk_fedge = '1') then piso_val <= '0' & piso_val(piso_val'length - 1 downto 1); end if; end process; -- -- clock reset or idle value ma_clk_rst_val <= '1'; -- -- timeout tm_top <= to_unsigned(TM_VAL, tm_top'length); -- -- gray to binary disabled gray_to_bin_en <= '0'; -- -- lsb to msb enabled lsb_to_msb_en <= '1'; -- -- use falling edge ma_clk_edge <= ma_clk_fedge; end architecture;