OpenCores
URL https://opencores.org/ocsvn/etherlab/etherlab/trunk

Subversion Repositories etherlab

[/] [etherlab/] [trunk/] [vhdl/] [io.vhd] - Rev 2

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------------
-- ETHERLAB - FPGA To C# To LABVIEW Bridge                                    --
--------------------------------------------------------------------------------
-- REFERNCES                                                                  --
--  [1] LTC2604/LTC2614/LTC2624 Quad 16-Bit Rail-to-Rail DACs                 --
--  [2] Xilinx UG230                                                          --
--  [3] LTC6912 Dual Programmable Gain Amplifiers                             --
--  [4] LTC1407/LTC1407A Serial 12-Bit/14-Bit, 3Msps ADCs                     --
--------------------------------------------------------------------------------
-- Copyright (C)2012  Mathias Hörtnagl <mathias.hoertnagl@gmail.com>          --
--                                                                            --
-- This program 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 3 of the License, or          --
-- (at your option) any later version.                                        --
--                                                                            --
-- This program 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 program.  If not, see <http://www.gnu.org/licenses/>.      --
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library work;
use work.common.all;
 
entity io is
   port(
      clk         : in  std_logic;
      clk90       : in  std_logic;
   -- EtherLab data received.
      el_chnl     : in  std_logic_vector(7 downto 0);
      el_data     : in  data_t;
      el_dv       : in  std_logic;
      el_ack      : out std_logic;
   -- EtherLab data to send.
      el_snd_chnl : out std_logic_vector(7 downto 0);
      el_snd_data : out data_t;
      el_snd_en   : out std_logic;
   -- DAC/ADC Connections.
      SPI_MISO    : in  std_logic;
      SPI_MOSI    : out std_logic;
      SPI_SCK     : out std_logic;
      DAC_CS      : out std_logic;
      DAC_CLR     : out std_logic;
      AD_CONV     : out std_logic;
      AMP_CS      : out std_logic;
   -- Digital lines.
      DI          : in  std_logic_vector(3 downto 0);
      DO          : out std_logic_vector(3 downto 0);
   -- SWITCHES.
      SW          : in  std_logic_vector(3 downto 0);
   -- BUTTONS.
      BTN         : in  std_logic_vector(3 downto 0);
   -- LEDs.
      LED         : out std_logic_vector(7 downto 0)
   );
end io;
 
architecture rtl of io is
 
   -----------------------------------------------------------------------------
   -- SETTING:                                                                --
   --  + FREQ: Clock frequency. Usually 50 MHz.                               --
   --  + PULSE_WIDTH: Time between two EtherLab transmissions.                --   
   -----------------------------------------------------------------------------
   constant FREQ        : natural := 50;     -- [MHz] Frequency.
   constant PULSE_WIDTH : natural := 100;    -- [msec] Time between two sends.
 
   constant CYCLES_PER_MSEC : natural := 1000000/FREQ;
 
   type state_t is (Idle, Ready, AnalogOut, Send);
 
   type reg_t is record
      s    : state_t;
      chnl : std_logic_vector(7 downto 0);      -- Channel latch.
      ao   : std_logic_vector(23 downto 4);     -- Analog out register.
      do   : std_logic_vector(3 downto 0);      -- Digital out register.
      led  : std_logic_vector(7 downto 0);      -- LED register.
      c    : natural range 0 to 23;
   end record;
 
   type snd_state_t is (Idle, Pulse, Transmit);
 
   type snd_t is record
      s : snd_state_t;
      d : data_t;                                  -- EtherLab data struct.
      q : natural range 0 to CYCLES_PER_MSEC-1;    -- Milliseconds counter.
      p : natural range 0 to PULSE_WIDTH-1;        -- Pulse counter.
   end record;
 
   signal r, rin : reg_t := reg_t'(Idle, x"00", x"00000", x"0", x"00", 0);  
   signal s, sin : snd_t := snd_t'(Idle, (others => (others => '0')), 0,0);
begin
 
   snd : process(s, SW, BTN)
   begin
 
      sin <= s;
 
      el_snd_en <= '0';                   -- Turn off Ethernet packet sending.
 
      case s.s is
 
         when Idle =>
            if s.q = (CYCLES_PER_MSEC-1) then
               sin.q <= 0;
               if s.p = (PULSE_WIDTH-1) then
                  sin.p <= 0;
                  sin.s <= Pulse;
               else
                  sin.p <= s.p + 1;
               end if;
            else
               sin.q <= s.q + 1;
            end if;
 
         when Pulse =>
            sin.d(CHANNEL_E) <= x"000" & DI;       -- Sample digital input.
            sin.d(CHANNEL_G) <= x"000" & BTN;      -- Sample buttons.
            sin.d(CHANNEL_H) <= x"000" & SW;       -- Sample switches.
            sin.s            <= Transmit; 
 
         when Transmit =>
            el_snd_en <= '1';                      -- Send Ethernet packet.
            sin.s     <= Idle; 
 
      end case; 
   end process;
 
   el_snd_chnl <= "11010000";
   el_snd_data <= s.d;
 
 
   nsl : process(r, el_chnl, el_data, el_dv, clk90, SPI_MISO)
 
      -- DAC Commands and Addresses.
      constant CMD_UP : std_logic_vector(3 downto 0) := "0011";
      constant ADR_OA : std_logic_vector(3 downto 0) := "0000";
      constant ADR_OB : std_logic_vector(3 downto 0) := "0001";
      constant ADR_OC : std_logic_vector(3 downto 0) := "0010";
      constant ADR_OD : std_logic_vector(3 downto 0) := "0011";
   begin
 
      rin <= r;
 
      SPI_MOSI <= r.ao(23);      -- Send always the MSBit of the data register.
      SPI_SCK  <= '0';           -- Pull down SPI clock.
      DAC_CLR  <= '1';           -- Disable D/A Converter.
      DAC_CS   <= '1';
      AD_CONV  <= '0';           -- Disable A/D Converter.
      AMP_CS   <= '1';           -- Disable Pre Amplifier.
 
      el_ack    <= '0';          -- Ethernet receiver data ready ACK.
 
      case r.s is
         when Idle =>
            if el_dv = '1' then               
               rin.chnl <= el_chnl;
               rin.s <= Ready;
            end if;
 
         -- IMPROVE: Merge Ready and AnalogOut states.
         when Ready =>             
            --------------------------------------------------------------------
            -- LED Control                                                    --
            --------------------------------------------------------------------
            if isSet(r.chnl, CHANNEL_H) then
               rin.led <= el_data(CHANNEL_H)(7 downto 0);
               rin.chnl(CHANNEL_H) <= '0';
            end if;
            --------------------------------------------------------------------
            -- Digital Out Control                                            --
            --------------------------------------------------------------------
            if isSet(r.chnl, CHANNEL_G) then
               rin.do <= el_data(CHANNEL_G)(3 downto 0);
               rin.chnl(CHANNEL_G) <= '0';
            end if;
            --------------------------------------------------------------------
            -- Analog Out Control                                             --
            --------------------------------------------------------------------
            if r.chnl(3 downto 0) /= x"0" then
               rin.s <= AnalogOut;
            else
               rin.s <= Idle; 
            end if;        
 
         -----------------------------------------------------------------------
         -- Analog Out Control                                                --
         -----------------------------------------------------------------------
         -- Send data to DAC. Since all DACs are controlled via a singe serial 
         -- interface, the setting of new data follows the following precedence:
         -- A > B > C > D. Thus if data is ready for analog output A, it will be
         -- sent first. Next is analog output B, then C and finally D. 
         when AnalogOut =>          
            if isSet(r.chnl, CHANNEL_A) then
               rin.ao <= CMD_UP & ADR_OA & el_data(CHANNEL_A)(11 downto 0);
               rin.chnl(CHANNEL_A) <= '0';   -- Clear channel flag.
               rin.s <= Send;
            elsif isSet(r.chnl, CHANNEL_B) then
               rin.ao <= CMD_UP & ADR_OB & el_data(CHANNEL_B)(11 downto 0);
               rin.chnl(CHANNEL_B) <= '0';  
               rin.s <= Send;
            elsif isSet(r.chnl, CHANNEL_C) then
               rin.ao <= CMD_UP & ADR_OC & el_data(CHANNEL_C)(11 downto 0);
               rin.chnl(CHANNEL_C) <= '0'; 
               rin.s <= Send;
            elsif isSet(r.chnl, CHANNEL_D) then          
               rin.ao <= CMD_UP & ADR_OD & el_data(CHANNEL_D)(11 downto 0);
               rin.chnl(CHANNEL_D) <= '0';
               rin.s <= Send;
            else
               rin.s <= Idle;    -- All flags are cleared and DACs are updated.
            end if;
 
         -- To send data at maximum speed, we send clk90, wich is the clock
         -- signal phase shifted by 90 degree. This is necessary to meet the
         -- timing constraints t1 and t2 defined in [1].
         when Send =>
            DAC_CS  <= '0';
            SPI_SCK <= clk90;
            rin.ao  <= r.ao(22 downto 4) & '0';
            if r.c = 23 then
               rin.c <= 0;
               rin.s <= AnalogOut;
            else
               rin.c <= r.c + 1;
               rin.s <= Send;
            end if;
 
         -----------------------------------------------------------------------
         -- TODO: Analog In Control                                           --
         -----------------------------------------------------------------------
         -- Pulse the ADC and capture the data from the last pulse.
         -- when Pulse =>
            -- AD_CONV <= '1';
            -- SPI_SCK <= clk90;
            -- rin.c   <= 0;
            -- rin.d(CHANNEL_E) <= x"000" & DI;       -- Sample digital input.
            -- rin.d(CHANNEL_G) <= x"000" & BTN;      -- Sample buttons.
            -- rin.d(CHANNEL_H) <= x"000" & SW;       -- Sample switches.
            -- rin.s   <= Transmit; --Wait0;
 
         -- when Wait0 =>
            -- SPI_SCK <= clk90;
            -- if r.c = 1 then
               -- rin.c <= 0;
               -- rin.s <= Receive0;
            -- else
               -- rin.c <= r.c + 1;
            -- end if;            
 
         -- when Receive0 =>
            -- SPI_SCK <= clk90;
            -- rin.d(CHANNEL_A) <= r.d(CHANNEL_A)(15 downto 1) & SPI_MISO;
            -- if r.c = 13 then
               -- rin.c <= 0;
               -- rin.s <= Wait1;
            -- else
               -- rin.c <= r.c + 1;
            -- end if;
 
         -- when Wait1 =>
            -- SPI_SCK <= clk90;
            -- if r.c = 1 then
               -- rin.c <= 0;
               -- rin.s <= Receive1;
            -- else
               -- rin.c <= r.c + 1;
            -- end if;            
 
         -- when Receive1 =>
            -- SPI_SCK <= clk90;
            -- rin.d(CHANNEL_B) <= r.d(CHANNEL_B)(15 downto 1) & SPI_MISO;
            -- if r.c = 13 then
               -- rin.c <= 0;
               -- rin.s <= Transmit;
            -- else
               -- rin.c <= r.c + 1;
            -- end if;
 
      end case;
   end process;
 
   DO  <= r.do;
   LED <= r.led;
 
   reg : process(clk)
   begin
      if rising_edge(clk) then
         r <= rin;
         s <= sin;
      end if;
   end process;
end rtl;

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.