---------------------------------------------------------------------------------- -- Company: -- Engineer: Matti Ruohonen -- -- Create Date: 2011-05-26 15:12:15 -- Modification Date: 2011-05-26 17:14:50 -- Design Name: -- Module Name: spi_to_ft2232 - Behavioral -- Project Name: LUT PCU Loader: SPI to FT2232 bridge -- Target Devices: CoolRunner (XCR3064XL-6CSG48C) -- Tool versions: -- Description: Top level file for SPI to FT2232 communication bridge -- -- 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; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity spi_to_ft2232 is port ( clk_i : in std_logic; -- 6 MHz clock input from FT2232 XTOUT NOTE: only runs when the FT2232 is connected to USB bus (has power) rst_i : in std_logic; -- _RSTOUT from FT2232 spi_clk_i : in std_logic; -- SPI SCK from F2806 spi_din_i : in std_logic; -- SPI MOSI from F2806 spi_ste_i : in std_logic; -- SPI STE from F2806 spi_dout_o : out std_logic; -- SPI MISO to F2806 data_a_io : inout std_logic_vector(7 downto 0); -- FT2232 data bus A data_b_io : inout std_logic_vector(7 downto 0); -- FT2232 data bus B rd_a_o : out std_logic; -- RD to FT2232 bus A wr_a_o : out std_logic; -- WR to FT2232 bus A rxf_a_i : in std_logic; -- RXF from FT2232 bus A txe_a_i : in std_logic; -- TXE from FT2232 bus A rd_b_o : out std_logic; -- RD to FT2232 bus A wr_b_o : out std_logic; -- WR to FT2232 bus A rxf_b_i : in std_logic; -- RXF from FT2232 bus A txe_b_i : in std_logic; -- TXE from FT2232 bus A usb_busy_o : out std_logic -- ?? ); end spi_to_ft2232; architecture Behavioral of spi_to_ft2232 is signal spi_rx : std_logic_vector(9 downto 0); signal spi_tx : std_logic_vector(9 downto 0); signal ft_tx : std_logic_vector(7 downto 0); signal ft_rx : std_logic_vector(9 downto 0); signal clk_counter : std_logic_vector(3 downto 0); signal tx_cnt_w : std_logic; signal tx_cnt_r : std_logic; signal rd_a : std_logic; signal wr_a : std_logic; signal rd_b : std_logic; signal wr_b : std_logic; signal tx_a : std_logic; signal tx_b : std_logic; signal da_a, dt_a : std_logic; signal da_b, dt_b : std_logic; signal init : std_logic := '0'; begin PROCESS_SCK_R: process (spi_clk_i) begin if (spi_clk_i'event and spi_clk_i = '1') then -- SPI SCK rising edge if (spi_ste_i = '0') then -- STE active: SPI enabled spi_rx <= spi_rx(8 downto 0) & spi_din_i; tx_a <= '0'; tx_b <= '0'; -- 9 bits received already, this is the 10th => one frame received if (clk_counter = "1001") then -- The new value is not available yet, so we construct it manually here too ft_tx <= spi_rx(6 downto 0) & spi_din_i; -- NOTE: Header is in bits 8..7 since the new value is not yet available if (spi_rx(8 downto 7) = "01") then -- Valid header for channel A tx_a <= '1'; elsif (spi_rx(8 downto 7) = "10") then -- Valid header for channel B tx_b <= '1'; end if; -- spi_rx <= (others => '0'); clk_counter <= (others => '0'); -- The bit counter will start counting from the valid header onwards -- This has the effect of re-synchronising after possible bit errors elsif (clk_counter = "0000") then -- Waiting for valid header -- Valid headers are 01 and 10 for A and B channel respectively if (spi_rx(1 downto 0) = "01" or spi_rx(1 downto 0) = "10") then -- NOTE: We have actually received 3 bits at this point, -- since the register gets updated after this process ends. clk_counter <= "0011"; -- So, set the counter to three -- The above is also why we check the bits 1 and 0 from the register. -- Or rather, we could check bit 0 and spi_din_i and set the counter to two... end if; else clk_counter <= clk_counter + 1; end if; end if; end if; end process PROCESS_SCK_R; PROCESS_SCK_F: process(spi_clk_i) begin if (spi_clk_i'event and spi_clk_i = '0') then -- Falling edge on SPI SCK if (spi_ste_i = '1') then spi_tx <= (others => '0'); tx_cnt_w <= '0'; --(others => '0'); else -- if (spi_ste_i = '0') then -- STE low: SPI enabled if (clk_counter = "0000") then spi_tx <= ft_rx; -- tx_cnt_w <= tx_cnt_w XOR '1'; else spi_tx <= spi_tx(8 downto 0) & '0'; -- Shift transmit register end if; end if; end if; end process PROCESS_SCK_F; PROCESS_CLK: process (clk_i) begin if (clk_i'event and clk_i = '1') then -- CLK rising edge if (rst_i = '0' or init = '0') then -- Reset (from FT2232) active rd_a <= '1'; -- active low rd_b <= '1'; -- active low wr_a <= '0'; wr_b <= '0'; da_a <= '0'; dt_a <= '0'; da_b <= '0'; dt_b <= '0'; -- ft_rx <= (others => '0'); -- tx_cnt_r <= (others => '0'); init <= '1'; -- Used to check for power-up init else if (da_a = '1') then -- There is data to be transmitted if (wr_a = '1') then -- Write signal has been high for one clock cycle -- Lower the write signal, which also latches the data into the FT2232 wr_a <= '0'; -- tx_a already inactive, so we can reset the check_a signal too if (tx_a = '0') then da_a <= '0'; -- Reset the 'only transmit once check' signal dt_a <= '0'; -- Reset the 'data transmitted' signal end if; -- Transmission allowed for channel A and data not already transmitted elsif (txe_a_i = '0' and dt_a = '0') then wr_a <= '1'; -- Activate channel A WR signal dt_a <= '1'; -- Mark the data as transmitted elsif (tx_a = '0' and dt_a = '1') then -- tx_a inactive and data has been transmitted da_a <= '0'; -- Reset the 'only transmit once check' signal dt_a <= '0'; -- Reset the 'data transmitted' signal end if; elsif (tx_a = '1') then -- Latch the 'data available' status to a private signal da_a <= '1'; elsif (da_b = '1') then -- There is data to be transmitted if (wr_b = '1') then -- Write signal has been high for one clock cycle -- Lower the write signal, which also latches the data into the FT2232 wr_b <= '0'; -- tx_a already inactive, so we can reset the check_a signal too if (tx_b = '0') then da_b <= '0'; -- Reset the 'only transmit once check' signal dt_b <= '0'; -- Reset the 'data transmitted' signal end if; -- Transmission allowed for channel A and data not already transmitted elsif (txe_b_i = '0' and dt_b = '0') then wr_b <= '1'; -- Activate channel A WR signal dt_b <= '1'; -- Mark the data as transmitted elsif (tx_b = '0' and dt_b = '1') then -- tx_a inactive and data has been transmitted da_b <= '0'; -- Reset the 'only transmit once check' signal dt_b <= '0'; -- Reset the 'data transmitted' signal end if; elsif (tx_b = '1') then -- Latch the 'data available' status to a private signal da_b <= '1'; end if; -- No Tx going on, check for received data if (da_a = '0' and da_b = '0') then if (tx_cnt_w /= tx_cnt_r) then -- Old data transmitted -- Received data for channel A in FT2232 buffer if (rxf_a_i = '0') then if (rd_a = '0') then -- RD signal already active ft_rx <= "01" & data_a_io; -- Read channel A data byte and add header rd_a <= '1'; -- Disable RD signal else rd_a <= '0'; -- Activate RD signal end if; -- Received data for channel B in FT2232 buffer and no Tx going on elsif (rxf_b_i = '0') then if (rd_b = '0') then -- RD signal already active ft_rx <= "10" & data_b_io; -- Read channel B data byte and add header rd_b <= '1'; -- Disable RD signal else rd_b <= '0'; -- Activate RD signal end if; end if; tx_cnt_r <= tx_cnt_w; end if; end if; end if; end if; end process PROCESS_CLK; data_a_io <= ft_tx when (wr_a = '1') else (others => 'Z'); data_b_io <= ft_tx when (wr_b = '1') else (others => 'Z'); rd_a_o <= rd_a; wr_a_o <= wr_a; rd_b_o <= rd_b; wr_b_o <= wr_b; spi_dout_o <= spi_tx(9); end Behavioral;
Comments
0 B
|0 👍
/0 👎
0 B
|👍
/👎