From: hadeshyp Date: Fri, 23 Jan 2009 18:08:15 +0000 (+0000) Subject: added adc2308 readout, Jan X-Git-Tag: oldGBE~491 X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=1ddc744a376bb16cd24ce54d1f0feaad49c201e3;p=trbnet.git added adc2308 readout, Jan --- diff --git a/basics/ram_dp.vhd b/basics/ram_dp.vhd index c01dce1..a4c0f63 100644 --- a/basics/ram_dp.vhd +++ b/basics/ram_dp.vhd @@ -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 index 0000000..e63badf --- /dev/null +++ b/special/adc_ltc2308_readout.vhd @@ -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 index 0000000..d038da3 --- /dev/null +++ b/testbenches/testbench_adc_ltc2308_readout.prj @@ -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 index 0000000..d7e0266 --- /dev/null +++ b/testbenches/testbench_adc_ltc2308_readout.vhd @@ -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; diff --git a/trb_net_std.vhd b/trb_net_std.vhd index 15ad93e..1947143 100644 --- a/trb_net_std.vhd +++ b/trb_net_std.vhd @@ -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