Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

FT2232H write from PC to FPGA not working

I am now using the FT2232H usb chip in FT245 Sync Fifo mode. I tried to write some bytes from PC to FPGA and then read them back. But the following code is not working: what I read back is always 0x55, not what I wrote to FPGA. Here is the code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FTDI_Controller is 
port(    
    FTDI_RXF_n            : in std_logic;        
    FTDI_TXE_n            : in std_logic;        
    FTDI_RD_n            : out std_logic;        
    FTDI_WR_n            : out std_logic;        
    FTDI_OE_n            : out std_logic;        
    FTDI_Data            : inout std_logic_vector(7 downto 0);  
    CLK_FTDI        : in std_logic        
    );
end FTDI_Controller;
architecture RTL of FTDI_Controller is
begin
process(CLK_FTDI)
    variable rCS: integer range 0 to 2:=0;
    variable wCS: integer range 0 to 1:=0;
    variable D_Readed: std_logic_vector(7 downto 0):=x"55"; 
begin
    if rising_edge(CLK_FTDI) then  
        --read operations
        if (FTDI_RXF_n = '0') then 
            FTDI_WR_n <= '1';
            wCS:=0;
            
            CASE rCS is
                when 0 =>
                    FTDI_OE_n <= '0';   
                    rCS:=1;
                when 1 =>
                    FTDI_RD_n <= '0';
                    rCS:=2;
                    
                when 2 =>
                    D_Readed := FTDI_Data;
                when others =>
                    rCS:=0;
                    
            end CASE;
            
        else
            FTDI_RD_n <= '1';
            FTDI_OE_n <= '1';
            rCS:=0;
            
            --write operations    
            if(FTDI_TXE_n ='0') then 
                
                CASE wCS is 
                    when 0 =>
                        FTDI_WR_n <= '0';
                        wCS:=1;
                    when 1 =>
                        FTDI_Data <= D_Readed;
                    when others =>
                        wCS:=0;
                end CASE;
                
            else 
                FTDI_WR_n <= '1';
                wCS:=0;
            end if; 
                
        end if; 
    end if; 
         
end process;  
  
end RTL;

4 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I believe D_Readed needs to be a registered signal, not a variable.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I believe D_Readed needs to be a registered signal, not a variable.

    --- Quote End ---

    I have tried to change D_Readed to a registered signal, but the result is the same. I stuck in this problem for a long time.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You can't drive a bidirectional bus in such a simple manner. You need some logic to determine when to drive the bus and when not to.

    Try this. I hope it helps and points you in the right direction.
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    entity FTDI_Controller is 
    port(    
        FTDI_RXF_n            : in std_logic;        
        FTDI_TXE_n            : in std_logic;        
        FTDI_RD_n            : out std_logic;        
        FTDI_WR_n            : out std_logic;        
        FTDI_OE_n            : out std_logic;        
        FTDI_Data            : inout std_logic_vector(7 downto 0);  
        CLK_FTDI        : in std_logic        
        );
    end FTDI_Controller;
    architecture RTL of FTDI_Controller is
        signal D_Readed: std_logic_vector(7 downto 0); 
        signal drive_bus: std_logic;    -- Use this to determine control drive of the 'FTDI_Data' bus
    begin
    process(CLK_FTDI)
        variable rCS: integer range 0 to 2:=0;
        variable wCS: integer range 0 to 1:=0;
    begin
        if rising_edge(CLK_FTDI) then
            drive_bus <= '0';           -- Ensure the bus isnt driven when it shouldn't be
            --read operations
            if (FTDI_RXF_n = '0') then 
                FTDI_WR_n <= '1';
                wCS:=0;
                
                CASE rCS is
                    when 0 =>
                        FTDI_OE_n <= '0';   
                        rCS:=1;
                    when 1 =>
                        FTDI_RD_n <= '0';
                        rCS:=2;
                        
                    when 2 =>
                        D_Readed <= FTDI_Data;
                    when others =>
                        rCS:=0;
                        
                end CASE;
                
            else
                FTDI_RD_n <= '1';
                FTDI_OE_n <= '1';
                rCS:=0;
                
                --write operations    
                if(FTDI_TXE_n ='0') then 
                    
                    CASE wCS is 
                        when 0 =>
                            FTDI_WR_n <= '0';
                            drive_bus <= '1';   -- You're writing, so drive the bus...
                            wCS:=1;
                        when 1 =>
                            drive_bus <= '0';   -- ... for a bit. Then stop.
                        when others =>
                            wCS:=0;
                    end CASE;
                    
                else 
                    FTDI_WR_n <= '1';
                    wCS:=0;
                end if; 
                    
            end if; 
        end if; 
             
    end process;  
    -- Control the data being driven onto the FTDI_Data bus here:
    FTDI_Data <= D_Readed when drive_bus = '1' else (others => 'Z');
    end RTL;
    

    Cheers,

    Alex
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    You can't drive a bidirectional bus in such a simple manner. You need some logic to determine when to drive the bus and when not to.

    Try this. I hope it helps and points you in the right direction.
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    entity FTDI_Controller is 
    port(    
        FTDI_RXF_n            : in std_logic;        
        FTDI_TXE_n            : in std_logic;        
        FTDI_RD_n            : out std_logic;        
        FTDI_WR_n            : out std_logic;        
        FTDI_OE_n            : out std_logic;        
        FTDI_Data            : inout std_logic_vector(7 downto 0);  
        CLK_FTDI        : in std_logic        
        );
    end FTDI_Controller;
    architecture RTL of FTDI_Controller is
        signal D_Readed: std_logic_vector(7 downto 0); 
        signal drive_bus: std_logic;    -- Use this to determine control drive of the 'FTDI_Data' bus
    begin
    process(CLK_FTDI)
        variable rCS: integer range 0 to 2:=0;
        variable wCS: integer range 0 to 1:=0;
    begin
        if rising_edge(CLK_FTDI) then
            drive_bus <= '0';           -- Ensure the bus isnt driven when it shouldn't be
            --read operations
            if (FTDI_RXF_n = '0') then 
                FTDI_WR_n <= '1';
                wCS:=0;
                
                CASE rCS is
                    when 0 =>
                        FTDI_OE_n <= '0';   
                        rCS:=1;
                    when 1 =>
                        FTDI_RD_n <= '0';
                        rCS:=2;
                        
                    when 2 =>
                        D_Readed <= FTDI_Data;
                    when others =>
                        rCS:=0;
                        
                end CASE;
                
            else
                FTDI_RD_n <= '1';
                FTDI_OE_n <= '1';
                rCS:=0;
                
                --write operations    
                if(FTDI_TXE_n ='0') then 
                    
                    CASE wCS is 
                        when 0 =>
                            FTDI_WR_n <= '0';
                            drive_bus <= '1';   -- You're writing, so drive the bus...
                            wCS:=1;
                        when 1 =>
                            drive_bus <= '0';   -- ... for a bit. Then stop.
                        when others =>
                            wCS:=0;
                    end CASE;
                    
                else 
                    FTDI_WR_n <= '1';
                    wCS:=0;
                end if; 
                    
            end if; 
        end if; 
             
    end process;  
    -- Control the data being driven onto the FTDI_Data bus here:
    FTDI_Data <= D_Readed when drive_bus = '1' else (others => 'Z');
    end RTL;
    

    Cheers,

    Alex

    --- Quote End ---

    Finally I got it working with your tips. Thanks so much, Alex. :)