--------------------------------------------------------------------------------------------------- -- Filename : usbrx_ad7357.vhd -- Project : OsmoSDR FPGA Firmware -- Purpose : AD7357 Interface --------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------- -- Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany -- -- written by Matthias Kleffel -- -- -- -- This program is free software; you can redistribute it and/or modify -- -- it under the terms of the GNU General Public License as published by -- -- the Free Software Foundation as version 3 of the License, or -- -- -- -- This program is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- -- GNU General Public License V3 for more details. -- -- -- -- You should have received a copy of the GNU General Public License -- -- along with this program. If not, see . -- ----------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library xp2; use xp2.all; use xp2.components.all; library work; use work.all; use work.mt_toolbox.all; use work.usbrx.all; entity usbrx_ad7357 is port( -- common clk : in std_logic; reset : in std_logic; -- config config : in usbrx_adc_config_t; -- ADC interface adc_cs : out std_logic; adc_sck : out std_logic; adc_sd1 : in std_logic; adc_sd2 : in std_logic; -- output out_clk : out std_logic; out_i : out unsigned(13 downto 0); out_q : out unsigned(13 downto 0) ); end usbrx_ad7357; architecture rtl of usbrx_ad7357 is -- internal types type state_t is (S_ACQUISITION, S_CONVERT); -- main status signal state : state_t; signal counter : unsigned(7 downto 0); -- SCK generator signal cg_div : unsigned(7 downto 0); signal cg_count : unsigned(7 downto 0); signal cg_phase : std_logic; signal cg_ddr_a : std_logic; signal cg_ddr_b : std_logic; signal cg_renxt : std_logic; signal cg_redge : std_logic; -- chip select (+ delayed versions) signal css : std_logic_vector(3 downto 0); -- latch input on rising/falling edge of current cycle -- (+ delayed versions) signal latch_r : std_logic_vector(3 downto 0); signal latch_f : std_logic_vector(3 downto 0); -- input register stage #1 signal sd1_s1r : std_logic; -- SD1 - rising edge signal sd1_s1f : std_logic; -- SD1 - falling edge signal sd2_s1r : std_logic; -- SD2 - rising edge signal sd2_s1f : std_logic; -- SD2 - falling edge -- input register stage #2 signal sd1_s2r : std_logic; -- SD1 - rising edge signal sd1_s2f : std_logic; -- SD1 - falling edge signal sd2_s2r : std_logic; -- SD2 - rising edge signal sd2_s2f : std_logic; -- SD2 - falling edge -- input shift registers signal sreg1 : std_logic_vector(13 downto 0); signal sreg2 : std_logic_vector(13 downto 0); -- output latches signal onew : std_logic; signal oreg1 : std_logic_vector(13 downto 0); signal oreg2 : std_logic_vector(13 downto 0); begin -- SCL clock generator logic process(clk) begin if rising_edge(clk) then -- set default values cg_renxt <= '0'; cg_redge <= cg_renxt; latch_r <= latch_r(latch_r'left-1 downto 0) & '0'; latch_f <= latch_f(latch_f'left-1 downto 0) & '0'; -- get config cg_div <= config.clkdiv; -- get operation mode if cg_div=0 or cg_div=1 then --> full speed, just pass through clock cg_ddr_a <= '0'; cg_ddr_b <= '1'; cg_renxt <= '1'; latch_f(0) <= '1'; else --> divided clock, update divider-logic if cg_count=0 then -- toggle clock on FE in middle of cycle cg_count <= cg_div - 2; cg_phase <= not cg_phase; cg_ddr_a <= cg_phase; cg_ddr_b <= not cg_phase; cg_renxt <= not cg_phase; latch_r(0) <= cg_phase; elsif cg_count=1 then -- toggle clock on RE after this cycle cg_count <= cg_div - 1; cg_phase <= '0'; --not cg_phase; cg_ddr_a <= '1'; --cg_phase; cg_ddr_b <= '1'; --cg_phase; latch_f(0) <= '1'; else -- leave clock unchanged cg_count <= cg_count - 2; cg_ddr_a <= cg_phase; cg_ddr_b <= cg_phase; end if; -- failsafe if cg_count=1 and cg_div(0)='0' then cg_count <= cg_div - 2; end if; end if; -- handle reset if reset='1' then cg_div <= (others=>'1'); cg_count <= (others=>'0'); cg_phase <= '0'; cg_renxt <= '0'; cg_redge <= '0'; cg_ddr_a <= '1'; cg_ddr_b <= '1'; latch_r <= (others=>'0'); latch_f <= (others=>'0'); end if; end if; end process; -- output register for SCLK oddr: ODDRXC port map ( clk => clk, rst => reset, da => cg_ddr_a, db => cg_ddr_b, q => adc_sck ); -- main control logig process(clk) begin if rising_edge(clk) then -- set default values css <= css(css'left-1 downto 0) & css(0); -- update status case state is when S_ACQUISITION => -- doing ACQUISITION, wait until ready to start conversion if cg_redge='1' then -- new SCLK cycle, check if wait-counter has ellapsed counter <= counter - 1; if counter<=1 then --> counter ellapsed, start conversion state <= S_CONVERT; counter <= to_unsigned(15,counter'length); css(0) <= '0'; end if; end if; when S_CONVERT => -- doing conversion, wait until all bits are clocked out if cg_redge='1' then -- new SCLK cycle, check if bit-counter has ellapsed counter <= counter - 1; if counter=0 then -- all bits received, return to ACQUISITION state state <= S_ACQUISITION; counter <= config.acqlen; css(0) <= '1'; end if; end if; end case; -- handle reset if reset='1' then state <= S_ACQUISITION; -- TODO counter <= (others=>'0'); css <= (others=>'1'); end if; end if; end process; -- output chip-select adc_cs <= css(0); -- input capture registers iddr1: IDDRXC port map ( clk => clk, rst => '0', ce => '1', d => adc_sd1, qa => sd1_s1r, qb => sd1_s1f ); iddr2: IDDRXC port map ( clk => clk, rst => '0', ce => '1', d => adc_sd2, qa => sd2_s1r, qb => sd2_s1f ); -- input data handling process(clk) begin if rising_edge(clk) then -- set default valies onew <= '0'; -- register input-bits once more sd1_s2r <= sd1_s1r; sd1_s2f <= sd1_s1f; sd2_s2r <= sd2_s1r; sd2_s2f <= sd2_s1f; -- update shift-registers if latch_r(3)='1' then sreg1 <= sreg1(12 downto 0) & sd1_s2r; sreg2 <= sreg2(12 downto 0) & sd2_s2r; elsif latch_f(3)='1' then sreg1 <= sreg1(12 downto 0) & sd1_s2f; sreg2 <= sreg2(12 downto 0) & sd2_s2f; end if; -- latch away shift-register when requested if css(2)='1' and css(3)='0' then onew <= '1'; oreg1 <= sreg1; oreg2 <= sreg2; end if; -- handle reset if reset='1' then sd1_s2r <= '0'; sd1_s2f <= '0'; sd2_s2r <= '0'; sd2_s2f <= '0'; sreg1 <= (others=>'0'); sreg2 <= (others=>'0'); oreg1 <= (others=>'0'); oreg2 <= (others=>'0'); onew <= '0'; end if; end if; end process; -- set output out_clk <= onew; out_i <= unsigned(oreg1); out_q <= unsigned(oreg2); end rtl;