library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library UNISIM; use UNISIM.VComponents.all; entity AD7960_conversion_freq is Generic ( num_bits : positive := 16; clk_freq : positive := 100; -- MHz sync_clk_freq : positive := 220; --MHz tMSB : positive := 300; -- ns tCNVH : positive := 130 -- ns ); Port ( DINp : in STD_LOGIC; -- data in (positive logic) DCOp : out STD_LOGIC; -- data clock out (positive logic) DCIp : in STD_LOGIC; -- data clock in from ADC (positive logic) CNVp : out STD_LOGIC; -- conversion start to ADC (positive logic) clk : in STD_LOGIC; -- clock for the data operations sync_clk: in STD_LOGIC; -- sync clock (system frequency) aresetn : in STD_LOGIC; -- reset conv : in STD_LOGIC; -- conversion frequency data : out STD_LOGIC_VECTOR(num_bits-1 downto 0); -- data output in 16 bit for AD7961, 18 for AD7960 dvalid : out STD_LOGIC); -- data valid, not used in current design end AD7960_conversion_freq; architecture Behavioral of AD7960_conversion_freq is signal din : std_logic; signal dclkin : std_logic; signal cnv : std_logic; signal dataregister : std_logic_vector(num_bits-1 downto 0); signal data_clk_synced : std_logic_vector(1 downto 0); signal data_in_synced : std_logic_vector(1 downto 0); signal synced_clk : std_logic_vector(1 downto 0); signal conv_synced : std_logic_vector(1 downto 0); signal count_bits : integer range 0 to num_bits; -- counting the bits when the ADC is clocking the data out signal enableclkout : std_logic; signal cnv_counter: integer range 0 to 512; -- count the time after 0-1 transition of conv in for the conversion out going down signal msb_counter: integer range 0 to 512; -- count the time after 0-1 transition of conv in for MSB signal clkout_counter: integer range 0 to 32; -- count the number of clock cycles going to the ADC TYPE states_cnv IS (idle, pulse, end_pulse, wait_low); TYPE state_data IS (init, read, data_out); signal state_cnv: states_cnv := idle; signal next_state_cnv: states_cnv := idle; TYPE states_clkout IS (idle, clocking); signal state_clkout: states_clkout := idle; signal next_state_clkout: states_clkout := idle; TYPE states_msb IS (idle, wait_msb, read_msb); signal state_msb: states_cnv := idle; signal next_state_msb: states_cnv := idle; signal trigger_msb : std_logic; --signal next_state: state_deser := init; signal data_state: state_data := init; signal data_next_state: state_data := init; ------NEW TYPE states_cnv_new IS (counting, idle); signal resetn : std_logic_vector(1 downto 0); begin -- assign the ports to the signals din <= DINp; dclkin <= DCIp; CNVp <= cnv; --enable the output clock clock_out: process (sync_clk, enableclkout) begin DCOp <= enableclkout AND clk; end process; synchronisation : process (sync_clk, clk, dclkin, conv, din) begin if rising_edge(sync_clk) then synced_clk <= synced_clk(0) & clk; data_clk_synced <= data_clk_synced(0) & dclkin; conv_synced <= conv_synced(0) & conv; data_in_synced <= data_in_synced(0) & din; resetn <= resetn(0) & aresetn; end if; end process; cnvst_statemachine : PROCESS (sync_clk, aresetn, state_cnv, conv_synced, cnv_counter) BEGIN if aresetn = '0' then -- reset cnv <= '0'; cnv_counter <= 1; state_cnv <= idle; elsif rising_edge(sync_clk) then -- on sync clock state_cnv <= next_state_cnv; case state_cnv is when idle => if conv_synced(1) = '1' then -- idle mode cnv <= '0'; cnv_counter <= 1; next_state_cnv <= pulse; -- we have a 0-1 transition on conv, we output the CONVST pulse end if; when pulse => cnv_counter <= cnv_counter + 1; -- output the CONVST pulse and count the time cnv <= '1'; if cnv_counter = (clk_freq * tCNVH / 1000) then next_state_cnv <= end_pulse; -- we are done with the CONVST pulse end if; when end_pulse => cnv <= '0'; -- drive CONVST low cnv_counter <= cnv_counter; next_state_cnv <= wait_low; when wait_low => if conv_synced(1) = '0' then -- wait for another trigger from conv cnv <= '0'; next_state_cnv <= idle; end if; end case; end if; END PROCESS cnvst_statemachine; msb_statemachine : PROCESS (sync_clk, aresetn, state_msb, conv_synced, msb_counter) BEGIN if (aresetn = '0') then trigger_msb <= '0'; msb_counter <= 1; state_msb <= idle; ELSIF rising_edge(sync_clk) THEN state_msb <= next_state_msb; -- same timing structure as with CONVST case state_msb is when idle => trigger_msb <= '0'; msb_counter <= 1; if conv_synced(1) = '1' then next_state_msb <= pulse; end if; when pulse => trigger_msb <= '0'; msb_counter <= msb_counter + 1; if msb_counter = (clk_freq * tMSB / 1000) - 1 then -- waiting for the pulse next_state_msb <= end_pulse; end if; when end_pulse => trigger_msb <= '1'; msb_counter <= 1; next_state_msb <= wait_low; when wait_low => trigger_msb <= '0'; if conv_synced(1) = '0' then next_state_msb <= idle; end if; end case; end if; END PROCESS msb_statemachine; clkout_statemachine : PROCESS (clk, trigger_msb) BEGIN if aresetn = '0' then -- reset mode enableclkout <= '0'; state_clkout <= idle; clkout_counter <= 1; elsif (clk = '1' and clk'event) then state_clkout <= next_state_clkout; case state_clkout is when idle => enableclkout <= '0'; -- when untriggered, the conversion clock is low clkout_counter <= 1; if trigger_msb = '1' then next_state_clkout <= clocking; -- end of MSB wait time triggers the conversion clock end if; when clocking => enableclkout <= '1'; clkout_counter <= clkout_counter + 1; if clkout_counter = num_bits-1 then next_state_clkout <= idle; -- after the required number of bits, the clock is deactivated end if; end case; end if; END PROCESS clkout_statemachine; data_statemachine : PROCESS (sync_clk, conv_synced, aresetn) BEGIN IF aresetn = '0' THEN data_state <= init; ELSIF (sync_clk'EVENT AND sync_clk = '1') THEN CASE data_state IS WHEN init => -- init state, there is no data clocked yet IF next_state_cnv = end_pulse THEN data_state <= read; END IF; WHEN read => IF data_next_state = data_out THEN -- we are in the data state where data is clocked from the ADC data_state <= data_out; END IF; WHEN data_out => IF data_next_state = init THEN -- data is ready and written to the output register data_state <= init; -- we go back to the init state END IF; END CASE; END IF; END PROCESS; data_process : PROCESS (aresetn, data_state, data_clk_synced, sync_clk) BEGIN CASE data_state IS WHEN init => count_bits <= 0; WHEN read => IF rising_edge(sync_clk) THEN IF (data_clk_synced = "10") THEN -- on every data clock transition from 0-1 we read the data to the register dvalid <= '0'; case count_bits is when 0 => dataregister(15) <= data_in_synced(1); when 1 => dataregister(14) <= data_in_synced(1); when 2 => dataregister(13) <= data_in_synced(1); when 3 => dataregister(12) <= data_in_synced(1); when 4 => dataregister(11) <= data_in_synced(1); when 5 => dataregister(10) <= data_in_synced(1); when 6 => dataregister(9) <= data_in_synced(1); when 7 => dataregister(8) <= data_in_synced(1); when 8 => dataregister(7) <= data_in_synced(1); when 9 => dataregister(6) <= data_in_synced(1); when 10 => dataregister(5) <= data_in_synced(1); when 11 => dataregister(4) <= data_in_synced(1); when 12 => dataregister(3) <= data_in_synced(1); when 13 => dataregister(2) <= data_in_synced(1); when 14 => dataregister(1) <= data_in_synced(1); when others => NULL; end case; IF (count_bits > 14) THEN -- all required bits are read, only the last one must be saved dataregister(0) <= data_in_synced(1); data_next_state <= data_out; ELSE count_bits <= count_bits + 1; -- increment only when the register is not read yet END IF; END IF; END IF; WHEN data_out => count_bits <= 0; -- reset the counted bits data <= dataregister; -- write the data register to the data port dvalid <= '1'; -- validate the data on the dvalid out data_next_state <= init; -- back to the init state END CASE; END PROCESS; end Behavioral;