summaryrefslogtreecommitdiffstats
path: root/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd')
-rw-r--r--fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd299
1 files changed, 299 insertions, 0 deletions
diff --git a/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd b/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd
new file mode 100644
index 0000000..f37d0fb
--- /dev/null
+++ b/fpga/hw-v2/src/usbrx/datapath/usbrx_ad7357.vhd
@@ -0,0 +1,299 @@
+---------------------------------------------------------------------------------------------------
+-- 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 <http://www.gnu.org/licenses/>. --
+-----------------------------------------------------------------------------------
+
+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;