Forum Discussion

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

Missing Bytes reading FPGA data with FTDI 2232H

Hi,

I recently developing an FPGA program that will be used to measure something.

IO inputs will be stored in the FPGA SRAM and later transferred with over USB with the FTDI chip to be processed on a PC.

With testing only the USB part of the program I noticed that some bytes are missing (on regular base each 128 bytes there is one missing, and on rare occurrence there are several missing).

To test this I implemented a counter in VHDL code generating bytes to transmit to the PC.

Part of the VHDL code :

elsif (State_WR = '1' )   then     
        STM_RD<= rd_idle;    
        --#  Start sequence of setting flags to write to the FTDI            
              case STM_WR is                    
            --## WRITE IDLE : prepare flags of FTDI and RAM
            when wr_idle =>
                FTDI_OE_n<='1';
                    --If FTDI_TXE_n is 0, then FTDI will allow data to be transmitted 
                if(FTDI_TXE_n ='1') then
                    STM_WR <= do_WR;
                end if;    
                FTDI_WR_n <= '1';        
                        
            --## WRITE START: start write command to FTDI
            when do_WR =>
                FTDI_WR_n <= '0';        -- Enables the data byte on the D0...D7 pins to be written into the transmit FIFO buffer
                STM_WR <= burst_write;
            &#8203;
                        --## WRITE BURST: burst bytes to FTDI            
                         when burst_write =>
                -- If FTDI_TXE_n is asserted, FTDI does not want data anymore, so we pause XMIT:
                if(FTDI_TXE_n = '0') then 
                    STM_WR <= wr_pause;
                    FTDI_WR_n <= '1';    -- Disable write enable                                
                else        
                        counter <= counter+1;
                                        --******************Output data*************
                    FTDI_Data<=std_logic_vector(to_unsigned(counter,8));                  
                end if;        
            --# # PAUSE : FTDI chip needs a break...    
            when wr_pause =>
                State_ReadyToWrite <='0';        
                if(FTDI_TXE_n = '1') then    
                    State_ReadyToWrite <='1';    
                    STM_WR <= burst_write;
                    FTDI_WR_n <= '0';    -- enable writing again
                end if;
            when others =>
            end case;     

C++ program (used functions):

bool FT2232H::Initialize()
    {
        UCHAR mask = 0xff;            // set all IOs to output
        UCHAR mode = 0x00;            // reset value of bitmode
        //UCHAR bitMode;
        UCHAR latencyTimer = 2; // default setting is 16
        int deviceIndx=0;                // Select first FTDI device
        FT_STATUS ftStatus;
        int readTimeout = 900;    // 
        int writeTimeout =2000;    // 
        // Obtain handle
        ftStatus = FT_Open(deviceIndx, &ftHandle); 
        if (ftHandle == INVALID_HANDLE_VALUE)
            cout<<"failed opening connection";
        ftStatus = FT_SetBitMode(ftHandle, mask, mode);
        Sleep(1000);
        mode = 0x40; //Sync FIFO mode
        ftStatus = FT_SetBitMode(ftHandle, mask, mode);
        if (ftStatus == FT_OK)
            {
            ftStatus = FT_SetLatencyTimer(ftHandle, latencyTimer); 
            ftStatus = FT_SetUSBParameters(ftHandle,0x10000,0x10000);
            ftStatus = FT_SetFlowControl(ftHandle,FT_FLOW_RTS_CTS,0,0);
            ftStatus = FT_SetTimeouts(ftHandle,readTimeout,writeTimeout);
            //ftStatus = FT_GetBitMode(ftHandle, &bitMode);
            return true;
            }
        else
            {
            //TODO add recovery and feedback wheb ftStatus is not OK
            return false;
            }        
    }
bool FT2232H::Read(char *pRxBuf,int bufSize)
    {
    bool isReadDone= false;
    DWORD bytesReceived;
    FT_STATUS ftStatus;
    char *pRxBufCur = pRxBuf;
    int maxBufSize =  bufSize>MAX_RXBUFF ? MAX_RXBUFF : bufSize;  // limit bufsize
    int currReceivedBytes=0;
    int cyclesToRead=(int) bufSize/maxBufSize + 2;
    int cyclesReaded=0;
    Purge();
    while(cyclesReaded<cyclesToRead){
        Sleep(1);  
        cyclesReaded++;
        // prevent to big bufsize on the end of the buffer
        maxBufSize = ((bufSize - currReceivedBytes)> maxBufSize)? maxBufSize : bufSize- currReceivedBytes;
        ftStatus = FT_Read(ftHandle,pRxBufCur,maxBufSize,&bytesReceived);
        if(bytesReceived<maxBufSize)
            break;
        currReceivedBytes += bytesReceived;       
        pRxBufCur += maxBufSize;        // set pointer further in buffer
        if(currReceivedBytes >= bufSize){
            break;
            }                
        }
    if(currReceivedBytes<bufSize && ftStatus== FT_OK)
        {
        std::cout<< "Reading failed due timeout: Received"<<std::endl;
        }
    else if (ftStatus != FT_OK)  
        {
        std::cout<<"Reading failed"<<std::endl;    
        PrintError(ftStatus);
        }
    else
        {
        std::cout<<"Reading successfully: "<<currReceivedBytes<<" received." <<std::endl;
        isReadDone= true;
        }
    return isReadDone? true : false;
    }
void FT2232H::Purge()
    {
    FT_STATUS ftStatus;
    ftStatus=FT_Purge(ftHandle,FT_PURGE_RX);
    if(ftStatus!=FT_OK)
        {
            cout<<"READ BUF NOT PURGED"<<endl;
            PrintError(ftStatus);
        }        
    ftStatus=FT_Purge(ftHandle,FT_PURGE_TX);
    if(ftStatus!=FT_OK)
        {
        cout<<"READ BUF NOT PURGED"<<endl;
        PrintError(ftStatus);
        }
    }

The result of this read operation is :

(counter = 8 bit counter)

0,2,3,4,............127,128,130,131,132,....,255,0,2,3,4,5,......,127,128,130,.........,224,226,227,......,255,0,2,3,4,5,......,12,120,.....127,128,130,131,.......255,....................

=> missing one byte on 0->2 and 128->131 occurs on regular base

=> missing one or more than one byte like 120->120 and 224->226 occurs less frequent and irregular.

Does have some one the same experience with the Sync FT245 mode of the FTDI 2232H chip ?

Are there suggestions to solve this problem ?

Thanks in Advance

3 Replies

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

    Here are my notes for the FTDI devices;

    http://www.ovro.caltech.edu/~dwh/correlator/pdf/ftdi.pdf

    and I've attached a loopback example program. There's one comment in there that may be relevant to your problem ...

    
        /* Set flow control per AN130 - apparantly this stops the
         * driver from dropping data.
         */
        ftStatus = FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0, 0);
        if (ftStatus != FT_OK) {
            printf("Error: FT_SetFlowControl returned %d\n", (int)ftStatus);
            return 1;
        }
    

    Ah, but I see you already have that line in your code.

    So perhaps your issue is with the interface logic. Look at the waveforms in the PDF I linked to. Use SignalTap II in your design to reproduce them. Perhaps you have an issue. Do you have a testbench that you have used to test your design?

    Cheers,

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

    I found my problem.... I switched the input pins TXE and RXF of the FTDI in my FPGA program.

    I didn't noticed the problem directly because I also inverted the signals TXE and RXF.

    Below the working code of my FTDI controller :

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    entity FTDI_Controller is 
    port(    
        -- communication with software
        State_WR            : in std_logic;                            -- start writing         
        State_RD            : in std_logic;                            -- start reading
        State_DONE        : out std_logic;                            -- finished with reading or writing
        State_Accepted    : in std_logic;
        State_ReadyToRead : out std_logic;
        State_ReadyToWrite : out std_logic;                        -- when FTDI is ready to write 
        D_ToWrite        : in std_logic_vector(7 downto 0);    -- data to write 
        D_Readed            : out std_logic_vector(7 downto 0); -- data readed by interface
        -- Connection to hardware FTDI (FT245 COnfiguration)    
        FTDI_RXF_n            : in std_logic;        -- When low -> there is Data availible in the fifo
        FTDI_TXE_n            : in std_logic;        -- When low -> Data can be written into the fifo
        FTDI_RD_n            : out std_logic;        -- When low (and RXF_n low)-> Data is clocked to D0..D7 to receive 
        FTDI_WR_n            : out std_logic;        -- When low (and TXF_n low)-> Data is written to transmit FIFO
        FTDI_OE_n            : out std_logic;        -- Output enable -> Should be low one clock to drive data onto D0..D7    
        FTDI_Data            : inout std_logic_vector(7 downto 0);    -- Data vector
        
        -- Other Connections:
        CLK_FTDI        : in std_logic    ;    -- 60 MHz clock driven by FDTI
        Reset_n        : in std_logic ;            -- reset input    
        );
    end FTDI_Controller;
    architecture RTL of FTDI_Controller is
    -- Create state machine cases
    type T_STM_RD         is (rd_idle, do_OE, do_RD, read_data,read_done);
    type T_STM_WR         is (wr_idle, do_WR, burst_write, wr_pause, slow_wr);
    signal STM_RD            : T_STM_RD;
    signal STM_WR            : T_STM_WR;
    begin
    --# EXECUTE EACH CLOCK PULS    
    process(CLK_FTDI,reset_n)
    begin
    if(Reset_n = '0') then    
                    D_Readed <= (others => '0');
    elsif (rising_edge(CLK_FTDI)) then             
                
            if (State_RD = '1' )   then 
                --#  Start sequence of setting flags to read from the FTDI            
                    STM_WR <= wr_idle;
                    State_ReadyToWrite <='0';    
                    -- Evaluate the read STM.
                    case STM_RD is                        
                        --# # READ IDLE : initialize variables
                        when rd_idle =>
                            State_ReadyToRead <='0';
                            test_outC<='0';
                            FTDI_OE_n <= '1';
                            FTDI_RD_n <= '1';        
                            FTDI_Data <= (others => 'Z');
                            D_Readed <= (others => '0');
                            -- If FTDI pulls RXF low then data is available. We need to do OE next.
                            if(FTDI_RXF_n = '0') then
                                STM_RD <= do_OE;
                            end if;
                        --## OUTPUT ENABLE : enable to start reading     
                        when do_OE =>
                            -- Set output enable one clock pulse before reading command 
                            FTDI_OE_n <= '0';
                            STM_RD <= do_RD;
                        
                        --## READ FLAG : Pull RD_n low and go to read state 
                        when do_RD =>   
                            FTDI_RD_n <= '0';
                            State_ReadyToRead <='1';
                            STM_RD <= read_data;
                        
                        --## READING : read until FTDI stops
                        when read_data =>
                            -- Finish read operation ?
                            if(FTDI_RXF_n = '1') then                                                        
                                -- reset FT245 signals
                                FTDI_OE_n <= '1';
                                FTDI_RD_n <= '1';                                                    
                                STM_RD <= read_done;    
                                State_DONE<='1';
                            else
                                -- *** Here data is comming @ 60MHz ***
                                D_Readed <= FTDI_Data;    
                            end if;
                        when read_done =>
                            State_ReadyToRead <='0';
                            test_outC<='1';
                            if(State_Accepted='1') then
                                State_DONE <='0';    
                                STM_RD<= rd_idle;
                            else
                                State_DONE<='1';                        
                            end if;
                        when others =>
                    end case;                
            
                
                elsif (State_WR = '1' )   then     
                    STM_RD<= rd_idle;    
                --#  Start sequence of setting flags to write to the FTDI            
                    case STM_WR is                    
                        --## WRITE IDLE : prepare flags of FTDI and RAM
                        when wr_idle =>
                            FTDI_OE_n<='1';
                            FTDI_Data <= (others => 'Z');
                            --If FTDI_TXE_n is 0, then FTDI will allow data to be transmitted 
                            if(FTDI_TXE_n ='0') then
                                STM_WR <= do_WR;
                            end if;    
                            FTDI_WR_n <= '1';        
                        
                        --## WRITE START: start write command to FTDI
                        when do_WR =>
                            FTDI_WR_n <= '0';        -- Enables the data byte on the D0...D7 pins to be written into the transmit FIFO buffer
                            STM_WR <= burst_write;
                            
                        when burst_write =>
                            -- If FTDI_TXE_n is asserted, FTDI does not want data anymore, so we pause XMIT:
                            if(FTDI_TXE_n ='1') then 
                                STM_WR <= wr_pause;
                                FTDI_WR_n <= '1';    -- Disable write enable                                
                            else        
                                FTDI_Data <= D_ToWrite;                        
                            end if;            
                            
                        --# # PAUSE : FTDI chip needs a break...    
                        when wr_pause =>
                            State_ReadyToWrite <='0';        
                            if(FTDI_TXE_n ='0') then    
                                State_ReadyToWrite <='1';    
                                STM_WR <= burst_write;
                                FTDI_WR_n <= '0';    -- enable writing again
                                FTDI_Data <= (others => 'Z');
                            end if;
                        when others =>
                    end case;    
                
                    else
                        STM_WR <= wr_idle;
                        STM_RD <= rd_idle;
                        -- disable FTDI actions
                        FTDI_WR_n <= '1';    
                        FTDI_OE_n <= '1';
                        FTDI_RD_n <= '1';    
                        State_ReadyToWrite <='0';    
                        State_ReadyToRead <='0';
                        State_DONE <='0';    
                        D_Readed<=(others=>'0');
                    end if;            
        end if;            
    end process;    
    end RTL;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi, I am Bharat

    I am using FPGA (1-ADC 2314 2- FPGA (spartan-6) 3- FTDI 2232 4- LabVIEW), FTDI 2232 module and LabVIEW for my project.

    My first aim is to establish simple byte reading from my board (ADC)

    As you have made FTDI controller, I would like to have some inputs from your side. Please help for following queries.

    I read FTDI datasheet, what I understood is:

    --it might not be possible to transmit single byte transfer using FTDI 2232 module (minimum - 64 bytes). is it correct ?

    --if possible, pl. share your complete code. (might be asking too much then sorry )

    ---What is the purpose of C codes you are referring above ?

    thanks & best regards

    Bharat