Subversion Repositories f9daq

Rev

Blame | Last modification | View Log | RSS feed

----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 24.10.2018 17:44:30
-- Design Name:
-- Module Name: ADC_unit - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;



-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity ADC_unit is
   
    generic ( adc_bit_num : natural := 14; --input data from ad converter is 14 bit
              bit_num : natural := 10; -- number of bits for our data (scaled from 14 bit to 10 bit)
              num_of_units: natural := 2; -- number of BRAM_buffer and PE_unit units
              buffer_size: natural := 5; --size of each BRAM_buffer in bits
              mode: string := "MODE_3"; -- modes of operation: MODE_1 = navaden algoritm, MODE_2 = odklop bufferja in 1 enota, MODE_3 = novo od 30.11.2018 naprej
              byte: natural := 8
                                                                         
             );
             
    port ( clk_in: in std_logic;
           START: in std_logic; -- start the system
           data_in : in unsigned ( (adc_bit_num - 1) downto 0 ); --data from ADC
           ADC_unit_feedback: in std_logic;
           AD_wr_en: out unsigned ( (num_of_units - 1) downto 0 );-- goes to BRAM_buffer, to AD_wr_en signal
           AD_addr: out unsigned ( (buffer_size - 1) downto 0 );  -- goes to BRAM_buffer, address signal
           data_out: out unsigned ( (bit_num - 1) downto 0 ); -- goes to data_in of BRAM_buffer
           --MODE_3--
           threshold: in unsigned ( (11 - 1) downto 0 ); --11 bitno zato, ker imam najvec 2048 kanalov
           capt_num_of_samples: in unsigned ( (byte - 1) downto 0 ); --time window
           INT_res: out std_logic;
           
           SW_trigger_value: in unsigned(4 downto 0);
           PM_trigger_in: in unsigned ( (adc_bit_num - 1) downto 0)
          );
           
end ADC_unit;

architecture Behavioral of ADC_unit is


------FUNCTIONS-----------------
    function data_map( input: unsigned ( (adc_bit_num - 2) downto 0) := (others => '0'); --transforms data drom one region to the other (for example from 0 - 1023 to 0-512)
                       current_low: integer := 0;
                       current_high: integer := 0;
                       next_low: integer := 0;
                       next_high: integer := 0 ) return unsigned is
   
    --variable result: real := 0.0;
    variable output : integer := 0;
   
    begin    
        output := ((to_integer(input) - current_low) * (next_high - next_low)) / (current_high - current_low) + next_low;
        --TODO: zaokrozevanje
        return to_unsigned(output,bit_num);
    end function;

   

--------------CONSTANTS------------------- (used for input arguments of function data_map)
    constant adc_low: integer := 0; --old area low
    constant adc_high: integer :=8191; --2**(adc_bit_num -1) - 1; --1443;-- --old area high , blo je adc_bit_num sam to pol se neg. del adc-ja zravn, kar nocm TODO: 12.4.2019, kalibriraj na novo vrednost
    constant mapped_low: integer := 0; --new area low
    constant mapped_high: integer := 2**bit_num - 1; -- new area high



--------SIGNALS--------------------------
   
    signal data_in_reduced: unsigned ( (adc_bit_num - 2) downto 0) := (others => '0'); -- 13 bitov rabm, da sam pozitivne vrednosti berem, negativnih ne
   
    signal data_out_sig: unsigned ( (bit_num - 1) downto 0 ) := (others => '0');
   
    signal AD_addr_sig: unsigned ( (buffer_size - 1) downto 0) := (others =>'0');
   
    signal absolute_addr: integer := 0; -- ta šteje število podatkov in pol to pretvarja v naslov za bram bufferje (AD_addr_sig = absolute_addr % (2**buffer_size)
   
    signal unit: integer := 0;
    signal unit_next: integer := 1;
    signal last_unit: std_logic;-- := '0';
   
    signal delay_cycles : integer := 0;
    signal delay_cycles_2 : integer := 0;
    signal delay_flag : boolean := FALSE;
   
   
   --MODE 3 SIGNALI-----------------------------------------
    --signal threshold_dig: unsigned ( (11 - 1) downto 0 ) := (others => '0'); -- threshold pride notr kot analogna vrednost, potem jo pretvorim v digialno in to zapisem v ta signal: POPRAVEK: zaenkrat ne bo tako, bom kar digitalno vrednost poslal, pretvorba iz analogne sledi v C-programu
    signal data_in_mapped: unsigned ( (bit_num - 1) downto 0) := (others => '0'); -- pretvorjen data_in_reduced iz 13 bitov na 10 bitov
    signal data_in_mapped_prev: unsigned ( (bit_num - 1) downto 0) := (others => '0'); --gledam prejsnjo vrednost, da dolocicm trenutek prehoda pod treshold
    signal send_data_flag: std_logic := '0';
   
    signal counter: unsigned ( (byte - 1) downto 0) := (others => '0');
   
    signal int_res_sig: std_logic := '1'; --integrator reset signal   1: RESET , 0: INTEGRIRAJ
    signal int_reset_time_cycles: integer := 40;--25; --25 ciklov * 8ns = 200ns
    type integrator_mode is (INTEGRATE, RESET); -- stanji integratorja
    signal int_state: integrator_mode := INTEGRATE;
   
    signal trigger_in_reduced: unsigned ( (adc_bit_num - 2) downto 0) := (others => '0');
    signal trigger_in_inverted: unsigned ( (adc_bit_num - 1) downto 0) := (others => '0');
   
begin

--DEL KODE, KI VELJA ZA VSE MODE
data_in_reduced <= data_in(12 downto 0) when data_in(13) = '0' else -- vzemi samo pozitivne vrednosti, negativne na 0
                  (others => '0') when data_in(13) = '1';

--trigger_in_reduced <= PM_trigger_in(12 downto 0) when PM_trigger_in(13) = '1' else --za vsak slucaj, ce ne gre po dvojiskem komplementu
                     -- (others => '0');

trigger_in_inverted <= (not(PM_trigger_in) + 1) when PM_trigger_in(13) = '1' else --dvojiski komplement, hocem pozitivno vrednost, je lazje primerjat
                       (others => '0');

data_out <= data_out_sig;




------------------------MODE_1 IN MODE_2 -------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------



MODE_1_MODE_2: if (mode = "MODE_1" or mode = "MODE_2") generate

---COMBINATIONAL PART-------------------------------

               
    AD_addr <= AD_addr_sig;
   
   
    last_unit <= '1' when unit = num_of_units - 1 else
                 '0';
 

---SEQUENTIAL PART------
   
    Data_handling_1_2: process (clk_in)
       variable end_flag: std_logic := '0';
       variable first_flag: std_logic := '0';
       variable delay_flag: boolean := FALSE;
    begin
       
        if (rising_edge(clk_in)) then
                   
                if (START = '1') then
                   
                    if(num_of_units = 1) then
                                   
                        if(first_flag = '0') then --ko gres prvic skos
                            AD_wr_en(0) <= '1'; --prizgi PE_enoto
                           
                            if(delay_cycles < 2) then --delay za 2 cikla
                                delay_cycles <= delay_cycles + 1;
                            end if;
                           
                            if (delay_cycles = 2) then
                                -- naslovi in izhodni podatki
                                absolute_addr <= absolute_addr + 1;
                                AD_addr_sig <= to_unsigned( absolute_addr rem (2**buffer_size), buffer_size ); -- TODO: 30.11.2018 -- TEGA SPLOH NI TREBA, ker ne uporabljam tega signala v temu mode-u
                                data_out_sig <= data_map(data_in_reduced, adc_low, adc_high, mapped_low, mapped_high); -- isto kot komentar eno vrstico zgoraj
                            end if;
                           
                            if (AD_addr_sig = 2**buffer_size - 2) then -- ce je -1 pol enga prevec nakonc vpise
                                AD_wr_en(0) <= '0';
                                delay_cycles <= 0;
                                first_flag := '1';
                            end if;
                       
                        elsif(first_flag = '1') then --ideja: tale del das delay ene par ciklov, tolk da ADC_unit_feedback oz. UC_rd_en_sig ze na 1 skoc in pol gledas kdaj je naslednjic 0, to je pa glih takrt k rabs przgat spet
                           
                            if (delay_cycles < 6) then --6 zato, ker tok cajta rab, da UC_wr_en skoc na '1'      
                                delay_cycles <= delay_cycles + 1;
                                absolute_addr <= 0;
                                AD_addr_sig <= (others => '0');
                            end if;
                                             
                            if( delay_cycles = 6 and ADC_unit_feedback = '0' and AD_addr_sig < 2**buffer_size - 1 ) then --mislim, da addr in data out tukaj ne rabim prirejat, ker sem ga ze zgoraj
                                AD_wr_en(0) <= '1';                           --ADC_unit_feedback je v tukaj UC_rd_en_sig, zarad muxa v hist_system_top
                                delay_cycles <= 6;
                               
                                if(delay_cycles_2 < 2) then --delay za 2 cikla
                                    delay_cycles_2 <= delay_cycles_2 + 1;
                                end if;
                                                       
                                if (delay_cycles_2 = 2) then
                                    absolute_addr <= absolute_addr + 1;
                                    AD_addr_sig <= to_unsigned( absolute_addr rem (2**buffer_size), buffer_size ); -- isto kot v C-ju: absolute_addr % 2**buffer_size (ostanek pri deljenju)
                                    data_out_sig <= data_map(data_in_reduced, adc_low, adc_high, mapped_low, mapped_high);
                                end if;
                            end if;    
                           
                            if (AD_addr_sig = 2** buffer_size - 2) then
                                AD_wr_en(0) <= '0';
                                delay_cycles <= 0;
                                delay_cycles_2 <= 0;
                            end if;
                               
                        end if;
                   
                   
                   
                    --ZA VEC ENOT-------------------------------------------
                    elsif (num_of_units /= 1 and ADC_unit_feedback = '0') then
                                                       
                        -- naslovi in izhodni podatki
                        absolute_addr <= absolute_addr + 1;
                        AD_addr_sig <= to_unsigned( absolute_addr rem (2**buffer_size), buffer_size ); -- isto kot v C-ju: absolute_addr % 2**buffer_size (ostanek pri deljenju)
                        data_out_sig <= data_map(data_in_reduced, adc_low, adc_high, mapped_low, mapped_high);
                       
                       
                        --menjava enot
                        if (AD_addr_sig = 2**buffer_size - 1) then
                           
                            if(unit < num_of_units - 2) then
                                unit <= unit_next;
                                unit_next <= unit_next + 1;
                           
                            elsif (last_unit = '0') then --za zadnjo enoto
                                unit <= unit_next;
                                --unit_next <= unit_next;--  = kokr da nc ne napisem, pac ne povecam se enkrat
                            end if;
                           
                        end if;
                       

                       
                        --priziganje in ugasanje enot
                        if (last_unit = '0') then  --vse enote razen zadnje
                            if (AD_addr_sig < 2**buffer_size - 2 ) then
                               
                                AD_wr_en(unit) <= '1';

                               
                            elsif (AD_addr_sig = 2**buffer_size - 1) then
                                AD_wr_en(unit) <= '0';
                                AD_wr_en(unit_next) <= '1';
                           
                            end if;
                       
                        elsif (last_unit = '1') then --ugasni zadnjo en ob pravem casu, prizge se pa: - ko je last unit se 0, ce je vec enot
                            if (AD_addr_sig < 2**buffer_size -1 and end_flag = '0') then                                 -- tukaj jo prizgem, ce je samo 1 enota
                                AD_wr_en(unit) <= '1';
                            else
                                AD_wr_en(unit) <= '0';
                                end_flag := '1'; --ko se AD_wr(unit) postavi na 0, se celotna elsif zanka potem se 1x izvede in AD_wr_en(unit) se
                            end if;             -- spet postavi na '1', kar ni OK. V ta namen tukaj postavim flag, da zadnja enota res ostane na 0
                        end if;                 -- ko jo tukaj izklopim (pogoj, da bi se postavila na '1' v vrstici 162 ni izpolnjen)
                   
                    elsif (num_of_units /= 1 and ADC_unit_feedback = '1') then --resetiraj za naslednje sprejemanje, ce je vec enot. ce tega ni, se vse samo 1x izvede
                        AD_wr_en <= (others => '0');
                        data_out_sig <= (others => '0');
                        AD_addr_sig <= (others => '0');
                        absolute_addr <= 0;
                        unit <= 0;
                        unit_next <= 1;
                        end_flag := '0';
                    end if;
                       
                else  --reset everything when START = '0'--
                 
                    AD_wr_en <= (others => '0');
                    data_out_sig <= (others => '0');
                    AD_addr_sig <= (others => '0');
                    absolute_addr <= 0;
                    unit <= 0;
                    unit_next <= 1;
                    delay_cycles <= 0;
                    delay_cycles_2 <= 0;
                    first_flag := '0';
                    end_flag := '0';
                end if;
                       
                   
                   
        end if;  
   
    end process;

end generate; --end of code for MODE_1 and MODE_2




------------------------MODE_3 -------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
MODE_3: if (mode = "MODE_3") generate

----------COMBINATIONAL PART---------------------
    INT_res <=  int_res_sig; --SPREMENJENO 30.3.2019 -- not sm pobrisov, ker sm ga na zadnjem testiranju pomoje dodal, pa ga ni treba. 12-4.2019 -- vse dela ok

----------SEQUENTIAL PART---------------------------
   
    Data_handling_3: process (clk_in)
   
    variable min_value: unsigned ( (bit_num - 1) downto 0) := (others => '0'); -- minimalna (zacetna) vrednost na intervalu integriranja
    variable max_value: unsigned ( (bit_num - 1) downto 0) := (others => '0'); --maksimalna (koncna) vrednost na intervalu, ko integriramo
    --variable counter: unsigned ( (byte - 1) downto 0) := (others => '0');
    --variable go_measure: std_logic := '0';
    variable do_it_once: std_logic := '0';
    variable do_it_once_2: std_logic := '0';
   
    begin
   
        if ( rising_edge(clk_in) ) then
           
           --TODO: pogoj ADC_unit_feedback, da enota ve, kdaj lahko posilja podatke -- 3.2.2019: tole pomoje mam
           
           if (do_it_once = '0') then --tole samo zato, da ni na zacetku AD_wr_en(0) undefined
               AD_wr_en(0) <= '0';
               do_it_once := '1';
           end if;
           
           
            if ( START = '1' ) then
               
                data_in_mapped <= data_map(data_in_reduced, adc_low, adc_high, mapped_low, mapped_high);
               
                if (ADC_unit_feedback = '0' ) then
                               
                    case int_state is
                   
                        when INTEGRATE =>
                           
                            int_res_sig <= '0'; --tole se uporabi samo prvic in samo prvic imam potem 1 clk zamude, ko pridem v INTEGRATE stanje, ker v ostalih primerih
                                            -- sem ravno prisel iz RESET stanja, ki mi pa ze vklopi integriranje, prav zato, da ni 1 clk zamude pri zacetku integriranja
                                            -- potem, ko pridem v INTEGRATE stanje
                           
                            if( int_res_sig = '0') then --pogoj zato, da ga ze takoj ne poveca, ko pade int_res na 0 ,ampak z enim clockom zamude, ker je drugace cas integriranja za 1 clock  napacen (prevelik)
                               
                                if(do_it_once_2 = '0') then -- ta del pridobi vhodno vrednost na ADC na zacetku integriranja
                                    min_value := data_in_mapped;
                                    do_it_once_2 := '1';
                                end if;
                               
                                counter <= counter + 1;
                               
                               
--                                if( counter < capt_num_of_samples - 1) then------------------------------------
                                   
--                                    if(data_in_mapped >= threshold) then
                                       
--                                        if(data_in_mapped > max_value) then
--                                            --max_value := data_in_mapped; --SPREMENJENO 22.7.2019
--                                        end if;
                                       
--                                    end if;
                               
                                if( counter = capt_num_of_samples - 1) then  ---------------------------------
                                   
                                   
                                    send_data_flag <= '1'; --poslji maksimalen podatek v PE enoto
                                   
                                    --SPREMENJENO 22.7.2019
                                    if (data_in_mapped >= threshold) then
                                        data_out_sig <= data_in_mapped; --max_value; -- - min_value; --dodano
                                    end if;
                                   
                                   
                                    counter <= (others => '0');
                                    --max_value := (others => '0');
                                   
                                    int_res_sig <= '1'; --ustavi integriranje
                                    int_state <= RESET; -- pojdi v reset stanje
                                   
                                end if; -----------------------------------------------------------------------
                               
                            end if;
                           
                       
                        when RESET =>
                           
                            do_it_once_2 := '0';
                            --------------VPIS PODATKA V PE_unit----------------
                            if (send_data_flag = '1' and data_out_sig >= threshold) then-- data_out_sig dodano, da ne vpisuje nicel , > threshold mogoce
                                 
                                send_data_flag <= '0'; -- KO SE data_out_sig POJAVI NA IZHODNEM VODILU, JE POTREBNO POCAKATI EN CLK,
                                AD_wr_en(0) <= '1';    --POTEM PA SELE VKLOPITI PISANJE (DA SE data_out PODATEK POJAVI NA old_value V PE_ENOTI)
                           
                            else
                                AD_wr_en(0) <= '0';
                                send_data_flag <= '0'; --dodano
                                data_out_sig <= (others => '0'); --SPREMENJENO 22.7.2019 dodano
                            end if;
                           
                            --------------ŠTETJE ÈASA PRAZNJENJA KONDENZATORJA------
                            if (delay_cycles < int_reset_time_cycles - 1) then
                               delay_cycles <= delay_cycles + 1; --koliko ciklov je preteklo od zaèetka resetiranja integratorja
                           
                           
                            elsif (delay_cycles = int_reset_time_cycles - 1) then
                                if(to_integer(trigger_in_inverted(12 downto 0)) >= (to_integer(SW_trigger_value) *5) ) then--if ( to_integer(trigger_in_reduced) >= (to_integer(SW_trigger_value) * 5)) then
                                    int_res_sig <= '0'; --ze tukaj vklopi integriranje, da ni zamude po prihodu v INTEGRATE stanje
                                    int_state <= INTEGRATE;
                                    delay_cycles <= 0;
                                end if;
                            end if;
                           
                    end case;                              
                   
               
                else -- ce je ADC_unit_feedback '1'
                    data_out_sig <= (others => '0');
                    AD_wr_en(0) <= '0';
                    max_value := (others => '0');
                    counter <= (others => '0');
                    send_data_flag <= '0';
                    int_res_sig <= '1'; -- izklopi integrator
                    delay_cycles <= 0;
                    do_it_once_2 := '0';
                   
                end if; --ADC_unit_feedback pogoj
           
           
            else
                do_it_once := '0';
                do_it_once_2 := '0';
                data_out_sig <= (others => '0');  
                AD_wr_en(0) <= '0';
                max_value := (others => '0');
                counter <= (others => '0');
                send_data_flag <= '0';
                int_res_sig <= '1'; -- izklopi integrator
                delay_cycles <= 0;
           
            end if; --start pogoj
       
        end if;--clk pogoj
                       
   
    end process;

end generate; --konec MODE_3



end Behavioral;