]> jspc29.x-matter.uni-frankfurt.de Git - trbnet.git/commitdiff
added adc2308 readout, Jan
authorhadeshyp <hadeshyp>
Fri, 23 Jan 2009 18:08:15 +0000 (18:08 +0000)
committerhadeshyp <hadeshyp>
Fri, 23 Jan 2009 18:08:15 +0000 (18:08 +0000)
basics/ram_dp.vhd
special/adc_ltc2308_readout.vhd [new file with mode: 0644]
testbenches/testbench_adc_ltc2308_readout.prj [new file with mode: 0644]
testbenches/testbench_adc_ltc2308_readout.vhd [new file with mode: 0644]
trb_net_std.vhd

index c01dce1cf342670c9fa3ac59af88130067f6b7b7..a4c0f63ba0f6239ada2b68ad1f0b33e40bc15884 100644 (file)
@@ -6,7 +6,7 @@ USE IEEE.std_logic_UNSIGNED.ALL;
 library work;
 use work.trb_net_std.all;
 
-entity trb_net_ram_dp is
+entity ram_dp is
   generic(
     depth : integer := 3;
     width : integer := 16
@@ -22,9 +22,9 @@ entity trb_net_ram_dp is
     );
 end entity;
 
-architecture trb_net_ram_dp_arch of trb_net_ram_dp is
+architecture ram_dp_arch of ram_dp is
   type ram_t is array(0 to 2**depth-1) of std_logic_vector(width-1 downto 0);
-  SIGNAL ram : ram_t ;
+  SIGNAL ram : ram_t  := (others => (others => '0'));
 begin
 
 
diff --git a/special/adc_ltc2308_readout.vhd b/special/adc_ltc2308_readout.vhd
new file mode 100644 (file)
index 0000000..e63badf
--- /dev/null
@@ -0,0 +1,376 @@
+--sequential readout of all eight single-ended channels of a LT2306 ADC via SPI interface
+
+--Register Map
+--00     Control Register     0 Conversion Enable  1 single measurement  2 reset min/max/overview, 3 compare enable
+--01     Overview             1 nibble for each channel: 0 Voltage ok, 1 Voltage too low, 2 Voltage too high
+--10-17  Measurements         0-11 current value, 12-21 min value(10bit), 22-31 max value(10bit)
+--20-27  Voltage Range CTRL   0-11 min value  16-27 max value
+
+
+LIBRARY ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.trb_net_std.all;
+
+entity adc_ltc2308_readout is
+  generic(
+    CLOCK_FREQUENCY : integer := 100; --MHz
+    PRESET_RANGES : range_ram_t := (x"FFF_000",  x"B50_C10", x"480_4E0", x"510_6A0",
+                                --   -3           3           1.2         1.4
+                                --    ???         2.9-3.1     1.15-1.25   1.3-1.7
+                                    x"C80_D48", x"D48_ED8", x"A28_960", x"A28_960")
+                                --    3.3         3.5         5V/2        5V/2
+                                --    3.2-3.4     3.4-3.8     2.4-2.6     2.4-2.6
+
+    );
+  port(
+    CLK    : in std_logic;
+    RESET  : in std_logic;
+    CLK_EN : in std_logic;
+
+    ADC_SCK       : out std_logic;
+    ADC_SDI       : out std_logic;
+    ADC_SDO       : in  std_logic;
+    ADC_CONVST    : out std_logic;
+
+    DAT_ADDR_IN          : in  std_logic_vector(5 downto 0);
+    DAT_READ_EN_IN       : in  std_logic;
+    DAT_WRITE_EN_IN      : in  std_logic;
+    DAT_DATA_OUT         : out std_logic_vector(31 downto 0);
+    DAT_DATA_IN          : in  std_logic_vector(31 downto 0);
+    DAT_DATAREADY_OUT    : out std_logic;
+    DAT_NO_MORE_DATA_OUT : out std_logic;
+    DAT_WRITE_ACK_OUT    : out std_logic;
+    DAT_UNKNOWN_ADDR_OUT : out std_logic;
+    DAT_TIMEOUT_IN       : in  std_logic;
+
+    STAT_VOLTAGES_OUT    : out std_logic_vector(31 downto 0)
+    );
+end entity;
+
+architecture adc_readout_arch of adc_ltc2308_readout is
+
+  component ram_dp_rw is
+    generic(
+      depth : integer := 3;
+      width : integer := 12
+      );
+    port(
+      CLK   : in  std_logic;
+      wr1   : in  std_logic;
+      a1    : in  std_logic_vector(depth-1 downto 0);
+      din1  : in  std_logic_vector(width-1 downto 0);
+      a2    : in  std_logic_vector(depth-1 downto 0);
+      dout2 : out std_logic_vector(width-1 downto 0)
+      );
+  end component;
+
+  component signal_sync is
+    generic(
+      WIDTH : integer := 1;     --
+      DEPTH : integer := 3
+      );
+    port(
+      RESET    : in  std_logic; --Reset is neceessary to avoid optimization to shift register
+      CLK0     : in  std_logic;                          --clock for first FF
+      CLK1     : in  std_logic;                          --Clock for other FF
+      D_IN     : in  std_logic_vector(WIDTH-1 downto 0); --Data input
+      D_OUT    : out std_logic_vector(WIDTH-1 downto 0)  --Data output
+      );
+  end component;
+
+  component ram_dp is
+    generic(
+      depth : integer := 3;
+      width : integer := 16
+      );
+    port(
+      CLK   : in  std_logic;
+      wr1   : in  std_logic;
+      a1    : in  std_logic_vector(depth-1 downto 0);
+      dout1 : out std_logic_vector(width-1 downto 0);
+      din1  : in  std_logic_vector(width-1 downto 0);
+      a2    : in  std_logic_vector(depth-1 downto 0);
+      dout2 : out std_logic_vector(width-1 downto 0)
+      );
+  end component;
+
+  signal ram_write       : std_logic;
+  signal ram_addr        : std_logic_vector(2 downto 0);
+  signal ram_data        : std_logic_vector(31 downto 0);
+  signal ram_data_out    : std_logic_vector(31 downto 0);
+  signal timecounter     : unsigned(9 downto 0);
+  signal current_channel : std_logic_vector(2 downto 0);
+  signal last_channel    : std_logic_vector(2 downto 0);
+  signal output_data     : std_logic_vector(11 downto 6);
+  signal input_data      : std_logic_vector(11 downto 0);
+  signal reg_ADC_SDO     : std_logic;
+  type state_t is (IDLE, SEND_DATA, WAITING);
+  signal state           : state_t;
+  signal state_bits      : std_logic_vector(2 downto 0);
+  signal range_ram_wr        : std_logic;
+  signal range_ram_addr      : std_logic_vector(2 downto 0);
+  signal range_ram_data      : std_logic_vector(23 downto 0);
+  signal range_ram_data_out  : std_logic_vector(23 downto 0);
+  signal conv_enabled        : std_logic;
+  signal conv_single         : std_logic;
+  signal conv_single_clr     : std_logic;
+  signal conv_reset_clr      : std_logic;
+  signal conv_reset          : std_logic;
+  signal real_conv_reset     : std_logic;
+  signal conv_compare_enable : std_logic;
+  signal current_minimum     : std_logic_vector(11 downto 0);
+  signal current_maximum     : std_logic_vector(11 downto 0);
+  signal status_overview     : std_logic_vector(31 downto 0);
+  signal value_ram_data      : std_logic_vector(31 downto 0);
+  signal value_ram_addr      : std_logic_vector(2 downto 0);
+  signal last_DAT_READ_EN_IN : std_logic;
+
+  signal range_ram : range_ram_t := PRESET_RANGES;
+  signal first_sequence_after_stop : std_logic;
+
+begin
+
+  assert CLOCK_FREQUENCY <= 200
+  report "The clock frequency is too high, timing requirements of ADC not met."
+  severity FAILURE;
+
+
+
+  state_bits(0) <= '1' when state = IDLE else '0';
+  state_bits(1) <= '1' when state = SEND_DATA else '0';
+  state_bits(2) <= '1' when state = WAITING else '0';
+
+
+  THE_VALUE_RAM : ram_dp
+    generic map(
+      depth => 3,
+      width => 32
+      )
+    port map(
+      CLK   => CLK,
+      wr1   => ram_write,
+      a1    => ram_addr,
+      din1  => ram_data,
+      dout1 => ram_data_out,
+      a2    => value_ram_addr,
+      dout2 => value_ram_data
+      );
+
+  ram_addr  <= last_channel;
+  value_ram_addr <= range_ram_addr;
+
+
+
+  THE_RANGE_RAM : process(CLK)
+    begin
+      if rising_edge(CLK) then
+        if range_ram_wr = '1' then
+          range_ram(to_integer(unsigned(range_ram_addr))) <= range_ram_data;
+        end if;
+        range_ram_data_out <= range_ram(to_integer(unsigned(range_ram_addr)));
+        current_minimum <= range_ram(to_integer(unsigned(last_channel)))(11 downto 0);
+        current_maximum <= range_ram(to_integer(unsigned(last_channel)))(23 downto 12);
+      end if;
+    end process;
+
+
+  THE_ADC_SDO_sync : signal_sync
+    generic map(
+      WIDTH => 1,
+      DEPTH => 2
+      )
+    port map(
+      RESET    => RESET,
+      CLK0     => CLK,
+      CLK1     => CLK,
+      D_IN(0)  => ADC_SDO,
+      D_OUT(0) => reg_ADC_SDO
+      );
+
+
+
+  proc_fsm : process(CLK)
+    begin
+      if rising_edge(CLK) then
+        if RESET = '1' then
+          state           <= IDLE;
+          ADC_SCK         <= '0';
+          ADC_CONVST      <= '1';
+          ram_write       <= '0';
+          last_channel    <= "111";
+          current_channel <= "000";
+          input_data      <= (others => '0');
+          timecounter     <= (others => '0');
+          status_overview <= (others => '0');
+          first_sequence_after_stop <= '1';
+          real_conv_reset <= '0';
+          conv_reset_clr  <= '0';
+        elsif CLK_EN = '1' then
+          timecounter <= timecounter + to_unsigned(1,1);
+          case state is
+            when IDLE =>
+              -- output bits: singleended/not differential & channel number(3) & unipolar/not bipolar & sleepmode
+              output_data     <= "1" & current_channel & "00";
+              input_data      <= (others => '0');
+              timecounter     <= (others => '0');
+              ADC_SCK         <= '0';
+              ram_write       <= '0';
+              conv_single_clr <= '0';
+              if conv_enabled = '1' or conv_single = '1' then
+                state           <= SEND_DATA;
+                ADC_CONVST      <= '0';       --wake up device from nap,
+              else
+                current_channel <= "000";
+                state <= IDLE;
+              end if;
+
+            when SEND_DATA =>
+              if timecounter(2 downto 0) = 0 then
+                ADC_SDI                  <= output_data(output_data'left);
+                ADC_SCK                  <= '0';
+                output_data              <= output_data(output_data'left -1 downto output_data'right) & '0';
+              elsif timecounter(2 downto 0) = 4 then
+                ADC_SCK                  <= '1';
+              elsif timecounter(2 downto 0) = 6 then   --read on rising_edge, but delayed by two FF
+                input_data               <= input_data(input_data'left -1 downto 0) & reg_ADC_SDO;
+              end if;
+              if timecounter(6 downto 3) = 12 then     --read/wrote 12 Bits
+                state                    <= WAITING;
+                ram_data                 <= ram_data_out;
+                ram_write                <= not first_sequence_after_stop;
+                ram_data(11 downto 0)    <= input_data;
+                if unsigned(input_data(11 downto 2)) < unsigned(ram_data_out(21 downto 12)) or real_conv_reset = '1' then
+                  ram_data(21 downto 12) <= input_data(11 downto 2);
+                end if;
+                if unsigned(input_data(11 downto 2)) > unsigned(ram_data_out(31 downto 22)) or real_conv_reset = '1' then
+                  ram_data(31 downto 22) <= input_data(11 downto 2);
+                end if;
+
+                if conv_compare_enable = '1' and first_sequence_after_stop = '0' then
+                  if input_data < current_minimum then   --too low
+                    status_overview(to_integer(unsigned(last_channel))*4+1) <= '1';
+                    status_overview(to_integer(unsigned(last_channel))*4)   <= '0';
+                  elsif input_data > current_maximum then--too high
+                    status_overview(to_integer(unsigned(last_channel))*4+2) <= '1';
+                    status_overview(to_integer(unsigned(last_channel))*4)   <= '0';
+                  else
+                    status_overview(to_integer(unsigned(last_channel))*4)   <= '1';
+                  end if;
+                end if;
+              end if;
+
+            when WAITING =>
+              ram_write           <= '0';
+              if timecounter(7) = '1' then  --after 128 clock cycles = at least 640 ns after first bit
+                ADC_CONVST        <= '1';       --left high until conv. finished to get into nap-sleep mode
+              end if;
+              if timecounter(9) = '1' then  --after 512 clock cycles = at least 2560 ns after first bit
+                state             <= IDLE;
+                current_channel   <= std_logic_vector(unsigned(current_channel) + to_unsigned(1,1));
+                last_channel    <= current_channel;
+                first_sequence_after_stop <= '0';
+                if current_channel = "111" then
+                  conv_single_clr <= conv_single;   --end single run after channel 8
+                  real_conv_reset <= conv_reset and not real_conv_reset;
+                  conv_reset_clr  <= real_conv_reset;
+                end if;
+              end if;
+
+            when others =>
+              state           <= IDLE;
+          end case;
+          if real_conv_reset = '1' then          --clear status bits on request
+            status_overview <= (others => '0');
+          end if;
+        end if;
+      end if;
+    end process;
+
+
+
+
+  proc_reg_ctrl : process(CLK)
+    begin
+      if rising_edge(CLK) then
+        if RESET = '1' then
+          DAT_UNKNOWN_ADDR_OUT <= '0';
+          DAT_WRITE_ACK_OUT    <= '0';
+          DAT_NO_MORE_DATA_OUT <= '0';
+          DAT_DATAREADY_OUT    <= '0';
+          DAT_DATA_OUT         <= (others => '0');
+          range_ram_wr         <= '0';
+          conv_enabled         <= '0';
+          conv_single          <= '0';
+          conv_reset           <= '0';
+          conv_compare_enable  <= '0';
+          last_DAT_READ_EN_IN  <= '0';
+        elsif CLK_EN = '1' then
+          DAT_UNKNOWN_ADDR_OUT <= '0';
+          DAT_WRITE_ACK_OUT    <= '0';
+          DAT_NO_MORE_DATA_OUT <= '0';
+          DAT_DATAREADY_OUT    <= '0';
+          range_ram_wr         <= '0';
+          conv_single          <= conv_single and not conv_single_clr;
+          conv_reset           <= conv_reset  and not conv_reset_clr;
+          range_ram_addr       <= DAT_ADDR_IN(2 downto 0);
+          range_ram_data       <= DAT_DATA_IN(27 downto 16) & DAT_DATA_IN(11 downto 0);
+          last_DAT_READ_EN_IN  <= '0';
+
+          if DAT_WRITE_EN_IN = '1' then
+            case DAT_ADDR_IN is
+              when "000000" =>
+                conv_enabled      <= DAT_DATA_IN(0);
+                conv_single       <= DAT_DATA_IN(1);
+                conv_reset        <= DAT_DATA_IN(2);
+                conv_compare_enable <= DAT_DATA_IN(3);
+                DAT_WRITE_ACK_OUT <= '1';
+              when "100---" =>
+                range_ram_wr      <= '1';
+                DAT_WRITE_ACK_OUT <= '1';
+              when others   =>
+                  DAT_UNKNOWN_ADDR_OUT <= '1';
+            end case;
+          end if;
+          if DAT_READ_EN_IN = '1' or last_DAT_READ_EN_IN = '1' then
+            case DAT_ADDR_IN is
+              when "000000" =>
+                DAT_DATA_OUT          <= (0 => conv_enabled, 1 => conv_single, 3 => conv_compare_enable, others => '0');
+                DAT_DATAREADY_OUT     <= '1';
+              when "000001" =>
+                DAT_DATA_OUT          <= status_overview;
+                DAT_DATAREADY_OUT     <= '1';
+              when "010---" =>
+                DAT_DATA_OUT(31 downto 0) <= value_ram_data;
+                if DAT_READ_EN_IN = '1' then
+                  last_DAT_READ_EN_IN <= '1';
+                else
+                  last_DAT_READ_EN_IN <= '0';
+                  DAT_DATAREADY_OUT   <= '1';
+                end if;
+              when "100---" =>
+                DAT_DATA_OUT(11 downto 0)  <= range_ram_data_out(11 downto 0);
+                DAT_DATA_OUT(15 downto 12) <= (others => '0');
+                DAT_DATA_OUT(27 downto 16) <= range_ram_data_out(23 downto 12);
+                DAT_DATA_OUT(31 downto 28) <= (others => '0');
+                if DAT_READ_EN_IN = '1' then
+                  last_DAT_READ_EN_IN <= '1';
+                else
+                  last_DAT_READ_EN_IN <= '0';
+                  DAT_DATAREADY_OUT   <= '1';
+                end if;
+              when others  =>
+                DAT_UNKNOWN_ADDR_OUT <= '1';
+            end case;
+          end if;
+        end if;
+      end if;
+    end process;
+
+
+  STAT_VOLTAGES_OUT    <= status_overview;
+  DAT_NO_MORE_DATA_OUT <= '0';
+
+end architecture;
diff --git a/testbenches/testbench_adc_ltc2308_readout.prj b/testbenches/testbench_adc_ltc2308_readout.prj
new file mode 100644 (file)
index 0000000..d038da3
--- /dev/null
@@ -0,0 +1,5 @@
+vhdl work "../trb_net_std.vhd"
+vhdl work "../basics/ram_dp.vhd"
+vhdl work "../basics/signal_sync.vhd"
+vhdl work "../special/adc_ltc2308_readout.vhd"
+vhdl work "testbench_adc_ltc2308_readout.vhd"
diff --git a/testbenches/testbench_adc_ltc2308_readout.vhd b/testbenches/testbench_adc_ltc2308_readout.vhd
new file mode 100644 (file)
index 0000000..d7e0266
--- /dev/null
@@ -0,0 +1,114 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.trb_net_std.all;
+
+entity testbench is
+end entity;
+
+architecture testbench_arch of testbench is
+
+
+  component adc_ltc2308_readout
+    generic(
+      CLOCK_FREQUENCY : integer := 100; --MHz
+      PRESET_RANGES : range_ram_t := (x"FFF_000",  x"B50_C10", x"480_4E0", x"510_6A0",
+                                  --   -3           3           1.2         1.4
+                                  --    ???         2.9-3.1     1.15-1.25   1.3-1.7
+                                      x"C80_D48", x"D48_ED8", x"A28_960", x"A28_960")
+                                  --    3.3         3.5         5V/2        5V/2
+                                  --    3.2-3.4     3.4-3.8     2.4-2.6     2.4-2.6
+
+      );
+    port(
+      CLK    : in std_logic;
+      RESET  : in std_logic;
+      CLK_EN : in std_logic;
+
+      ADC_SCK       : out std_logic;
+      ADC_SDI       : out std_logic;
+      ADC_SDO       : in  std_logic;
+      ADC_CONVST    : out std_logic;
+
+      DAT_ADDR_IN          : in  std_logic_vector(5 downto 0);
+      DAT_READ_EN_IN       : in  std_logic;
+      DAT_WRITE_EN_IN      : in  std_logic;
+      DAT_DATA_OUT         : out std_logic_vector(31 downto 0);
+      DAT_DATA_IN          : in  std_logic_vector(31 downto 0);
+      DAT_DATAREADY_OUT    : out std_logic;
+      DAT_NO_MORE_DATA_OUT : out std_logic;
+      DAT_WRITE_ACK_OUT    : out std_logic;
+      DAT_UNKNOWN_ADDR_OUT : out std_logic;
+      DAT_TIMEOUT_IN       : in  std_logic;
+
+      STAT_VOLTAGES_OUT    : out std_logic_vector(31 downto 0)
+      );
+    end component;
+
+  signal CLK         :  std_logic := '1';
+  signal RESET       :  std_logic := '1';
+  signal CLK_EN      :  std_logic := '1';
+  signal ADC_SDO     :  std_logic := '0';
+  signal ADC_SCK     :  std_logic;
+  signal ADC_SDI     :  std_logic;
+  signal ADC_CONVST  :  std_logic;
+
+  signal DAT_ADDR_IN          :  std_logic_vector(5 downto 0) := "000000";
+  signal DAT_READ_EN_IN       :  std_logic := '0';
+  signal DAT_WRITE_EN_IN      :  std_logic := '0';
+  signal DAT_DATA_OUT         :  std_logic_vector(31 downto 0);
+  signal DAT_DATA_IN          :  std_logic_vector(31 downto 0);
+  signal DAT_DATAREADY_OUT    :  std_logic;
+  signal DAT_NO_MORE_DATA_OUT :  std_logic;
+  signal DAT_WRITE_ACK_OUT    :  std_logic;
+  signal DAT_UNKNOWN_ADDR_OUT :  std_logic;
+  signal DAT_TIMEOUT_IN       :  std_logic := '0';
+
+
+
+
+begin
+  CLK <= not CLK after 5 ns;
+  RESET <= '0' after 50 ns;
+
+
+  uut: adc_ltc2308_readout
+    port map(
+      CLK => CLK,
+      RESET => RESET,
+      CLK_EN => CLK_EN,
+      ADC_SCK => ADC_SCK,
+      ADC_SDI => ADC_SDI,
+      ADC_SDO => ADC_SDO,
+      ADC_CONVST => ADC_CONVST,
+      DAT_ADDR_IN          => DAT_ADDR_IN,
+      DAT_READ_EN_IN       => DAT_READ_EN_IN,
+      DAT_WRITE_EN_IN      => DAT_WRITE_EN_IN,
+      DAT_DATA_OUT         => DAT_DATA_OUT,
+      DAT_DATA_IN          => DAT_DATA_IN,
+      DAT_DATAREADY_OUT    => DAT_DATAREADY_OUT,
+      DAT_NO_MORE_DATA_OUT => DAT_NO_MORE_DATA_OUT,
+      DAT_WRITE_ACK_OUT    => DAT_WRITE_ACK_OUT,
+      DAT_UNKNOWN_ADDR_OUT => DAT_UNKNOWN_ADDR_OUT,
+      DAT_TIMEOUT_IN       => DAT_TIMEOUT_IN
+      );
+
+ADC_SDO <= '0';
+
+--Register Map
+--00     Control Register     0 Conversion Enable  1 single measurement  2 reset min/max/overview, 3 compare enable
+--01     Overview             1 nibble for each channel: 0 Voltage ok, 1 Voltage too low, 2 Voltage too high
+--10-17  Measurements         0-11 current value, 12-21 min value(10bit), 22-31 max value(10bit)
+--20-27  Voltage Range CTRL   0-11 min value  16-27 max value
+DAT_DATA_IN <= x"00000000", x"0000000D" after 2001ns, x"00000000" after 2021ns;--,
+--                            x"00000000" after 15001ns, x"00000000" after 15021ns,
+--                            x"0000000A" after 29001ns, x"00000000" after 29021ns;
+DAT_ADDR_IN <= "000000";
+DAT_WRITE_EN_IN <= '0', '1' after 2001ns,'0' after 2021ns;--,
+--                        '1' after 15001ns,'0' after 15021ns,
+--                        '1' after 29001ns,'0' after 29021ns;
+
+
+end architecture;
index 15ad93eca3e04de4dd8f887ae20b0b44c3dbd9c1..1947143bca8abf13ba53368450dd20ba7826a61a 100644 (file)
@@ -7,6 +7,8 @@ USE IEEE.std_logic_UNSIGNED.ALL;
 package trb_net_std is
 
   type channel_config_t is array(0 to 3) of integer;
+  type array_32_t is array(integer range <>) of std_logic_vector(31 downto 0);
+  type range_ram_t is array(7 downto 0) of std_logic_vector(23 downto 0);
 
 -- some basic definitions for the whole network
 -----------------------------------------------
@@ -152,6 +154,8 @@ package trb_net_std is
   function Log2( input:integer ) return integer;
   function count_ones( input:std_logic_vector ) return integer;
 
+
+
 end package trb_net_std;
 
 package body trb_net_std is