----------------------------------------------------------------------------------
-- 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;