Index: /firmware/FTM/ftu_control/FTM_ftu_control.vhd
===================================================================
--- /firmware/FTM/ftu_control/FTM_ftu_control.vhd	(revision 10175)
+++ /firmware/FTM/ftu_control/FTM_ftu_control.vhd	(revision 10175)
@@ -0,0 +1,925 @@
+----------------------------------------------------------------------------------
+-- Company:        ETH Zurich, Institute for Particle Physics
+-- Engineer:       Q. Weitzel
+-- 
+-- Create Date:    17:54:04 02/02/2011 
+-- Design Name: 
+-- Module Name:    FTM_ftu_control - Behavioral 
+-- Project Name: 
+-- Target Devices: 
+-- Tool versions: 
+-- Description:    Communication of FTM with the 40 FTU boards of the FACT camera 
+--
+-- Dependencies: 
+--
+-- Revision: 
+-- Revision 0.01 - File Created
+-- Additional Comments: 
+--
+----------------------------------------------------------------------------------
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.STD_LOGIC_ARITH.ALL;
+use IEEE.STD_LOGIC_UNSIGNED.ALL;
+
+library ftm_definitions;
+USE ftm_definitions.ftm_array_types.all;
+USE ftm_definitions.ftm_constants.all;
+
+---- Uncomment the following library declaration if instantiating
+---- any Xilinx primitives in this code.
+--library UNISIM;
+--use UNISIM.VComponents.all;
+
+entity FTM_ftu_control is
+  port(
+    clk_50MHz : in  std_logic;  -- main clock
+    
+    -- global bus enables for FTU crates 0-3
+    rx_en : out STD_LOGIC;  -- receiver enable
+    tx_en : out STD_LOGIC;  -- transmitter enable
+    
+    -- FTU crate 0 data I/O
+    rx_d_0 : in  STD_LOGIC;
+    tx_d_0 : out STD_LOGIC;
+
+    -- FTU crate 1 data I/O
+    rx_d_1 : in  STD_LOGIC;
+    tx_d_1 : out STD_LOGIC;
+
+    -- FTU crate 2 data I/O
+    rx_d_2 : in  STD_LOGIC;
+    tx_d_2 : out STD_LOGIC;
+
+    -- FTU crate 3 data I/O
+    rx_d_3 : in  STD_LOGIC;
+    tx_d_3 : out STD_LOGIC;
+
+    -- commands from FTM main control
+    new_config : in std_logic;
+    ping_all   : in std_logic;
+    read_rates : in std_logic;
+
+    -- answers to FTM main control
+    read_rates_started : out std_logic := '0';
+    read_rates_done    : out std_logic := '0';
+    new_config_started : out std_logic := '0';
+    new_config_done    : out std_logic := '0';
+    ping_all_started   : out std_logic := '0';
+    ping_all_done      : out std_logic := '0';
+
+    -- communication with static (config) RAM
+    -- this RAM is only read by FTU_control
+    static_RAM_busy    :  in std_logic;
+    static_RAM_started :  in std_logic;
+    static_RAM_ready   :  in std_logic;
+    data_static_RAM    :  in std_logic_vector(15 downto 0) := (others => '0');
+    read_static_RAM    : out std_logic := '0';
+    addr_static_RAM    : out std_logic_vector(11 downto 0) := (others => '0');
+    
+    -- communication with dynamic RAM (e.g. rates)
+    -- this RAM is only written by FTU_control
+    dynamic_RAM_busy    :  in std_logic;
+    dynamic_RAM_started :  in std_logic;
+    dynamic_RAM_ready   :  in std_logic;
+    data_dynamic_RAM    : out std_logic_vector(15 downto 0) := (others => '0');
+    write_dynamic_RAM   : out std_logic := '0';
+    addr_dynamic_RAM    : out std_logic_vector(11 downto 0) := (others => '0');
+
+    -- communication with FTU-list RAM 
+    -- this RAM is only written by FTU_control
+    FTUlist_RAM_busy    :  in std_logic;
+    FTUlist_RAM_started :  in std_logic;
+    FTUlist_RAM_ready   :  in std_logic;
+    data_FTUlist_RAM    : out std_logic_vector(15 downto 0) := (others => '0');
+    write_FTUlist_RAM   : out std_logic := '0';
+    addr_FTUlist_RAM    : out std_logic_vector(11 downto 0) := (others => '0')
+    
+  );
+end FTM_ftu_control;
+
+architecture Behavioral of FTM_ftu_control is
+
+  -- list of active FTUs, read out from static RAM before starting to contact FTUs
+  signal active_FTU_array_sig : active_FTU_array_type := ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
+
+  -- signals to count the number of responding FTUs (per crate and total) in case of a ping
+  signal FTU_answer_array_sig : FTU_answer_array_type := (0,0,0,0);
+  signal no_of_FTU_answer_sig : integer range 0 to (NO_OF_CRATES * NO_OF_FTUS_PER_CRATE) := 0;
+  
+  -- FTU configuration data, read out from static RAM (board by board)
+  signal FTU_dac_array_RAM_sig    : FTU_dac_array_type := ((others => '0'), (others => '0'), (others => '0'), (others => '0'), (others => '0'));
+  signal FTU_enable_array_RAM_sig : FTU_enable_array_type := ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
+  signal FTU_prescaling_RAM_sig   : std_logic_vector(15 downto 0) := (others => '0');
+  
+  -- signals for receiver of FTU communication
+  signal rec_reset_sig : std_logic := '0';  -- reset
+  signal rec_data_sig  : std_logic_vector (7 DOWNTO 0);
+  signal rec_block_sig : std_logic_vector (FTU_RS485_BLOCK_WIDTH - 1 downto 0);  -- initialized in FTM_ftu_rs485_receiver
+  signal rec_valid_sig : std_logic;  -- initialized in FTM_ftu_rs485_receiver
+  
+  -- select signal to multiplex the different crates
+  signal sel_crate_sig : STD_LOGIC_VECTOR (2 downto 0) := "111";
+
+  -- global signals after multiplexer
+  signal rx_en_sig    : std_logic;
+  signal tx_en_sig    : std_logic;
+  signal rx_valid_sig : std_logic;
+  signal tx_busy_sig  : std_logic;
+  signal tx_start_sig : std_logic;
+  signal tx_data_sig  : std_logic_vector (7 DOWNTO 0);
+  
+  -- signals for interpreter of FTU communication
+  signal FTU_brd_add_sig       : std_logic_vector (5 DOWNTO 0) := (others => '0');
+  signal FTU_command_sig       : std_logic_vector (7 DOWNTO 0) := (others => '1');
+  signal FTU_answer_ok_sig     : std_logic;  -- initialized in interpreter
+  signal FTU_dac_array_sig     : FTU_dac_array_type;  -- initialized in interpreter
+  signal FTU_enable_array_sig  : FTU_enable_array_type;  -- initialized in interpreter
+  signal FTU_rate_array_sig    : FTU_rate_array_type;  -- initialized in interpreter
+  signal FTU_prescaling_sig    : std_logic_vector(7 downto 0);  -- initialized in interpreter
+  signal FTU_crc_error_cnt_sig : std_logic_vector(7 downto 0);  -- initialized in interpreter
+  signal FTU_dna_sig           : std_logic_vector(63 downto 0);  -- initialized in interpreter
+  
+  -- rx_enable and tx_enable lines from different FTM_ftu_rs485_interface
+  -- initialized in corresponding interface
+  signal rx_en_0_sig : STD_LOGIC;
+  signal tx_en_0_sig : STD_LOGIC;
+  signal rx_en_1_sig : STD_LOGIC;
+  signal tx_en_1_sig : STD_LOGIC;
+  signal rx_en_2_sig : STD_LOGIC;
+  signal tx_en_2_sig : STD_LOGIC;
+  signal rx_en_3_sig : STD_LOGIC;
+  signal tx_en_3_sig : STD_LOGIC;
+
+  signal tx_start_0_sig : std_logic := '0';
+  signal tx_data_0_sig  : std_logic_vector (7 DOWNTO 0) := (others => '0');
+  signal tx_busy_0_sig  : std_logic;  -- initialized in FTM_ftu_rs485_interface_0
+  signal rx_valid_0_sig : std_logic;  -- initialized in FTM_ftu_rs485_interface_0
+  signal rx_data_0_sig  : std_logic_vector (7 DOWNTO 0);  -- initialized in FTM_ftu_rs485_interface_0
+  
+  signal tx_start_1_sig : std_logic := '0';
+  signal tx_data_1_sig  : std_logic_vector (7 DOWNTO 0) := (others => '0');
+  signal tx_busy_1_sig  : std_logic;  -- initialized in FTM_ftu_rs485_interface_1
+  signal rx_valid_1_sig : std_logic;  -- initialized in FTM_ftu_rs485_interface_1
+  signal rx_data_1_sig  : std_logic_vector (7 DOWNTO 0);  -- initialized in FTM_ftu_rs485_interface_1
+
+  signal tx_start_2_sig : std_logic := '0';
+  signal tx_data_2_sig  : std_logic_vector (7 DOWNTO 0) := (others => '0');
+  signal tx_busy_2_sig  : std_logic;  -- initialized in FTM_ftu_rs485_interface_2
+  signal rx_valid_2_sig : std_logic;  -- initialized in FTM_ftu_rs485_interface_2
+  signal rx_data_2_sig  : std_logic_vector (7 DOWNTO 0);  -- initialized in FTM_ftu_rs485_interface_2
+
+  signal tx_start_3_sig : std_logic := '0';
+  signal tx_data_3_sig  : std_logic_vector (7 DOWNTO 0) := (others => '0');
+  signal tx_busy_3_sig  : std_logic;  -- initialized in FTM_ftu_rs485_interface_3
+  signal rx_valid_3_sig : std_logic;  -- initialized in FTM_ftu_rs485_interface_3
+  signal rx_data_3_sig  : std_logic_vector (7 DOWNTO 0);  -- initialized in FTM_ftu_rs485_interface_3
+
+  -- signals to control and read out CRC
+  signal sel_crc_input_source_sig        : std_logic := '0';  -- 0 -> FSM, 1 -> interpreter
+  signal reset_crc_sig                   : std_logic;
+  signal enable_crc_sig                  : std_logic;
+  signal crc_data_sig                    : std_logic_vector (FTU_RS485_BLOCK_WIDTH - 9 downto 0) := (others => '0');
+  signal reset_crc_from_FSM_sig          : std_logic := '0';
+  signal reset_crc_from_interpreter_sig  : std_logic;
+  signal enable_crc_from_FSM_sig         : std_logic := '0';
+  signal enable_crc_from_interpreter_sig : std_logic;
+  signal crc_data_from_FSM_sig           : std_logic_vector (FTU_RS485_BLOCK_WIDTH - 9 downto 0) := (others => '0');
+  signal crc_sig                         : std_logic_vector(CRC_POLYNOMIAL'length - 1 downto 0);
+  signal crc_sig_inv                     : std_logic_vector(CRC_POLYNOMIAL'length - 1 downto 0);
+
+  -- various loop counters
+  signal active_FTU_list_cnt : integer range 0 to NO_OF_CRATES := 0;
+  signal crate_cnt           : integer range 0 to NO_OF_CRATES := 0;
+  signal FTU_cnt             : integer range 0 to NO_OF_FTUS_PER_CRATE := 0;
+  signal FTU_register_cnt    : integer range 0 to (NO_OF_FTU_ENABLE_REG + NO_OF_FTU_DAC_REG + 1) := 0;
+  signal FTU_command_cnt     : integer range 0 to 3 := 0;
+  signal frame_cnt           : integer range 0 to (FTU_RS485_BLOCK_WIDTH / 8) := 0;
+  signal FTU_list_reg_cnt    : integer range 0 to NO_OF_FTU_LIST_REG := 0;
+  signal FTU_list_header_cnt : integer range 0 to FTU_LIST_RAM_OFFSET := 0;
+
+  -- counter to define timeout and number of retries
+  signal timeout_cnt : integer range 0 to FTU_RS485_TIMEOUT := 0;
+  signal retry_cnt   : integer range 0 to FTU_RS485_NO_OF_RETRY := 0;
+  
+  component FTM_ftu_rs485_interface
+    port(
+      clk      : IN  std_logic;
+      -- RS485
+      rx_d     : IN  std_logic;
+      rx_en    : OUT std_logic;
+      tx_d     : OUT std_logic;
+      tx_en    : OUT std_logic;
+      -- FPGA
+      rx_data  : OUT std_logic_vector (7 DOWNTO 0);
+      --rx_busy  : OUT std_logic  := '0';
+      rx_valid : OUT std_logic  := '0';
+      tx_data  : IN  std_logic_vector (7 DOWNTO 0);
+      tx_busy  : OUT std_logic  := '0';
+      tx_start : IN  std_logic
+    );
+  end component;
+
+  component FTM_ftu_rs485_receiver
+    port(
+      rec_clk   : in  std_logic;
+      rec_reset : in  std_logic;
+      --rx_busy   : in  std_logic;
+      rec_din   : in  std_logic_vector(7 downto 0);
+      rec_den   : in  std_logic;
+      rec_dout  : out std_logic_vector(FTU_RS485_BLOCK_WIDTH - 1 downto 0) := (others => '0');
+      rec_valid : out std_logic := '0'
+    );
+  end component;
+
+  component FTM_ftu_rs485_interpreter
+    port(
+      clk               : IN  std_logic;
+      data_block        : IN  std_logic_vector(FTU_RS485_BLOCK_WIDTH - 1 downto 0);
+      block_valid       : IN  std_logic;
+      crc               : IN  std_logic_vector(7 downto 0);
+      FTU_brd_add       : IN  std_logic_vector(5 downto 0);
+      FTU_command       : IN  std_logic_vector(7 downto 0);
+      reset_crc         : OUT std_logic := '0';
+      enable_crc        : OUT std_logic := '0';
+      FTU_answer_ok     : OUT std_logic := '0';
+      FTU_dac_array     : OUT FTU_dac_array_type;
+      FTU_enable_array  : OUT FTU_enable_array_type;
+      FTU_rate_array    : OUT FTU_rate_array_type;
+      FTU_prescaling    : OUT std_logic_vector(7 downto 0);
+      FTU_crc_error_cnt : OUT std_logic_vector(7 downto 0);
+      FTU_dna           : OUT std_logic_vector(63 downto 0)
+    );
+  end component;
+  
+  component ucrc_par
+    generic(
+      POLYNOMIAL : std_logic_vector;
+      INIT_VALUE : std_logic_vector;
+      DATA_WIDTH : integer range 2 to 256;
+      SYNC_RESET : integer range 0 to 1
+    );
+    port(
+      clk_i   : in  std_logic;
+      rst_i   : in  std_logic;
+      clken_i : in  std_logic;
+      data_i  : in  std_logic_vector(DATA_WIDTH - 1 downto 0);
+      match_o : out std_logic;
+      crc_o   : out std_logic_vector(POLYNOMIAL'length - 1 downto 0)
+    );
+  end component;
+
+  type FTM_ftu_rs485_control_StateType is (INIT, IDLE, ACTIVE_LIST, READ_CONFIG, TRANSMIT_CONFIG,
+                                           PING, PING_END, FTU_LIST, RATES,
+                                           ACTIVE_LIST_1, ACTIVE_LIST_2, ACTIVE_LIST_3,
+                                           READ_CONFIG_1, READ_CONFIG_2, READ_CONFIG_3,
+                                           TRANSMIT_CONFIG_1, TRANSMIT_CONFIG_2, TRANSMIT_CONFIG_3,
+                                           PING_1, PING_2, PING_3, PING_END_1, PING_END_2, PING_END_3,
+                                           FTU_LIST_1, FTU_LIST_2, FTU_LIST_3);
+  signal FTM_ftu_rs485_control_State : FTM_ftu_rs485_control_StateType;
+
+begin
+
+  Inst_FTM_fTU_rs485_interface_0 : FTM_ftu_rs485_interface  -- crate 0
+    port map(
+      clk      => clk_50MHz,
+      -- RS485
+      rx_d     => rx_d_0,
+      rx_en    => rx_en_0_sig,
+      tx_d     => tx_d_0,
+      tx_en    => tx_en_0_sig,
+      -- FPGA
+      rx_data  => rx_data_0_sig,
+      --rx_busy  => ,
+      rx_valid => rx_valid_0_sig,
+      tx_data  => tx_data_0_sig,
+      tx_busy  => tx_busy_0_sig,
+      tx_start => tx_start_0_sig
+    );
+
+  Inst_FTM_fTU_rs485_interface_1 : FTM_ftu_rs485_interface  -- crate 1
+    port map(
+      clk      => clk_50MHz,
+      -- RS485
+      rx_d     => rx_d_1,
+      rx_en    => rx_en_1_sig,
+      tx_d     => tx_d_1,
+      tx_en    => tx_en_1_sig,
+      -- FPGA
+      rx_data  => rx_data_1_sig,
+      --rx_busy  => ,
+      rx_valid => rx_valid_1_sig,
+      tx_data  => tx_data_1_sig,
+      tx_busy  => tx_busy_1_sig,
+      tx_start => tx_start_1_sig
+    );
+
+  Inst_FTM_fTU_rs485_interface_2 : FTM_ftu_rs485_interface  -- crate 2
+    port map(
+      clk      => clk_50MHz,
+      -- RS485
+      rx_d     => rx_d_2,
+      rx_en    => rx_en_2_sig,
+      tx_d     => tx_d_2,
+      tx_en    => tx_en_2_sig,
+      -- FPGA
+      rx_data  => rx_data_2_sig,
+      --rx_busy  => ,
+      rx_valid => rx_valid_2_sig,
+      tx_data  => tx_data_2_sig,
+      tx_busy  => tx_busy_2_sig,
+      tx_start => tx_start_2_sig
+    );
+
+  Inst_FTM_fTU_rs485_interface_3 : FTM_ftu_rs485_interface  -- crate 3
+    port map(
+      clk      => clk_50MHz,
+      -- RS485
+      rx_d     => rx_d_3,
+      rx_en    => rx_en_3_sig,
+      tx_d     => tx_d_3,
+      tx_en    => tx_en_3_sig,
+      -- FPGA
+      rx_data  => rx_data_3_sig,
+      --rx_busy  => ,
+      rx_valid => rx_valid_3_sig,
+      tx_data  => tx_data_3_sig,
+      tx_busy  => tx_busy_3_sig,
+      tx_start => tx_start_3_sig
+    );
+
+  Inst_FTM_ftu_rs485_receiver : FTM_ftu_rs485_receiver
+    port map(
+      rec_clk   => clk_50MHz,
+      rec_reset => rec_reset_sig,
+      --rx_busy   =>,
+      rec_din   => rec_data_sig,
+      rec_den   => rx_valid_sig,
+      rec_dout  => rec_block_sig,
+      rec_valid => rec_valid_sig
+    );
+
+  Inst_FTM_ftu_rs485_interpreter : FTM_ftu_rs485_interpreter
+    port map(
+      clk               => clk_50MHz,
+      data_block        => rec_block_sig,
+      block_valid       => rec_valid_sig,
+      crc               => crc_sig,
+      FTU_brd_add       => FTU_brd_add_sig,
+      FTU_command       => FTU_command_sig,
+      reset_crc         => reset_crc_from_interpreter_sig,
+      enable_crc        => enable_crc_from_interpreter_sig,
+      FTU_answer_ok     => FTU_answer_ok_sig,
+      FTU_dac_array     => FTU_dac_array_sig,
+      FTU_enable_array  => FTU_enable_array_sig,
+      FTU_rate_array    => FTU_rate_array_sig,
+      FTU_prescaling    => FTU_prescaling_sig,
+      FTU_crc_error_cnt => FTU_crc_error_cnt_sig,
+      FTU_dna           => FTU_dna_sig
+    );
+  
+  Inst_ucrc_par : ucrc_par
+    generic map(
+      POLYNOMIAL => CRC_POLYNOMIAL,
+      INIT_VALUE => CRC_INIT_VALUE,
+      DATA_WIDTH => (FTU_RS485_BLOCK_WIDTH - 8),
+      SYNC_RESET => 1
+    )
+    port map(
+      clk_i   => clk_50MHz,
+      rst_i   => reset_crc_sig,
+      clken_i => enable_crc_sig,
+      data_i  => crc_data_sig,
+      match_o => open,
+      crc_o   => crc_sig_inv
+    );
+
+  -- Main finite state machine to control all 40 FTUs
+  FTM_ftu_rs485_control_FSM: process (clk_50MHz)
+  begin
+    if Rising_edge(clk_50MHz) then
+      case FTM_ftu_rs485_control_State is
+
+        when INIT =>  -- reset CRC register
+          reset_crc_from_FSM_sig <= '1';
+          FTM_ftu_rs485_control_State <= IDLE;
+
+        when IDLE =>  -- wait for command from outside 
+          sel_crate_sig <= "111";
+          sel_crc_input_source_sig <= '0';
+          reset_crc_from_FSM_sig <= '0';
+          enable_crc_from_FSM_sig <= '0';
+          new_config_done <= '0';
+          ping_all_done   <= '0';
+          read_rates_done <= '0';
+          if (new_config = '1') then
+            new_config_started <= '1';
+            ping_all_started   <= '0';
+            read_rates_started <= '0';
+            FTM_ftu_rs485_control_State <= ACTIVE_LIST;
+          elsif (new_config = '0' and  ping_all = '1') then
+            new_config_started <= '0';
+            ping_all_started   <= '1';
+            read_rates_started <= '0';
+            FTM_ftu_rs485_control_State <= PING;
+          elsif (new_config = '0' and  ping_all = '0' and read_rates = '1') then
+            new_config_started <= '0';
+            ping_all_started   <= '0';
+            read_rates_started <= '1';
+            FTM_ftu_rs485_control_State <= RATES;
+          else
+            new_config_started <= '0';
+            ping_all_started   <= '0';
+            read_rates_started <= '0';
+            FTM_ftu_rs485_control_State <= IDLE;
+          end if;
+
+        when ACTIVE_LIST =>  -- loop over 4 crates to get active FTU list
+          if (active_FTU_list_cnt < NO_OF_CRATES) then
+            active_FTU_list_cnt <= active_FTU_list_cnt + 1;
+            FTM_ftu_rs485_control_State <= ACTIVE_LIST_1;
+          else
+            active_FTU_list_cnt <= 0;
+            FTM_ftu_rs485_control_State <= READ_CONFIG;
+          end if;
+
+        when ACTIVE_LIST_1 =>
+          if (static_RAM_busy = '0') then
+            read_static_RAM <= '1';
+            addr_static_RAM <= conv_std_logic_vector(STATIC_RAM_ACT_FTU_OFFSET + (active_FTU_list_cnt - 1), STATIC_RAM_ADDR_WIDTH);
+            FTM_ftu_rs485_control_State <= ACTIVE_LIST_2;
+          end if;
+            
+        when ACTIVE_LIST_2 =>
+          if (static_RAM_started = '1') then
+            FTM_ftu_rs485_control_State <= ACTIVE_LIST_3;
+          end if;
+            
+        when ACTIVE_LIST_3 =>
+          if (static_RAM_ready = '1') then
+            active_FTU_array_sig(active_FTU_list_cnt - 1) <= data_static_RAM;
+            read_static_RAM <= '0';
+            FTM_ftu_rs485_control_State <= ACTIVE_LIST;
+          end if;
+                    
+        when READ_CONFIG =>  -- read configuration of FTUs (one by one)
+          if (crate_cnt < NO_OF_CRATES) then
+            sel_crate_sig <= conv_std_logic_vector(crate_cnt, 3);
+            if (FTU_cnt < NO_OF_FTUS_PER_CRATE) then
+              if (FTU_register_cnt < (NO_OF_FTU_ENABLE_REG + NO_OF_FTU_DAC_REG + 1)) then
+                FTU_register_cnt <= FTU_register_cnt + 1;
+                FTM_ftu_rs485_control_State <= READ_CONFIG_1;
+              else
+                FTU_cnt <= FTU_cnt + 1;
+                FTU_register_cnt <= 0;
+                if (active_FTU_array_sig(crate_cnt)(FTU_cnt) = '1') then
+                  FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG;
+                else
+                  FTM_ftu_rs485_control_State <= READ_CONFIG;
+                end if;
+              end if;
+            else
+              crate_cnt <= crate_cnt + 1;
+              FTU_cnt <= 0;
+              FTM_ftu_rs485_control_State <= READ_CONFIG;
+            end if;
+          else
+            crate_cnt <= 0;
+            new_config_started <= '0';
+            new_config_done <= '1';
+            sel_crate_sig <= "111";
+            FTM_ftu_rs485_control_State <= IDLE;
+          end if;
+
+        when READ_CONFIG_1 =>
+          if (static_RAM_busy = '0') then
+            read_static_RAM <= '1';
+            addr_static_RAM <= conv_std_logic_vector(STATIC_RAM_CFG_FTU_OFFSET +
+                                                     crate_cnt * NO_OF_FTUS_PER_CRATE * (NO_OF_FTU_ENABLE_REG + NO_OF_FTU_DAC_REG + 1) +
+                                                     FTU_cnt * (NO_OF_FTU_ENABLE_REG + NO_OF_FTU_DAC_REG + 1) +
+                                                     (FTU_register_cnt - 1), STATIC_RAM_ADDR_WIDTH);
+            FTM_ftu_rs485_control_State <= READ_CONFIG_2;
+          end if;
+            
+        when READ_CONFIG_2 =>
+          if (static_RAM_started = '1') then
+            FTM_ftu_rs485_control_State <= READ_CONFIG_3;
+          end if;
+            
+        when READ_CONFIG_3 =>
+          if (static_RAM_ready = '1') then
+            if ((FTU_register_cnt - 1) < NO_OF_FTU_ENABLE_REG) then
+              FTU_enable_array_RAM_sig(FTU_register_cnt - 1) <= data_static_RAM;
+            elsif ((FTU_register_cnt - 1) < (NO_OF_FTU_ENABLE_REG + NO_OF_FTU_DAC_REG)) then
+              FTU_dac_array_RAM_sig((FTU_register_cnt - 1) - NO_OF_FTU_ENABLE_REG) <= data_static_RAM;
+            elsif ((FTU_register_cnt - 1) = (NO_OF_FTU_ENABLE_REG + NO_OF_FTU_DAC_REG)) then
+              FTU_prescaling_RAM_sig <= data_static_RAM;
+            end if;
+            read_static_RAM <= '0';
+            FTM_ftu_rs485_control_State <= READ_CONFIG;
+          end if;
+          
+        when TRANSMIT_CONFIG =>  -- send configuration to FTUs (one by one)
+          rec_reset_sig <= '0';
+          if (FTU_command_cnt = 0) then  -- DACs
+            FTU_command_cnt <= FTU_command_cnt + 1;
+            enable_crc_from_FSM_sig <= '1';
+            crc_data_from_FSM_sig <= "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000"
+                                     & FTU_dac_array_RAM_sig(4)(15 downto 8) & FTU_dac_array_RAM_sig(4)(7 downto 0)
+                                     & FTU_dac_array_RAM_sig(3)(15 downto 8) & FTU_dac_array_RAM_sig(3)(7 downto 0)
+                                     & FTU_dac_array_RAM_sig(2)(15 downto 8) & FTU_dac_array_RAM_sig(2)(7 downto 0)
+                                     & FTU_dac_array_RAM_sig(1)(15 downto 8) & FTU_dac_array_RAM_sig(1)(7 downto 0)
+                                     & FTU_dac_array_RAM_sig(0)(15 downto 8) & FTU_dac_array_RAM_sig(0)(7 downto 0)
+                                     & "00000000" & FIRMWARE_ID & FTM_ADDRESS
+                                     & "00" & conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2)
+                                     & FTU_RS485_START_DELIM;
+            FTU_brd_add_sig <= conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2);
+            FTU_command_sig <= "00000000";
+            FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_1;
+          elsif (FTU_command_cnt = 1) then  -- enables
+            FTU_command_cnt <= FTU_command_cnt + 1;
+            enable_crc_from_FSM_sig <= '1';
+            crc_data_from_FSM_sig <= "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000" & "00000000" & "00000000"
+                                     & FTU_enable_array_RAM_sig(3)(15 downto 8) & FTU_enable_array_RAM_sig(3)(7 downto 0)
+                                     & FTU_enable_array_RAM_sig(2)(15 downto 8) & FTU_enable_array_RAM_sig(2)(7 downto 0)
+                                     & FTU_enable_array_RAM_sig(1)(15 downto 8) & FTU_enable_array_RAM_sig(1)(7 downto 0)
+                                     & FTU_enable_array_RAM_sig(0)(15 downto 8) & FTU_enable_array_RAM_sig(0)(7 downto 0)
+                                     & "00000011" & FIRMWARE_ID & FTM_ADDRESS
+                                     & "00" & conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2)
+                                     & FTU_RS485_START_DELIM;
+            FTU_brd_add_sig <= conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2);
+            FTU_command_sig <= "00000011";
+            FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_1;
+          elsif (FTU_command_cnt = 2) then  -- prescaling
+            FTU_command_cnt <= FTU_command_cnt + 1;
+            enable_crc_from_FSM_sig <= '1';
+            crc_data_from_FSM_sig <= "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & "00000000" & "00000000" & "00000000" & "00000000"
+                                     & FTU_prescaling_RAM_sig(15 downto 8) & FTU_prescaling_RAM_sig(7 downto 0)
+                                     & "00000110" & FIRMWARE_ID & FTM_ADDRESS
+                                     & "00" & conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2)
+                                     & FTU_RS485_START_DELIM;
+            FTU_brd_add_sig <= conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2);
+            FTU_command_sig <= "00000110";
+            FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_1;
+          else
+            FTU_command_cnt <= 0;
+            enable_crc_from_FSM_sig <= '0';
+            FTM_ftu_rs485_control_State <= READ_CONFIG;
+          end if;
+            
+        when TRANSMIT_CONFIG_1 =>  -- wait one cycle for CRC calculation
+          enable_crc_from_FSM_sig <= '0';
+          FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_2;
+          
+        when TRANSMIT_CONFIG_2 =>  -- transmit byte by byte
+          if (tx_busy_sig = '0') then
+            if (frame_cnt < 27) then
+              frame_cnt <= frame_cnt + 1;
+              tx_data_sig <= crc_data_from_FSM_sig (7 downto 0);
+              crc_data_from_FSM_sig <= "00000000" & crc_data_from_FSM_sig ((FTU_RS485_BLOCK_WIDTH - 9) downto 8);
+              tx_start_sig <= '1';
+              FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_2;
+            elsif (frame_cnt = 27) then
+              frame_cnt <= frame_cnt + 1;
+              tx_data_sig <= crc_sig;
+              tx_start_sig <= '1';
+              FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_2;
+            else
+              frame_cnt <= 0;
+              reset_crc_from_FSM_sig <= '1';
+              FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_3;
+            end if;            
+          else
+            tx_start_sig <= '0';
+            FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_2;
+          end if;
+          
+        when TRANSMIT_CONFIG_3 =>  -- wait for FTU answer
+          reset_crc_from_FSM_sig <= '0';
+          if (FTU_answer_ok_sig = '1') then
+            timeout_cnt <= 0;
+            retry_cnt <= 0;
+            sel_crc_input_source_sig <= '0';
+            FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG;
+          else
+            if (timeout_cnt < FTU_RS485_TIMEOUT) then
+              timeout_cnt <= timeout_cnt + 1;
+              sel_crc_input_source_sig <= '1';
+              FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG_3;
+            else
+              timeout_cnt <= 0;
+              sel_crc_input_source_sig <= '0';
+              rec_reset_sig <= '1';
+              if (retry_cnt < FTU_RS485_NO_OF_RETRY) then
+                retry_cnt <= retry_cnt + 1;
+                FTU_command_cnt <= FTU_command_cnt - 1;  -- try this command again
+                FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG;
+              else
+                retry_cnt <= 0;
+                FTU_command_cnt <= FTU_command_cnt;  -- move to next command;
+                FTM_ftu_rs485_control_State <= TRANSMIT_CONFIG;
+              end if;
+            end if;
+          end if;
+            
+        when PING =>  -- ping all FTUs
+          rec_reset_sig <= '0';
+          if (crate_cnt < NO_OF_CRATES) then
+            sel_crate_sig <= conv_std_logic_vector(crate_cnt, 3);
+            if (FTU_cnt < NO_OF_FTUS_PER_CRATE) then
+              FTU_cnt <= FTU_cnt + 1;
+              if (active_FTU_array_sig(crate_cnt)(FTU_cnt) = '1') then
+                enable_crc_from_FSM_sig <= '1';
+                crc_data_from_FSM_sig <= "00000000"
+                                         & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                         & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                         & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                         & "00000000" & "00000000" & "00000000" & "00000000" & "00000000" & "00000000"
+                                         & "00000101" & FIRMWARE_ID & FTM_ADDRESS
+                                         & "00" & conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2)
+                                         & FTU_RS485_START_DELIM;
+                FTU_brd_add_sig <= conv_std_logic_vector(FTU_cnt,4) & conv_std_logic_vector(crate_cnt,2);
+                FTU_command_sig <= "00000101";
+                FTM_ftu_rs485_control_State <= PING_1;
+              else
+                FTM_ftu_rs485_control_State <= PING;
+              end if;
+            else
+              crate_cnt <= crate_cnt + 1;
+              FTU_cnt <= 0;
+              FTM_ftu_rs485_control_State <= PING;
+            end if;
+          else
+            crate_cnt <= 0;
+            FTM_ftu_rs485_control_State <= PING_END;
+          end if;
+          
+        when PING_1 =>  -- wait one cycle for CRC calculation
+          enable_crc_from_FSM_sig <= '0';
+          FTM_ftu_rs485_control_State <= PING_2;
+
+        when PING_2 =>  -- transmit byte by byte
+          if (tx_busy_sig = '0') then
+            if (frame_cnt < 27) then
+              frame_cnt <= frame_cnt + 1;
+              tx_data_sig <= crc_data_from_FSM_sig (7 downto 0);
+              crc_data_from_FSM_sig <= "00000000" & crc_data_from_FSM_sig ((FTU_RS485_BLOCK_WIDTH - 9) downto 8);
+              tx_start_sig <= '1';
+              FTM_ftu_rs485_control_State <= PING_2;
+            elsif (frame_cnt = 27) then
+              frame_cnt <= frame_cnt + 1;
+              tx_data_sig <= crc_sig;
+              tx_start_sig <= '1';
+              FTM_ftu_rs485_control_State <= PING_2;
+            else
+              frame_cnt <= 0;
+              reset_crc_from_FSM_sig <= '1';
+              FTM_ftu_rs485_control_State <= PING_3;
+            end if;            
+          else
+            tx_start_sig <= '0';
+            FTM_ftu_rs485_control_State <= PING_2;
+          end if;
+
+        when PING_3 =>  -- wait for FTU answer
+          reset_crc_from_FSM_sig <= '0';
+          if (FTU_answer_ok_sig = '1') then
+            FTU_answer_array_sig(crate_cnt) <= FTU_answer_array_sig(crate_cnt) + 1;
+            no_of_FTU_answer_sig <= no_of_FTU_answer_sig + 1;
+            timeout_cnt <= 0;
+            sel_crc_input_source_sig <= '0';
+            FTM_ftu_rs485_control_State <= FTU_LIST;
+          else
+            if (timeout_cnt < FTU_RS485_TIMEOUT) then
+              timeout_cnt <= timeout_cnt + 1;
+              sel_crc_input_source_sig <= '1';
+              FTM_ftu_rs485_control_State <= PING_3;
+            else
+              timeout_cnt <= 0;
+              sel_crc_input_source_sig <= '0';
+              rec_reset_sig <= '1';
+              if (retry_cnt < FTU_RS485_NO_OF_RETRY) then
+                retry_cnt <= retry_cnt + 1;
+                FTU_cnt <= FTU_cnt - 1;  -- repeat this FTU
+                FTM_ftu_rs485_control_State <= PING;
+              else
+                FTU_cnt <= FTU_cnt;  -- move on
+                FTM_ftu_rs485_control_State <= FTU_LIST;
+              end if;
+            end if;
+          end if;
+
+        when FTU_LIST =>  -- fill FTU-list for actual FTU
+          rec_reset_sig <= '0';
+          if (FTU_list_reg_cnt < NO_OF_FTU_LIST_REG) then
+            FTU_list_reg_cnt <= FTU_list_reg_cnt + 1;
+            FTM_ftu_rs485_control_State <= FTU_LIST_1;
+          else
+            FTU_list_reg_cnt <= 0;
+            retry_cnt <= 0;
+            FTM_ftu_rs485_control_State <= PING;
+          end if;
+          
+        when FTU_LIST_1 =>
+          if (FTUlist_RAM_busy = '0') then
+            write_FTUlist_RAM <= '1';
+            addr_FTUlist_RAM <= conv_std_logic_vector(FTU_LIST_RAM_OFFSET +
+                                                      FTU_cnt * NO_OF_FTU_LIST_REG +
+                                                      (FTU_list_reg_cnt - 1), FTU_LIST_RAM_ADDR_WIDTH);
+            if (retry_cnt < FTU_RS485_NO_OF_RETRY) then
+              if ((FTU_list_reg_cnt - 1) = 0) then
+                data_FTUlist_RAM <= "000000" & conv_std_logic_vector((retry_cnt + 1),2) & "00" & FTU_brd_add_sig;
+              elsif ((FTU_list_reg_cnt - 1) = 1) then
+                data_FTUlist_RAM <= FTU_dna_sig(63 downto 48);
+              elsif ((FTU_list_reg_cnt - 1) = 2) then
+                data_FTUlist_RAM <= FTU_dna_sig(47 downto 32);
+              elsif ((FTU_list_reg_cnt - 1) = 3) then
+                data_FTUlist_RAM <= FTU_dna_sig(31 downto 16);
+              elsif ((FTU_list_reg_cnt - 1) = 4) then
+                data_FTUlist_RAM <= FTU_dna_sig(15 downto  0);
+              elsif ((FTU_list_reg_cnt - 1) = 5) then
+                data_FTUlist_RAM <= "00000000" & FTU_crc_error_cnt_sig;
+              end if;
+            else
+              data_FTUlist_RAM <= (others => '0');
+            end if;
+            FTM_ftu_rs485_control_State <= FTU_LIST_2;
+          end if;
+
+        when FTU_LIST_2 =>
+          if (FTUlist_RAM_started = '1') then
+            write_FTUlist_RAM <= '0';
+            FTM_ftu_rs485_control_State <= FTU_LIST_3;
+          end if;
+            
+        when FTU_LIST_3 =>
+          if (FTUlist_RAM_ready = '1') then
+            FTM_ftu_rs485_control_State <= FTU_LIST;
+          end if;
+
+        when PING_END =>  -- add final ping statistics to FTU-list
+          if (FTU_list_header_cnt < FTU_LIST_RAM_OFFSET) then
+            FTU_list_header_cnt <= FTU_list_header_cnt + 1;
+            FTM_ftu_rs485_control_State <= PING_END_1;
+          else
+            FTU_list_header_cnt <= 0;
+            ping_all_started <= '0';
+            ping_all_done <= '1';
+            sel_crate_sig <= "111";
+            FTM_ftu_rs485_control_State <= IDLE;
+          end if;
+
+        when PING_END_1 =>
+          if (FTUlist_RAM_busy = '0') then
+            write_FTUlist_RAM <= '1';
+            addr_FTUlist_RAM <= conv_std_logic_vector((FTU_list_header_cnt - 1), FTU_LIST_RAM_ADDR_WIDTH);
+            if ((FTU_list_header_cnt - 1) = 0) then
+              data_FTUlist_RAM <= conv_std_logic_vector(no_of_FTU_answer_sig, 16);
+            elsif ((FTU_list_header_cnt - 1) < 5) then
+              data_FTUlist_RAM <= conv_std_logic_vector(FTU_answer_array_sig(FTU_list_header_cnt - 2), 16);
+            elsif ((FTU_list_header_cnt - 1) < 9) then
+              data_FTUlist_RAM <= active_FTU_array_sig(FTU_list_header_cnt - 6);
+            end if;
+            FTM_ftu_rs485_control_State <= PING_END_2;
+          end if;
+          
+        when PING_END_2 =>
+          if (FTUlist_RAM_started = '1') then
+            write_FTUlist_RAM <= '0';
+            FTM_ftu_rs485_control_State <= PING_END_3;
+          end if;
+        
+        when PING_END_3 =>
+          if (FTUlist_RAM_ready = '1') then
+            FTM_ftu_rs485_control_State <= PING_END;
+          end if;
+          
+        when RATES =>  -- read all FTU rates
+          FTM_ftu_rs485_control_State <= IDLE;
+
+      end case;
+    end if;
+  end process FTM_ftu_rs485_control_FSM;
+
+  -- Process to multiplex the different crate buses
+  sel_crate_process: process (sel_crate_sig,
+                              rx_en_0_sig, rx_en_1_sig, rx_en_2_sig, rx_en_3_sig,
+                              tx_en_0_sig, tx_en_1_sig, tx_en_2_sig, tx_en_3_sig,
+                              rx_valid_0_sig, rx_valid_1_sig, rx_valid_2_sig, rx_valid_3_sig,
+                              rx_data_0_sig, rx_data_1_sig, rx_data_2_sig, rx_data_3_sig,
+                              tx_busy_0_sig, tx_busy_1_sig, tx_busy_2_sig, tx_busy_3_sig,
+                              tx_start_sig, tx_data_sig)
+  begin 
+    case sel_crate_sig is  
+      when "000" =>  -- crate 0
+        rx_en_sig <= rx_en_0_sig;
+        tx_en_sig <= tx_en_0_sig;
+        rx_valid_sig <= rx_valid_0_sig;
+        rec_data_sig <= rx_data_0_sig;
+        tx_busy_sig <= tx_busy_0_sig;
+        tx_start_0_sig <= tx_start_sig;
+        tx_start_1_sig <= '0';
+        tx_start_2_sig <= '0';
+        tx_start_3_sig <= '0';
+        tx_data_0_sig <= tx_data_sig;
+        tx_data_1_sig <= (others => '0');
+        tx_data_2_sig <= (others => '0');
+        tx_data_3_sig <= (others => '0');
+      when "001" =>  -- crate 1
+        rx_en_sig <= rx_en_1_sig;
+        tx_en_sig <= tx_en_1_sig;
+        rx_valid_sig <= rx_valid_1_sig;
+        rec_data_sig <= rx_data_1_sig;
+        tx_busy_sig <= tx_busy_1_sig;
+        tx_start_0_sig <= '0';
+        tx_start_1_sig <= tx_start_sig;
+        tx_start_2_sig <= '0';
+        tx_start_3_sig <= '0';
+        tx_data_0_sig <= (others => '0');
+        tx_data_1_sig <= tx_data_sig;
+        tx_data_2_sig <= (others => '0');
+        tx_data_3_sig <= (others => '0');
+      when "010" =>  -- crate 2
+        rx_en_sig <= rx_en_2_sig;
+        tx_en_sig <= tx_en_2_sig;
+        rx_valid_sig <= rx_valid_2_sig;
+        rec_data_sig <= rx_data_2_sig;
+        tx_busy_sig <= tx_busy_2_sig;
+        tx_start_0_sig <= '0';
+        tx_start_1_sig <= '0';
+        tx_start_2_sig <= tx_start_sig;
+        tx_start_3_sig <= '0';
+        tx_data_0_sig <= (others => '0');
+        tx_data_1_sig <= (others => '0');
+        tx_data_2_sig <= tx_data_sig;
+        tx_data_3_sig <= (others => '0');
+      when "011" =>  -- crate 3
+        rx_en_sig <= rx_en_3_sig;
+        tx_en_sig <= tx_en_3_sig;
+        rx_valid_sig <= rx_valid_3_sig;
+        rec_data_sig <= rx_data_3_sig;
+        tx_busy_sig <= tx_busy_3_sig;
+        tx_start_0_sig <= '0';
+        tx_start_1_sig <= '0';
+        tx_start_2_sig <= '0';
+        tx_start_3_sig <= tx_start_sig;
+        tx_data_0_sig <= (others => '0');
+        tx_data_1_sig <= (others => '0');
+        tx_data_2_sig <= (others => '0');
+        tx_data_3_sig <= tx_data_sig;
+      when others =>  -- no crate specified
+        rx_en_sig <= '0';
+        tx_en_sig <= '0';
+        rx_valid_sig <= '0';
+        rec_data_sig <= (others => '0');
+        tx_busy_sig <= '0';
+        tx_start_0_sig <= '0';
+        tx_start_1_sig <= '0';
+        tx_start_2_sig <= '0';
+        tx_start_3_sig <= '0';
+        tx_data_0_sig <= (others => '0');
+        tx_data_1_sig <= (others => '0');
+        tx_data_2_sig <= (others => '0');
+        tx_data_3_sig <= (others => '0');
+    end case;  
+  end process; 
+
+  -- Process to select the CRC input source (FSM or interpreter)
+  sel_crc_cource_process : process (sel_crc_input_source_sig,
+                                    reset_crc_from_interpreter_sig, reset_crc_from_FSM_sig,
+                                    enable_crc_from_interpreter_sig, enable_crc_from_FSM_sig,
+                                    rec_block_sig((FTU_RS485_BLOCK_WIDTH - 9) downto 0), crc_data_from_FSM_sig)                                    
+  begin
+    case sel_crc_input_source_sig is
+      when '0' =>  -- FSM
+        reset_crc_sig <= reset_crc_from_FSM_sig;
+        enable_crc_sig <= enable_crc_from_FSM_sig;
+        crc_data_sig <= crc_data_from_FSM_sig;
+      when '1' =>  -- interpreter
+        reset_crc_sig <= reset_crc_from_interpreter_sig;
+        enable_crc_sig <= enable_crc_from_interpreter_sig;
+        crc_data_sig <= rec_block_sig((FTU_RS485_BLOCK_WIDTH - 9) downto 0);
+      when others =>  -- signal undefined
+        reset_crc_sig <= reset_crc_from_FSM_sig;
+        enable_crc_sig <= enable_crc_from_FSM_sig;
+        crc_data_sig <= crc_data_from_FSM_sig;
+    end case;
+  end process;
+  
+  rx_en <= rx_en_sig;
+  tx_en <= tx_en_sig;
+
+  crc_sig <= crc_sig_inv(0) & crc_sig_inv(1) & crc_sig_inv(2) & crc_sig_inv(3) & crc_sig_inv(4) & crc_sig_inv(5) & crc_sig_inv(6) & crc_sig_inv(7);
+  
+end Behavioral;
+
Index: /firmware/FTM/ftu_control/FTM_ftu_rs485_interface.vhd
===================================================================
--- /firmware/FTM/ftu_control/FTM_ftu_rs485_interface.vhd	(revision 10175)
+++ /firmware/FTM/ftu_control/FTM_ftu_rs485_interface.vhd	(revision 10175)
@@ -0,0 +1,126 @@
+--
+-- VHDL Architecture FACT_FAD_lib.rs485_interface.beha
+--
+-- Created:
+--          by - Benjamin Krumm.UNKNOWN (EEPC8)
+--          at - 13:24:23 08.06.2010
+--
+-- using Mentor Graphics HDL Designer(TM) 2009.1 (Build 12)
+--
+--
+-- modified for FTM design by Q. Weitzel, 03 February 2011
+--
+
+LIBRARY ieee;
+USE ieee.std_logic_1164.all;
+USE ieee.std_logic_arith.all;
+
+library ftm_definitions;
+-- USE ftm_definitions.ftm_array_types.all;
+USE ftm_definitions.ftm_constants.all;
+
+ENTITY FTM_ftu_rs485_interface IS
+  GENERIC( 
+    CLOCK_FREQUENCY : integer := INT_CLK_FREQUENCY_1;
+    BAUD_RATE       : integer := FTU_RS485_BAUD_RATE
+  );
+  PORT( 
+    clk      : IN     std_logic;
+    -- RS485
+    rx_d     : IN     std_logic;
+    rx_en    : OUT    std_logic;
+    tx_d     : OUT    std_logic;
+    tx_en    : OUT    std_logic;
+    -- FPGA
+    rx_data  : OUT    std_logic_vector (7 DOWNTO 0);
+    --rx_busy  : OUT    std_logic  := '0';
+    rx_valid : OUT    std_logic  := '0';
+    tx_data  : IN     std_logic_vector (7 DOWNTO 0);
+    tx_busy  : OUT    std_logic  := '0';
+    tx_start : IN     std_logic
+  );
+
+END FTM_ftu_rs485_interface;
+
+ARCHITECTURE beha OF FTM_ftu_rs485_interface IS
+  
+  signal flow_ctrl : std_logic := '0'; -- '0' -> RX enable, '1' -> TX enable
+
+  --transmit
+  signal tx_start_f : std_logic := '0';
+  signal tx_sr : std_logic_vector(10 downto 0) := (others => '1');  -- start bit, 8 data bits, 2 stop bits
+  signal tx_bitcnt : integer range 0 to 11 := 11;
+  signal tx_cnt : integer range 0 to ((CLOCK_FREQUENCY / BAUD_RATE) - 1);
+
+  --receive
+  signal rx_dsr : std_logic_vector(3 downto 0) := (others => '1');
+  signal rx_sr : std_logic_vector(7 downto 0) := (others => '0');
+  signal rx_bitcnt : integer range 0 to 11 := 11;
+  signal rx_cnt : integer range 0 to ((CLOCK_FREQUENCY / BAUD_RATE) - 1);
+  
+BEGIN
+
+  -- Senden
+  tx_data_proc: process(clk)
+  begin
+    if rising_edge(clk) then
+      tx_start_f <= tx_start;
+      if (tx_start = '1' or tx_bitcnt < 11) then
+        flow_ctrl <= '1';
+      else
+        flow_ctrl <= '0';
+      end if;
+      if (tx_start = '1' and tx_start_f = '0') then -- steigende Flanke, los gehts
+        tx_cnt <= 0;                                -- Zaehler initialisieren
+        tx_bitcnt <= 0;                      
+        tx_sr <= "11" & tx_data & '0';              -- 2 x Stopbit, 8 Datenbits, Startbit, rechts gehts los
+      else
+        if (tx_cnt < (CLOCK_FREQUENCY/BAUD_RATE) - 1) then
+          tx_cnt <= tx_cnt + 1;
+        else  -- naechstes Bit ausgeben  
+          if (tx_bitcnt < 11) then
+            tx_cnt <= 0;
+            tx_bitcnt <= tx_bitcnt + 1;
+            tx_sr <= '1' & tx_sr(tx_sr'left downto 1);
+          end if;
+        end if;
+      end if;
+  end if;
+  end process;
+
+  tx_en <= flow_ctrl;
+  tx_d <= tx_sr(0);  -- LSB first
+  tx_busy <= '1' when (tx_start = '1' or tx_bitcnt < 11) else '0';
+
+  -- Empfangen
+  rx_data_proc: process(clk) 
+  begin
+    if rising_edge(clk) then
+      rx_dsr <= rx_dsr(rx_dsr'left - 1 downto 0) & rx_d;
+      if (rx_bitcnt < 11) then    -- Empfang laeuft
+        if (rx_cnt < (CLOCK_FREQUENCY/BAUD_RATE) - 1) then 
+          rx_cnt <= rx_cnt + 1;
+        else
+          rx_cnt <= 0; 
+          rx_bitcnt <= rx_bitcnt + 1;
+          if (rx_bitcnt < 9) then
+            rx_sr <= rx_dsr(rx_dsr'left - 1) & rx_sr(rx_sr'left downto 1); -- rechts schieben, weil LSB first
+          else 
+            rx_valid <= '1';
+          end if;
+        end if;
+      else
+        if (rx_dsr(3 downto 2) = "10") then   -- warten auf Start bit
+          rx_valid <= '0';
+          rx_cnt <= ((CLOCK_FREQUENCY / BAUD_RATE) - 1) / 2;
+          rx_bitcnt <= 0;
+        end if;
+      end if;
+    end if;
+  end process;
+  
+  rx_en <= flow_ctrl;
+  rx_data <= rx_sr;
+  --rx_busy <= '1' when (rx_bitcnt < 11) else '0';
+
+END ARCHITECTURE beha;
Index: /firmware/FTM/ftu_control/FTM_ftu_rs485_interpreter.vhd
===================================================================
--- /firmware/FTM/ftu_control/FTM_ftu_rs485_interpreter.vhd	(revision 10175)
+++ /firmware/FTM/ftu_control/FTM_ftu_rs485_interpreter.vhd	(revision 10175)
@@ -0,0 +1,180 @@
+----------------------------------------------------------------------------------
+-- Company:        ETH Zurich, Institute for Particle Physics
+-- Engineer:       Q. Weitzel
+-- 
+-- Create Date:    02/04/2011
+-- Design Name: 
+-- Module Name:    FTM_ftu_rs485_interpreter - Behavioral 
+-- Project Name: 
+-- Target Devices: 
+-- Tool versions: 
+-- Description:    data interpreter of FTM RS485 module for FTU communication
+--
+-- Dependencies: 
+--
+-- Revision: 
+-- Revision 0.01 - File Created
+-- Additional Comments: 
+--
+----------------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.STD_LOGIC_ARITH.ALL;
+use IEEE.STD_LOGIC_UNSIGNED.ALL;
+
+library ftm_definitions;
+USE ftm_definitions.ftm_array_types.all;
+USE ftm_definitions.ftm_constants.all;
+
+---- Uncomment the following library declaration if instantiating
+---- any Xilinx primitives in this code.
+--library UNISIM;
+--use UNISIM.VComponents.all;
+
+entity FTM_ftu_rs485_interpreter is
+  port(
+    clk               : IN  std_logic;
+    data_block        : IN  std_logic_vector(FTU_RS485_BLOCK_WIDTH - 1 downto 0);  -- from receiver
+    block_valid       : IN  std_logic;  -- from receiver
+    crc               : IN  std_logic_vector(7 downto 0);  -- from ucrc_par
+    FTU_brd_add       : IN  std_logic_vector(5 downto 0);  -- from FTM_ftu_control FSM
+    FTU_command       : IN  std_logic_vector(7 downto 0);  -- from FTM_ftu_control FSM
+    reset_crc         : OUT std_logic := '0';
+    enable_crc        : OUT std_logic := '0';
+    FTU_answer_ok     : OUT std_logic := '0';
+    FTU_dac_array     : OUT FTU_dac_array_type := ((others => '0'), (others => '0'), (others => '0'), (others => '0'), (others => '0'));
+    FTU_enable_array  : OUT FTU_enable_array_type := ((others => '0'), (others => '0'), (others => '0'), (others => '0'));
+    FTU_rate_array    : OUT FTU_rate_array_type := ((others => '0'), (others => '0'), (others => '0'), (others => '0'), (others => '0'));
+    FTU_prescaling    : OUT std_logic_vector(7 downto 0) := (others => '0');
+    FTU_crc_error_cnt : OUT std_logic_vector(7 downto 0) := (others => '0');
+    FTU_dna           : OUT std_logic_vector(63 downto 0) := (others => '0')
+  );
+end FTM_ftu_rs485_interpreter;
+
+architecture Behavioral of FTM_ftu_rs485_interpreter is
+
+  signal block_valid_sr : std_logic_vector(3 downto 0) := (others => '0');
+  
+  type FTM_ftu_rs485_interpreter_StateType is (INIT, WAIT_FOR_DATA, WAIT_CRC, CHECK_CRC, CHECK_HEADER, CHECK_CMD, DECODE);
+  signal FTM_ftu_rs485_interpreter_State : FTM_ftu_rs485_interpreter_StateType;
+
+begin
+  
+  FTM_ftu_rs485_interpreter_FSM: process (clk)
+  begin
+    if Rising_edge(clk) then
+      case FTM_ftu_rs485_interpreter_State is
+
+        when INIT =>  -- reset CRC register
+          reset_crc <= '1';
+          FTU_answer_ok <= '0';
+          FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+        
+        when WAIT_FOR_DATA => -- default state, waiting for valid 28-byte block 
+          block_valid_sr <= block_valid_sr(2 downto 0) & block_valid;
+          if (block_valid_sr(3 downto 2) = "01") then  -- rising edge of valid signal
+            enable_crc <= '1';
+            FTM_ftu_rs485_interpreter_State <= WAIT_CRC;
+          else
+            enable_crc <= '0';
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          end if;
+          reset_crc <= '0';
+          FTU_answer_ok <= '0';
+
+        when WAIT_CRC =>  -- wait one cycle for CRC calculation
+          enable_crc <= '0';
+          FTU_answer_ok <= '0';
+          FTM_ftu_rs485_interpreter_State <= CHECK_CRC;
+          
+        when CHECK_CRC =>  -- check whether CRC matches
+          reset_crc <= '1';
+          FTU_answer_ok <= '0';
+          if ( crc = data_block((FTU_RS485_BLOCK_WIDTH - 1) downto (FTU_RS485_BLOCK_WIDTH -9)) ) then
+            FTM_ftu_rs485_interpreter_State <= CHECK_HEADER;
+          else
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          end if;
+          
+        when CHECK_HEADER => -- check start delimiter and addresses
+          if (data_block(7 downto 0) = FTU_RS485_START_DELIM) and
+             (data_block(15 downto 8) = FTM_ADDRESS) and  
+             (data_block(23 downto 16) = ("00" & FTU_brd_add)) then
+            FTM_ftu_rs485_interpreter_State <= CHECK_CMD;
+          else
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          end if;
+          reset_crc <= '0';
+          FTU_answer_ok <= '0';
+
+        when CHECK_CMD => -- check command
+          reset_crc <= '0';
+          if (data_block(39 downto 32) = FTU_command) then
+            FTM_ftu_rs485_interpreter_State <= DECODE;
+            FTU_answer_ok <= '1';
+          else
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+            FTU_answer_ok <= '0';
+          end if;
+          
+        when DECODE => -- decode instruction
+          FTU_answer_ok <= '0';
+          if(data_block(39 downto 32) = "00000000") then -- set DACs
+            FTU_dac_array <= (data_block( 55 downto  40),
+                              data_block( 71 downto  56),
+                              data_block( 87 downto  72),
+                              data_block(103 downto  88),
+                              data_block(119 downto 104)
+                              );
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000001") then -- read DACs
+            FTU_dac_array <= (data_block( 55 downto  40),
+                              data_block( 71 downto  56),
+                              data_block( 87 downto  72),
+                              data_block(103 downto  88),
+                              data_block(119 downto 104)
+                              );
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000010") then -- read rates
+            FTU_rate_array <= (data_block( 71 downto  40),
+                               data_block(103 downto  72),
+                               data_block(135 downto 104),
+                               data_block(167 downto 136),
+                               data_block(199 downto 168)                                
+                               );
+            FTU_crc_error_cnt <= data_block(215 downto 208);
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000011") then -- set enables
+            FTU_enable_array <= (data_block( 55 downto 40),
+                                 data_block( 71 downto 56),
+                                 data_block( 87 downto 72),
+                                 data_block(103 downto 88)
+                                 );
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000100") then -- read enables
+            FTU_enable_array <= (data_block( 55 downto 40),
+                                 data_block( 71 downto 56),
+                                 data_block( 87 downto 72),
+                                 data_block(103 downto 88)
+                                 );
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000110") then -- set counter mode
+            FTU_prescaling <= data_block(47 downto 40);
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000111") then -- read counter mode
+            FTU_prescaling <= data_block(47 downto 40);
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          elsif (data_block(39 downto 32) = "00000101") then -- ping pong
+            FTU_dna <= data_block(103 downto 40);
+            FTU_crc_error_cnt <= data_block(215 downto 208);
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          else
+            FTM_ftu_rs485_interpreter_State <= WAIT_FOR_DATA;
+          end if;
+          
+      end case;
+    end if;
+  end process FTM_ftu_rs485_interpreter_FSM;
+  
+end Behavioral;
Index: /firmware/FTM/ftu_control/FTM_ftu_rs485_receiver.vhd
===================================================================
--- /firmware/FTM/ftu_control/FTM_ftu_rs485_receiver.vhd	(revision 10175)
+++ /firmware/FTM/ftu_control/FTM_ftu_rs485_receiver.vhd	(revision 10175)
@@ -0,0 +1,68 @@
+--
+-- VHDL Architecture FACT_FAD_lib.rs485_receiver.beha
+--
+-- Created:
+--          by - Benjamin Krumm.UNKNOWN (EEPC8)
+--          at - 12:16:57 11.06.2010
+--
+-- using Mentor Graphics HDL Designer(TM) 2009.2 (Build 10)
+--
+--
+-- modified for FTU and FTM design by Q. Weitzel, 13 September 2010
+-- timeout replaced by reset by Q. Weitzel, 04 February 2011
+--
+
+LIBRARY ieee;
+USE ieee.std_logic_1164.all;
+USE ieee.std_logic_arith.all;
+
+library ftm_definitions;
+USE ftm_definitions.ftm_constants.all;
+
+ENTITY FTM_ftu_rs485_receiver IS
+  generic(
+    RX_BYTES  : integer := FTU_RS485_BLOCK_WIDTH / 8; -- no. of bytes to receive
+    RX_WIDTH  : integer := FTU_RS485_BLOCK_WIDTH
+  );
+  port(
+    rec_clk   : in  std_logic;
+    rec_reset : in  std_logic;
+    --rx_busy   : in  std_logic;
+    rec_din   : in  std_logic_vector(7 downto 0);
+    rec_den   : in  std_logic;
+    rec_dout  : out std_logic_vector(RX_WIDTH - 1 downto 0) := (others => '0');
+    rec_valid : out std_logic := '0'
+  );
+END ENTITY FTM_ftu_rs485_receiver;
+
+ARCHITECTURE beha OF FTM_ftu_rs485_receiver IS
+  
+  signal rxcnt : integer range 0 to RX_BYTES := 0;
+  signal rxsr  : std_logic_vector(3 downto 0) := (others => '0');
+  
+BEGIN
+  
+  rx_data_proc : process(rec_clk)
+  begin
+    if rising_edge(rec_clk) then
+      rxsr <= rxsr(2 downto 0) & rec_den;
+      if (rec_reset = '1') then
+        rec_dout <= (others => '0');
+        rxcnt <= 0;
+        rec_valid <= '0';
+      else        
+        if (rxsr(3 downto 2) = "01") then -- identify rising edge
+          rec_dout((rxcnt*rec_din'length + rec_din'length - 1) downto (rxcnt*rec_din'length)) <= rec_din;
+          rxcnt <= rxcnt + 1;
+          if (rxcnt < RX_BYTES - 1) then
+            rec_valid <= '0';
+          else
+            rxcnt <= 0;
+            rec_valid <= '1';
+          end if;
+        end if;
+      end if;
+    end if;
+  end process rx_data_proc;
+  
+END ARCHITECTURE beha;
Index: /firmware/FTM/ftu_control/ucrc_par.vhd
===================================================================
--- /firmware/FTM/ftu_control/ucrc_par.vhd	(revision 10175)
+++ /firmware/FTM/ftu_control/ucrc_par.vhd	(revision 10175)
@@ -0,0 +1,176 @@
+----------------------------------------------------------------------
+----                                                              ----
+---- Ultimate CRC.                                                ----
+----                                                              ----
+---- This file is part of the ultimate CRC projectt               ----
+---- http://www.opencores.org/cores/ultimate_crc/                 ----
+----                                                              ----
+---- Description                                                  ----
+---- CRC generator/checker, parallel implementation.              ----
+----                                                              ----
+----                                                              ----
+---- To Do:                                                       ----
+---- -                                                            ----
+----                                                              ----
+---- Author(s):                                                   ----
+---- - Geir Drange, gedra@opencores.org                           ----
+----                                                              ----
+----------------------------------------------------------------------
+----                                                              ----
+---- Copyright (C) 2005 Authors and OPENCORES.ORG                 ----
+----                                                              ----
+---- This source file may be used and distributed without         ----
+---- restriction provided that this copyright statement is not    ----
+---- removed from the file and that any derivative work contains  ----
+---- the original copyright notice and the associated disclaimer. ----
+----                                                              ----
+---- This source file is free software; you can redistribute it   ----
+---- and/or modify it under the terms of the GNU General          ----
+---- Public License as published by the Free Software Foundation; ----
+---- either version 2.0 of the License, or (at your option) any   ----
+---- later version.                                               ----
+----                                                              ----
+---- This source is distributed in the hope that it will be       ----
+---- useful, but WITHOUT ANY WARRANTY; without even the implied   ----
+---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ----
+---- PURPOSE. See the GNU General Public License for more details.----
+----                                                              ----
+---- You should have received a copy of the GNU General           ----
+---- Public License along with this source; if not, download it   ----
+---- from http://www.gnu.org/licenses/gpl.txt                     ----
+----                                                              ----
+----------------------------------------------------------------------
+--
+-- CVS Revision History
+--
+-- $Log: not supported by cvs2svn $
+-- Revision 1.1  2005/05/09 15:58:38  gedra
+-- Parallel implementation
+--
+--
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity ucrc_par is
+   generic (
+      POLYNOMIAL : std_logic_vector;
+      INIT_VALUE : std_logic_vector;
+      DATA_WIDTH : integer range 2 to 256;
+      SYNC_RESET : integer range 0 to 1);  -- use sync./async reset
+   port (
+      clk_i   : in  std_logic;          -- clock
+      rst_i   : in  std_logic;          -- init CRC
+      clken_i : in  std_logic;          -- clock enable
+      data_i  : in  std_logic_vector(DATA_WIDTH - 1 downto 0);  -- data input
+      match_o : out std_logic;          -- CRC match flag
+      crc_o   : out std_logic_vector(POLYNOMIAL'length - 1 downto 0));  -- CRC output
+end ucrc_par;
+
+architecture rtl of ucrc_par is
+
+   constant msb      : integer                        := POLYNOMIAL'length - 1;
+   constant init_msb : integer                        := INIT_VALUE'length - 1;
+   constant p        : std_logic_vector(msb downto 0) := POLYNOMIAL;
+   constant dw       : integer                        := DATA_WIDTH;
+   constant pw       : integer                        := POLYNOMIAL'length;
+   type fb_array is array (dw downto 1) of std_logic_vector(msb downto 0);
+   type dmsb_array is array (dw downto 1) of std_logic_vector(msb downto 1);
+   signal crca       : fb_array;
+   signal da, ma     : dmsb_array;
+   signal crc, zero  : std_logic_vector(msb downto 0);
+   signal arst, srst : std_logic;
+   
+begin
+
+-- Parameter checking: Invalid generics will abort simulation/synthesis
+   PCHK1 : if msb /= init_msb generate
+      process
+      begin
+         report "POLYNOMIAL and INIT_VALUE vectors must be equal length!"
+            severity failure;
+         wait;
+      end process;
+   end generate PCHK1;
+
+   PCHK2 : if (msb < 3) or (msb > 31) generate
+      process
+      begin
+         report "POLYNOMIAL must be of order 4 to 32!"
+            severity failure;
+         wait;
+      end process;
+   end generate PCHK2;
+
+   PCHK3 : if p(0) /= '1' generate      -- LSB must be 1
+      process
+      begin
+         report "POLYNOMIAL must have lsb set to 1!"
+            severity failure;
+         wait;
+      end process;
+   end generate PCHK3;
+
+-- Generate vector of each data bit
+   CA : for i in 1 to dw generate       -- data bits
+      DAT : for j in 1 to msb generate
+         da(i)(j) <= data_i(i - 1);
+      end generate DAT;
+   end generate CA;
+
+-- Generate vector of each CRC MSB
+   MS0 : for i in 1 to msb generate
+      ma(1)(i) <= crc(msb);
+   end generate MS0;
+   MSP : for i in 2 to dw generate
+      MSU : for j in 1 to msb generate
+         ma(i)(j) <= crca(i - 1)(msb);
+      end generate MSU;
+   end generate MSP;
+
+-- Generate feedback matrix
+   crca(1)(0)            <= da(1)(1) xor crc(msb);
+   crca(1)(msb downto 1) <= crc(msb - 1 downto 0) xor ((da(1) xor ma(1)) and p(msb downto 1));
+   FB : for i in 2 to dw generate
+      crca(i)(0)            <= da(i)(1) xor crca(i - 1)(msb);
+      crca(i)(msb downto 1) <= crca(i - 1)(msb - 1 downto 0) xor
+                               ((da(i) xor ma(i)) and p(msb downto 1));
+   end generate FB;
+
+-- Reset signal
+   SR : if SYNC_RESET = 1 generate
+      srst <= rst_i;
+      arst <= '0';
+   end generate SR;
+   AR : if SYNC_RESET = 0 generate
+      srst <= '0';
+      arst <= rst_i;
+   end generate AR;
+
+-- CRC process
+   crc_o <= crc;
+   zero  <= (others => '0');
+
+   CRCP : process (clk_i, arst)
+   begin
+      if arst = '1' then                -- async. reset
+         crc     <= INIT_VALUE;
+         match_o <= '0';
+      elsif rising_edge(clk_i) then
+         if srst = '1' then             -- sync. reset
+            crc     <= INIT_VALUE;
+            match_o <= '0';
+         elsif clken_i = '1' then
+            crc <= crca(dw);
+            if crca(dw) = zero then
+               match_o <= '1';
+            else
+               match_o <= '0';
+            end if;
+         end if;
+      end if;
+   end process;
+   
+end rtl;
+
