0
\$\begingroup\$

I want to read data from FT2232H used in an FT245 style synchronous FIFO mode (http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232H.pdf p.27) with DE0-Nano FPGA board:

process(clk)
begin    
    if (rising_edge(clk)) then
        next_state <= current_state;

        case current_state IS
            when POLL_UNTIL_RXF_LOW =>
                if (rxf = '0') then
                    current_oe <= '0';
                    next_state <= WAIT_SET_RD_LOW;
                else
                    current_oe <= '1';
                end if;
                current_rd <= '1';

            when WAIT_SET_RD_LOW =>
                current_oe <= '0';
                current_rd <= '1';
                next_state <= SET_RD_LOW;

            when SET_RD_LOW =>
                current_oe <= '0';
                current_rd <= '0';                    
                next_state <= READ_DATA;

            when READ_DATA =>        
                if (rxf = '0') then
                    current_oe <= '0';
                    current_rd <= '0';

                    -- access data here
                else
                    current_oe <= '1';
                    current_rd <= '1';                        
                    next_state <= POLL_UNTIL_RXF_LOW;
                end if;

            when others =>
                null;
        end case;
    end if;
end process;

rd <= current_rd;
oe <= current_oe;

siwu <= '1';
wr <= '0';

This code doesn't work well: about 51% of my data gets lost. I think, this is happening because clk in this code is 60 MHz clock provided by FT2232H; however, the DE0-Nano has an on-board 50 MHz oscillator connected directly to one of the FPGA clock pins. Is it possible to read 60 MHz data with 50 MHz clocked FPGA at all? How do you do it?

\$\endgroup\$
  • \$\begingroup\$ You can use a pll to generate 60 MHz clock for fpga or use a fifo working in two different time domains. \$\endgroup\$ – Qiu Sep 16 '14 at 16:26
  • 1
    \$\begingroup\$ There is no unit abbreviated as "mhz". 1/1000 of a Hz is 1 mHz. 1,000,000 Hz is 1 MHz. Please be clear which one you mean. \$\endgroup\$ – The Photon Sep 16 '14 at 16:28
  • \$\begingroup\$ @Qiu okay, I created 60 MHz PLL, what's next? \$\endgroup\$ – themylogin Sep 16 '14 at 17:02
  • \$\begingroup\$ There's nothing wrong with your state machine -- or at least what you've shown us of it -- other than the fact that you are wasting a clock between driving OE low and driving RD low. This just slows things down, but shouldn't cause you to lose data. But you really need to provide a lot more information, such as showing us your complete VHDL module, so that we don't have to guess at things like what the signals are used for, what mode the FT232H is in (synchronous FIFO mode?), and what exactly happens at -- access data here. \$\endgroup\$ – Dave Tweed Sep 16 '14 at 20:28
  • 1
    \$\begingroup\$ See, if you had started with that, it would have made this much more straightforward. The problem is that your state machine is implemented with two separate registered state variables, current_state and next_state, which are updated in two separate clocked processes. This means that it takes two clock cycles to do anything, and it effectively runs half as fast as you think it does. More importantly, it means that it drops every other byte coming out of the FT232H. \$\endgroup\$ – Dave Tweed Sep 17 '14 at 4:21
3
\$\begingroup\$

This should be possible with some careful design.

Firstly as @Qui says you should generate a synchronised clock signal inside your FPGA at 60 MHz to allow you to read the data.

  1. Create a PLL which locks to the clock signal provided from your FT2232 and outputs a 60 MHz clock at a phase of 0 (synchronised). The FT2232 clock must be connected to a clock-capable input pin (see the device pinout and DE0-Nano user manual to find the pins).
  2. Use this clock signal as the logic clock for all of the code which reads the data lines to and from the FT2232. This in clock domain A.
  3. Write some logic which looks at the locked pin of the PLL. This indicates that the PLL has synchronised successfully. You shouldn't try to communicate with the FT2232 before the PLL locks.

You can then read your data as you have been, hopefully more successfully!

You then have two choices when it comes to using the data, you can either use the 60 MHz PLL output for all the rest of your logic (simple) or move the received data across a clock-domain boundary and process it with logic clocked at you 50 MHz board clock. In the first case just go right ahead, but if you need to use the 50 MHz then read on.

If you need your signals to be used in the 50 MHz clock domain (clock domain B) then you must be very careful in crossing the clock domain boundary or the same problem will happen as you have already experienced (that is effectively what you are doing). In general you must

  1. Separate your logic so that you know exactly which parts of the design are in which clock domain.
  2. Define the signals which are going to cross from one section to the other (A to B and B to A). If you can, make the signals relatively low-rate (compared to either clock), for instance by transferring a whole word at a time rather than serially.
  3. Synchronise any signals crossing the boundary to the new clock domain. Synchronising is required to prevent metastability. Using a dual-port FIFO is probably the simplest and most reliable way. See this question and this one.
  4. Simulate each clock domain's logic separately with dummy inputs to make sure they work before trying them both together.
  5. Simulate the whole design to make sure it works in the simulator.
  6. Define your timing constraints carefully before synthesising the design, if you do this well the tools should catch problems with the clock boundaries.
  7. Synthesise and test. A good, high bandwidth oscilloscope (150 MHz+) will help a lot in debugging signals from test pins when it comes to looking at whether clocks and signals are synchronised correctly.

Unfortunately I can't help you much with the last part as I don't use Altera tools.

\$\endgroup\$
  • \$\begingroup\$ Don't double-register, use a FIFO. It's possible to make dual clock FIFOs out of the chip's block RAM. This will mean you can run data across a rate of 1 data word per slow clock. You may also be able to build a FIFO block with the GUI tools to save yourself the pain of building a dual clock FIFO yourself. If you can push most of the cross-clock-domain communication into the FIFO, it will make your life significantly simpler. \$\endgroup\$ – alex.forencich Sep 17 '14 at 3:40
  • \$\begingroup\$ @alex.forencich I am writing incoming data to one of two simple dual-port RAMs (actually, frame double buffer), could this fact be used to simplify my cross-clock-domain communication? I've used 98% on-chip RAM for this double buffer, there is no more left. \$\endgroup\$ – themylogin Sep 17 '14 at 4:22
  • \$\begingroup\$ Well, you might be able to do that if you can get the ports to run at different speeds. It's mainly a matter of which clock domain does it make sense to put the logic in and where it makes sense to connect the clock domains. If you can run all of the logic between that dual port RAM and the FT2232H in the same clock domain, then that could be the perfect solution. Also, if you do use a FIFO, it doesn't need to be huge - just enough to make up the difference in clock speeds. \$\endgroup\$ – alex.forencich Sep 17 '14 at 4:24
  • \$\begingroup\$ @Xcodo thank you very much for your detailed explanation of what's happening. The thing I don't understand is how do I drive FPGA with my PLL-generated 60 MHz clock: Cyclone IV E has only one clock pin and on my board it is directly connected to 50 MHz oscillator and, how I understand, clock signal can be only taken from this special pin; if not, how is PLL-generated clock different from clock taken from GPIO port? \$\endgroup\$ – themylogin Sep 17 '14 at 4:25
  • 1
    \$\begingroup\$ Exactly. You'll need to run the clock signal from the FT2232H into a clock-capable FPGA pin (there are a lot more than 1; consult the datasheet) and then the PLL and then the interface logic. If you can isolate all of the high-bandwidth communication between the buffer and the USB port in the 60 MHz clock domain, that would simplify the design significantly. \$\endgroup\$ – alex.forencich Sep 17 '14 at 4:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.