library IEEE; use IEEE.std_logic_1164.all; use ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; -- ADDR -- 0 ch1 & ch 0 24 bit readonly -- 1 ch3 & ch 2 24 bit readonly -- 2 ch5 & ch 4 24 bit readonly -- 3 ch7 & ch 6 24 bit readonly -- 0..3 writing here triggers the measurement cycle -- 4..7 CFR - writing sends the CFR(11:0) to the ADC -- bits 11. .0 - see TLV2548 datasheet -- bits 12 - 1/0 continuous/triggered entity seradc_auto is PORT ( CLK : in std_logic; -- Clock, 30 or 40 MHz RESET_n : in std_logic; -- reset -- to the internal bus CE : in std_logic; WE : in std_logic; ADDR : in std_logic_vector( 2 downto 0); WDATA : in std_logic_vector(23 downto 0); RDATA : out std_logic_vector(31 downto 0); -- ext status status : in std_logic_vector( 1 downto 0); cl : out std_logic_vector( 1 downto 0); -- current limit reached -- to the ADC ADC_INTn : in std_logic; ADC_nCSStrt : out std_logic; ADC_nCS : out std_logic; ADC_SCLK : out std_logic; ADC_SDI : out std_logic; ADC_SDO : in std_logic); end seradc_auto; architecture a of seradc_auto is component TLV2548 is PORT ( CLK : in std_logic; -- Clock, 30 or 40 MHz RESET_n : in std_logic; -- reset CE : in std_logic; CMD : in std_logic_vector( 3 downto 0); WDATA : in std_logic_vector(11 downto 0); RDATA : out std_logic_vector(11 downto 0); RDY : out std_logic; -- and ADC_nCS ADC_SCLK : out std_logic; ADC_SDI : out std_logic; ADC_SDO : in std_logic); end component; subtype adc_data is std_logic_vector(11 downto 0); type adc_matrix is array(0 to 7) of adc_data; signal adc_last : adc_matrix; type sm_type is (idle, send_config, start_meas, start_read, store_read, wait_conversion, wait_int, finish); signal sm : sm_type; signal cmd_adc : std_logic_vector( 3 downto 0); signal rdata_adc : std_logic_vector(11 downto 0); signal cfr : std_logic_vector(12 downto 0); -- current limits digital & analog signal climits_d : std_logic_vector(23 downto 0); signal climits_a : std_logic_vector(23 downto 0); signal send_cfr, start_cyc : std_logic; signal ce_adc, rdy_adc : std_logic; signal adc_int : std_logic; signal counter : std_logic_vector(2 downto 0); signal timer : Integer range 0 to 127; constant time_conversion : Integer := 127; constant time_sample : Integer := 127; signal adc_data_undef : adc_data; begin adc_data_undef <= (others =>'-'); -- configuration register and start process(clk, reset_n) begin if reset_n = '0' then cfr <= (others => '0'); send_cfr <= '0'; start_cyc <= '0'; adc_int <= '0'; climits_a <= (others => '1'); climits_d <= (others => '1'); elsif clk'event and clk='1' then start_cyc <= cfr(12); adc_int <= not ADC_INTn; send_cfr <= '0'; if ce='1' and we='1' then case addr(2 downto 0) is when "100" | "101" => cfr <= WDATA(cfr'range); send_cfr <= '1'; when "110" => climits_a <= WDATA(climits_a'range); when "111" => climits_d <= WDATA(climits_d'range); when "000" | "001" | "010" | "011" => start_cyc <= '1'; when others => cfr <= (others => '-'); climits_a <= (others => '-'); climits_d <= (others => '-'); start_cyc <= '-'; send_cfr <= '-'; end case; end if; end if; end process; adc: TLV2548 PORT map( CLK => CLK, RESET_n => RESET_n, CE => ce_adc, CMD => cmd_adc, WDATA => cfr(11 downto 0), RDATA => rdata_adc, RDY => rdy_adc, ADC_SCLK => ADC_SCLK, ADC_SDI => ADC_SDI, ADC_SDO => ADC_SDO); -- state machine process(clk, reset_n) begin if reset_n = '0' then sm <= idle; counter <= "000"; ce_adc <= '0'; cmd_adc <= "0000"; timer <= 0; ADC_nCSStrt <= '1'; elsif clk'event and clk='1' then ADC_nCSStrt <= '1'; ce_adc <= '0'; cmd_adc <= "----"; case sm is when idle => if send_cfr='1' then sm <= send_config; cmd_adc <= "1010"; ce_adc <= '1'; elsif start_cyc = '1' then sm <= start_meas; counter <= "000"; timer <= time_sample; end if; when send_config => sm <= finish; when start_meas => ADC_nCSStrt <= '0'; if timer = 0 then sm <= wait_conversion; timer <= time_conversion; counter <= counter + 1; else timer <= timer - 1; end if; when wait_conversion => if timer = 0 then if counter /= "000" then timer <= time_sample; sm <= start_meas; else sm <= wait_int; end if; else timer <= timer - 1; end if; when wait_int => counter <= "000"; -- if adc_int = '1' then sm <= start_read; ce_adc <= '1'; cmd_adc <= "1110"; -- read fifo -- end if; when start_read => if rdy_adc = '1' and ce_adc='0' then sm <= store_read; end if; when store_read => if counter = "111" then sm <= finish; else sm <= start_read; counter <= counter + 1; ce_adc <= '1'; cmd_adc <= "1110"; -- read fifo end if; when finish => if rdy_adc='1' then sm <= idle; end if; end case; end if; end process; process(clk) begin if clk'event and clk='1' then if sm = store_read then case counter is when "000" => adc_last(0) <= rdata_adc; when "001" => adc_last(1) <= rdata_adc; when "010" => adc_last(2) <= rdata_adc; when "011" => adc_last(3) <= rdata_adc; when "100" => adc_last(4) <= rdata_adc; when "101" => adc_last(5) <= rdata_adc; when "110" => adc_last(6) <= rdata_adc; when "111" => adc_last(7) <= rdata_adc; when others => adc_last <= (others => adc_data_undef); end case; end if; end if; end process; ADC_nCS <= rdy_adc; -- read mux omx: process(addr, adc_last, cfr, status) begin RDATA <= (others => '0'); RDATA(RDATA'high downto RDATA'high-1) <= status; case addr is when "000" => RDATA(23 downto 0) <= adc_last(1) & adc_last(0); when "001" => RDATA(23 downto 0) <= adc_last(3) & adc_last(2); when "010" => RDATA(23 downto 0) <= adc_last(5) & adc_last(4); when "011" => RDATA(23 downto 0) <= adc_last(7) & adc_last(6); when "100" | "101" => RDATA(cfr'range) <= cfr; when "110" => RDATA(climits_a'range) <= climits_a; when "111" => RDATA(climits_d'range) <= climits_d; when others => RDATA <= (others => '-'); end case; end process; process(clk, reset_n) begin if reset_n = '0' then cl <= (others => '0'); elsif clk'event and clk='1' then cl <= (others => '0'); -- 0 is analog, 1 is digital if adc_last(4) > climits_a(11 downto 0) then cl(0) <= '1'; end if; -- Current 3V3 PASA if adc_last(5) > climits_a(23 downto 12) then cl(1) <= '1'; end if; -- Current 3V3 digital IO if adc_last(6) > climits_d(11 downto 0) then cl(0) <= '1'; end if; -- Current 1V8 analog if adc_last(7) > climits_d(23 downto 12) then cl(1) <= '1'; end if; -- Current 1V8 digital core end if; end process; end;