WangXuan95 / FPGA-ftdi245fifo

FPGA-based USB fast data transmission using FT232H/FT600 chip. 使用FT232H/FT600芯片进行FPGA与电脑之间的高速数据传输。
https://gitee.com/wangxuan95/FPGA-ftdi245fifo
GNU General Public License v3.0
254 stars 78 forks source link

Problem with FT232H : 32bits TX (fpga--> PC) 16 upper bits with 16 lower bits switched sometimes after a cold start #9

Open collins4you opened 2 years ago

collins4you commented 2 years ago

Hi, I copy-past the verilog code inside my fpga. For info i use one UM232H board (FT232H chip) connected with one Digilent CMOD Board (fpga xilinx artix7). 8bits and 16bits transfer working very well from fpga to pc. For 32 bits i got a strange bug, sometimes (often) i got a switch between the 16 lower bits and the 16 upper bits. It means probably 16bits are lost after a cold start... I found a solution that is to release an hardware reset signal (added to the verilog code) just after started the python sample code. For exemple (python console) : WORKING (increment well) : recv 4 words 0: 0x0174_b082 1: 0x0174_b083 2: 0x0174_b084 3: 0x0174_b085

NOT WORKING (switch 16bits, increment the upper 16bits) : recv 4 words 0: 0xb0486_0178 1: 0xb0487_0178 2: 0xb0488_0178 3: 0xb0489_0178

This bug is quite strange coz the verilog code in 32bit transfer use two 32bits fifo and one 8bits fifo for the output (where are the 16bits words)

collins4you commented 2 years ago

64bits transfers same problem 16bits words switched : recv 32 B (error, incrément third 16bits word) 0: 0x0018_0e15_0000_0000 1: 0x0018_0e16_0000_0000 2: 0x0018_0e17_0000_0000 3: 0x0018_0e18_0000_0000

recv 32 B (increment ok) 0: 0x0000_0000_0021_ed83 1: 0x0000_0000_0021_ed84 2: 0x0000_0000_0021_ed85 3: 0x0000_0000_0021_ed86

collins4you commented 2 years ago

SOLVED !!! The problem (i checked signals on acbus) during reset and configuration in fifo mode of ft232h got some glitch on rxf# (acbus0) and it starts the check-counter and fill-in fifos in fpga and consequently starts randomly the tranfer... That's why you can miss some bytes and desynchronize your words of 16,32,64bits...

For people interested i found one solution to really control the start of your stream in fifo mode. For that I configue ACBUS9 of FT232H chip (UM232H Board) in CBUS Bit Bang Mode. It means i switched ACBUS9 in I/O MODE with FT_ProgUM232H_v3.12.14.633 software (FT232H EEPROM).By default/reset acbus9 start high in I/O mode, so low level will start my stream. And i discover it's possible to combinate SYNC 245 FIFO Mode (usb.setBitMode(0xff, 0x40)) with CBUS Bit Bang Mode (usb.setBitMode(0x??, 0x20)) : you have to use "mode" 0x60 (usb.setBitMode(0x??, 0x20)).

<1> I replace in fpga code : _assign usbtx_valid = 1'b1;_ by assign usbtx_valid = ~usb_acbus9; //by default acbus9 in I/O mode starts high And i add the port usb_acbus9 connected to acbus9 of ft232h (to do : synchronize this signal with fpga clock with a process) <2> I add in python code one way to up and down acbus9 to really decide to start the stream in fpga just before start the first usb data transfer (usb_rx) : in the USB_FT232H_sync245mode() class i added two method : def UpC9(self): self._usb.setBitMode(0x88,0x60) #lucky find configuration after try-check thanks app note an_232r-01 def DownC9(self): self._usb.setBitMode(0x80,0x60) # for acbus8 use 0x44 to up and 0x40 to down So in main code it's something like that : usb = USB_FT232H_sync245mode(b'UM232H') usb.DownC9() #really start the stream ___ for i in range(100): #launch read immediatly after and do what you have to do... ____ usb_rx(usb, 65536, 64,i) usb.UpC9() #at the end i stop the stream (by default/reset acbus9 starts high)
collins4you commented 2 years ago

And to conclude, thanks a lot to WangXuan!!!! A lot of time saved! good good job! If interested, i'm planning to integrate everything in xilinx IP to deal directly with axi-stream and axi register...

WangXuan95 commented 2 years ago

Thanks a lot for your sharing! I think your analysis is reasonable: TXE# is not stable during power-up and FPGA has already try to send by the time. (I guess you mean TXE# instead of RXF#, since TXE# determines whether FPGA->PC transfer is allowed). The reason I've never occured this issue is probably because the FPGA I've used powers-up slower than the FT232H.

I seem to understand your solution: by treating ACBUS9 as a GPIO that the PC can control, and then allow the FPGA to send data stream under control. I think your solution is indeed stable enough.

I'm thinking if there is a way to solve this without additional IO, because you know my repo is designed not only for FT232H but also other FTDI chips such as FT600, so I need to keep the generality. I may consider adding a startup logic inside ftdi_245fifo.sv: wait for TXE#=0 for a while before allowing the data in the FIFO to be sent to FT232H (so as to exclude the TXE#=0 glitch during startup). Since I don't have an FPGA board for testing recently, you might help me try this idea if possible, just simply add a counter to ftdi_245fifo.sv:

reg[31:0] counter = 0;

Add its reset on line 194:

    counter <= 0;

Modify lines 210~213 and add the logic of waiting for TXE#=0 to keep for 6000000 cycles (100ms, maybe longer):

    RESET2: begin
       {usb_oe, usb_rd, usb_wr} <= '1;
       if(counter<6000000) begin
          counter <= usb_txe ? 0 : counter+1;
       end else begin
          stat <= RXIDLE;
       end
    end

If it works, I welcome you to give a PULL REQUEST for this repo, so you can be a contributor.

Besides, I welcome you to integrate my repo as a xilinx IP. Any attribution use is welcome. Also, I look forward you to open source your version of AXI-stream and AXI-registers (if there's a major change compared to my repo, there is no need to cite me).

collins4you commented 2 years ago

Hi,

Is ok to share, i've already saved a lot of time thanks to you ;) I added this external control of stream to valid my "theory" about the cold start error. It was really important for me to be sure your code is working for me. Now, I can invest time to drop it inside an axi-lite (control register) & axi-stream module.

Bytheway, i'm planning to do two mode : a register r/w mode and a stream mode.

And like you suggest, i can add a delay-timer for the first transaction in stream mode or use a register dedicated to manage a cold start... For your solution i tried, but i got the same problem. Bytheway i don't think it's a good idea to change your main sequencer. Maybe add a sequencer for the "usb tx test" with something delay only the first transaction...

I'm planning to submit there what i'll do (if i success ;) )...

colin