Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Writing data to USB with FTDI chip/Writing too frequently causes error

Status
Not open for further replies.

pigtwo

Member level 4
Joined
Jul 16, 2015
Messages
70
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
2,771
Hello all,

I'm working on a project where I need to send data from my computer to an FPGA. I'm using a FTDI chip(FT232RL-REEL) to convert USB to RS232. Sending data from my computer to the FPGA works fine but I'm having some problems with sending data from the FPGA through the FTDI chip to the computer. I can send one byte of data easily with no problems as long I don't send it very frequently. If I start sending data quickly it doesn't work and on my computer I get an error that says "A device attached to the system is not functioning.". The code that generated this error is shown below. I have to disconnect and reconnect the USB cable to get it back into an ok state. I'm thinking maybe there is some sort of control packet it or something I need to give the FTDI chip and maybe it just times out if I don't send the next packet soon enough.

Below is my Verilog for sending RS232 packets:

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
`timescale 1ns / 1ps
`default_nettype none
 
module RS232_SENDER(
 
    // Basic signals
    input wire clock_50,
    input wire reset,
    
    // Data and control signals
    input wire[7:0] data_in,
    input wire execute,
    output reg ready,
    
    // RS232 signals
    output reg rs232_tx
    
    );
    
    
    // Internal registers
    reg start_counter;
    reg[7:0] counter;
    reg[9:0] data_send;
    
    // Define sequential logic
    always @(posedge clock_50)  begin
        if(!reset) begin
            rs232_tx <= 1;
            ready <= 0;
            data_send <= 8'b11111111;
            counter <= 0;
            start_counter <= 0;
            
        end else begin
        
            if(!ready && !start_counter) begin  // This should handle the start up/reset condition
                ready <= 1;
            end
            
            if(ready && execute)    begin  // Detect execute signal(only when ready is high)
                ready <= 0;
                start_counter <= 1;
                data_send <= {1'b1, data_in, 1'b0};  // Read data and include start and stop bits
            end else if(counter == 156) begin // All data sent, go back to ready
                ready <= 1;
                start_counter <= 0;
            end
            
            if(start_counter) begin
                counter <= counter + 1;  // Count when ready not high
            end else begin
                counter <= 0;
            end
            
            // Write out data at approrate times
            if( counter == 1 || counter == 24 || counter == 40 || counter == 56 || counter == 72 || counter == 88 || counter == 104 || counter == 120 || counter == 136 || counter == 155) begin
                rs232_tx <= data_send[0];
                data_send <= {1'b0, data_send[9:1]};
            end else if(counter == 0) begin
                rs232_tx <= 1'b1;
            end else begin
                rs232_tx <= rs232_tx;
            end
            
        end
        
    end
    
endmodule



Here is the code that drives that module to send data quickly:

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
`timescale 1ns / 1ps
`default_nettype none
 
module RS232_SENDER_TEST(
    input wire clock_50,  
    input wire reset,
    
    output wire tx,
    output wire[1:0] testpoint,
    
    input wire rx
    );
    
    // Define internal signals
    wire ready;
    reg execute, execute_next;
    reg[7:0] data_in, data_in_next, state, state_next;  
    reg rx_sync;
    
    // Define local params
    localparam[7:0]
        start = 0,
        send = 1,
        delay = 2,
        done = 3;
 
    assign testpoint[0] = tx;
    assign testpoint[1] = rx_sync;
    
    // Create instance
    RS232_SENDER TX1(   
                            .clock_50(clock_50),
                            .reset(reset),
                            .data_in(data_in),
                            .execute(execute),
                            .ready(ready),
                            .rs232_tx(tx)
                            );
    
    // Define sequential logic
    always @(posedge clock_50)  begin
        if(!reset) begin
            execute <= 0;
            data_in <= 0;
            rx_sync <= 0;
            state <= start;
        end else    begin
            rx_sync <= rx;
            execute <= execute_next;
            data_in <= data_in_next;
            state <= state_next;
        end
    end
    
    // Define combination logic
    always@*    begin
    
        execute_next = execute;
        data_in_next = data_in;
        state_next = state;
        
        case(state)
        start: 
        begin
            execute_next = 0;
            data_in_next = 0;
            state_next = send;
        end
        
        send:
        begin
            if(ready) begin
                execute_next = 1;
                data_in_next = 121;
                state_next = delay;
            end
        end
        
        delay:
        begin
            if(!ready) begin
                execute_next = 0;
                state_next = start;
            end
        end
        
        done:
        begin
            state_next = done;
        end
        
        default: state_next = start;
        
        endcase
        
    
    end
    
endmodule



Here is the code that reads the data on the computer. I'm not a very good programmer and I don't almost anything about USB so this is just copied from the documentation:

Code Python - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import usb.core
import usb.util
import time
import random
 
# find our device
dev = usb.core.find(idVendor=0x0403, idProduct=0x6001)
 
# was it found?
if dev is None:
    raise ValueError('Device not found')
 
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
 
# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
 
ep = usb.util.find_descriptor(
    intf,
    # match the first OUT endpoint
    custom_match = \
    lambda e: \
        usb.util.endpoint_direction(e.bEndpointAddress) == \
        usb.util.ENDPOINT_OUT)
 
assert ep is not None
 
#ret = ep.read(1,2)
#print(ret)
ret = dev.read(0x81,8,1000)
print(ret)



Does anyone have experience with this and know what might be causing this? Any help or advice is greatly appreciated!

Thank you!
 

Perhaps a system driver issue.

What OS is the computer system running? What revision is the FTDI driver? What version of Python? What version of the USB API?

Have you verified the FTDI is genuine and not a counterfeit?

FTDI FT232RL: real vs fake

There have been several issues with FTDI drivers working with counterfeit FT232RL devices in the past.

BigDog
 

My OS is Windows 7 and the USB driver I'm using is libusb0 (v1.2.6.0). It was just the one that was recommend for python library that I was using.

I'm not sure if it's genuine or not. I was using the FTDI drivers and software to configure it and it didn't seem to complain. My chip is engraved like your link mentions but that doesn't definitely prove it.

I'm starting to think it might be the drivers because I'm now remembering issues where I couldn't even get the FTDI chip to connect correctly over USB and I would get this same error.
 

You might try setting up a traditional RS-232 link with a MAX232 and cable to a serial port on your system.

BigDog
 
  • Like
Reactions: pigtwo

    pigtwo

    Points: 2
    Helpful Answer Positive Rating
That's a good idea. But I already have the boards built and everything else works and this was meant to just be a minor addition. So I'll probably just drop it. I don't have much of a desire to dig into the USB protocol. Thank you for the help!
 

A simple test that could eliminate or confirm the hardware problem assumption (either USB driver or FPGA code itself) could be made by doing a remote loopback link by connecting the TX and RX on the TTL side of FTDI, then making the PC application to send patterns and compare with the received. I'm not familiar with Python, but in general, if the communication has already been established at least once but does not remain stable, I usually believe that the problem is software and only after discarding this possibility, consider the hardware as guilty.
 

Hi,

Driver....maybe.

But maybe it's a hardware problem.
Please show us your schematic and your PCB layout. (Please don't post the schematic from the datasheet).

Are you using hardware flow control at the FPGA?
What is your system clock frequency...and what are the "really" generated baud rates on the FPGA.

You may test 8N2 while sending out data from FPGA to PC....but leave 8N1 setup at the PC.

Btw. You talk about "RS232".. but RS232 uses -12/+12V instead of TTL levels. Please confirm that you don't use RS232 at all it is UART with TTL levels.

Klaus
 

@andre_teprom I'll double check and try to get a loopback test working. I'll update with the results.

@KlausST Attached is the schematic. The bottom of the first page is the FTDI chip and pins 85 and 87 on the FPGA are the TX and RX lines. The net names on those may be backwards but I have compensated for this in the UCF file for the FPGA. I've verified that the on the physical board the TX and RX lines are correct(or at least not swapped). I use OrCAD so I can include the .brd file if anyone wants but otherwise I attached a screenshot of the relevant region. Let me know if you need a better picture of the board.

I took a measurement on my scope and the baud rate appears to be 3.05Mbps.

You may test 8N2 while sending out data from FPGA to PC....but leave 8N1 setup at the PC.
Unfortunately with the python I don't really know what it's doing in regards to the USB configuration. I believe both 8N2 and 8N1(these are the reading and writing endpoints?) are set up. I will try a loop back test which should guarantee both are setup and operating.

You're correct, I'm not using RS232 and it is UART with TTL levels. Thank you for the correction, I didn't realize until now that that was the difference between the two.

While measuring the baud rate I noticed a problem with my code. I wasn't giving enough time to writing the stop bit. I corrected this but it didn't solve the problem. I also noticed some weird glitches where it would send out a packet that didn't look like what I told it to send. Or it would send two packets, one looked correct and the other looked different. But after a while I couldn't reproduce it. Below is my updated code for completeness.

Thank you!


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
`timescale 1ns / 1ps
`default_nettype none
 
module RS232_SENDER(
 
    // Basic signals
    input wire clock_50,
    input wire reset,
    
    // Data and control signals
    input wire[7:0] data_in,
    input wire execute,
    output reg ready,
    
    // RS232 signals
    output reg rs232_tx
    
    );
    
    
    // Internal registers
    reg start_counter;
    reg[7:0] counter;
    reg[9:0] data_send;
    
    // Define sequential logic
    always @(posedge clock_50)  begin
        if(!reset) begin
            rs232_tx <= 1;
            ready <= 0;
            data_send <= 8'b11111111;
            counter <= 0;
            start_counter <= 0;
            
        end else begin
        
            if(!ready && !start_counter) begin  // This should handle the start up/reset condition
                ready <= 1;
            end
            
            if(ready && execute)    begin  // Detect execute signal(only when ready is high)
                ready <= 0;
                start_counter <= 1;
                data_send <= {1'b1, data_in, 1'b0};  // Read data and include start and stop bits
            end else if(counter == 170) begin // All data sent, go back to ready
                ready <= 1;
                start_counter <= 0;
            end
            
            if(start_counter) begin
                counter <= counter + 1;  // Count when ready not high
            end else begin
                counter <= 0;
            end
            
            // Write out data at approrate times
            if( counter == 1 || counter == 24 || counter == 40 || counter == 56 || counter == 72 || counter == 88 || counter == 104 || counter == 120 || counter == 136 || counter == 152) begin
                rs232_tx <= data_send[0];
                data_send <= {1'b0, data_send[9:1]};
            end else if(counter == 0) begin
                rs232_tx <= 1'b1;
            end else begin
                rs232_tx <= rs232_tx;
            end
            
        end
        
    end
    
endmodule



- - - Updated - - -

Are you using hardware flow control at the FPGA?
No, currently neither reading nor writing to the FTDI chip uses flow control. Now that you mention it this might be my problem. Possibly the FTDI chip needs some amount of time after receiving a packet of data before it can receive another. But since I'm ignoring the flow control lines I violate this time and so the whole chip goes into an error state. I'll probe some more to see if this is the case.

I did a loopback test where I write 4 bytes from my computer to the FPGA and then the FPGA writes them back plus 10 and it worked perfectly.

- - - Updated - - -

I did a little probing of the handshaking signals but didn't find much. The output handshaking signals never changed. But to be honest I don't exactly know how these work so I may need to look into that more.

I've found that if I add a 20ms delay between sending bytes to the FTDI chip it will work. I can't imagine this is intended.
 

Attachments

  • neopixel_grid.pdf
    68.3 KB · Views: 136
  • FTDI_FGPA.PNG
    FTDI_FGPA.PNG
    113.6 KB · Views: 198

Hi,

I wasn't giving enough time to writing the stop bit.
Funny. Exactly this I had in mind as I requested to do "8N2 while sending out data from FPGA to PC".
Your error description does match to the "short STOP bit"

Handshaking is simple:
* there is one (input) line that permits / prohibts you to send data. This signal is bytewise, not bitwise.
* and there is an (output) to tell the same to your communication partner.
On the PC side you just need to anable hardware handshaking. All is done by the hardware, you don't need to write extra software.
On the FPGA side you just need to delay sending a byte as long as you are not allowed to send data.
Because the FPGA usually is continously ready to receive data...you just set the line to a fixed value.

Klaus
 

I did a little more testing with various amounts of stop bits but I haven't had any luck.

I was thinking that flow control is the problem. But I'm not so sure. I sent continuous data from my computer to the FTDI chip and I probed all the flow control pins but they were all static. I sent a bunch of data from the FPGA to the FTDI chip and probed the flow controls pins and again they were static. I would think when I send data from my computer to the FTDI chip the RTS line should go low and it shouldn't send the data until CTS goes low. But RTS never goes low and I receive the data perfectly. So I'm leaning on there being no flow control but I can't seem to verify this. I found out there are a few different types of flow control you can choose from with the FT232R but I cannot figure out how you actually set them. What worse is I can't even see what flow control my FT232R is using. The program that is supposed to be used to program the FT232R is FT Prog but it has no options for flow control(or baud rate which I find very odd).

I'm going to try to look through my code a little more and maybe read the FT232R data sheet very thoroughly. Maybe there is something very fundamental I missed.
 

Hi,

Flow control isn't set with FTprog.
It is set on the PC side by the user software. COM port setup. You set baudrate, you set 8N1...you may set flow control the same way.

// Write out data at approrate times
if( counter == 1 || counter == 24 || counter == 40 || co...
Why 1 - 24 - 40...? Why do you start with a delta of 23, and then use a delta of 16?

--> show us the simulation results or at least a scope picture where we can see your timing.

You didn't answer my baudrate question from post #7.
--> please answer it

Klaus
 

Flow control isn't set with FTprog.
It is set on the PC side by the user software. COM port setup. You set baudrate, you set 8N1...you may set flow control the same way.
The FTDI chip for me doesn't come up as a COM port in the device manager. I can find all those settings for a different COM port but the FTDI chip comes up as a different device. With FTDI's drivers installed it comes up as a USB serial converter and there is no options for it. See the attached picture. Maybe I'm looking in the wrong place or some different drivers have to be installed to see it as a COM port?
com_port_settings.PNG

Why 1 - 24 - 40...? Why do you start with a delta of 23, and then use a delta of 16?
Thank you for noticing that. That is a mistake. For some reason I thought the start bit was 1.5 bits long. I'm not sure why I was thinking this. I've corrected this and tuned the values a little better with my scope to try to fit the pattern the FTDI chip outputs. I've posted the updated code at the bottom for completeness's sake. Even with fixing this I still have the same problem.

You didn't answer my baudrate question from post #7.
--> please answer it
Sorry, I must have missed it somehow. The system clock is 50MHz. The desired baudrate is 3 Mbps. I'm measuring my output baud rate very close to 3 Mbps(roughly 3.05 Mbps).

Attached is the simulation output of my updated code(fixing the 1.5 bit width start bit) and a scope output comparing my FPGA output with a captured waveform of the FTDI chip's output. Again this is with the updated code.


Thank you again for the help!


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
`timescale 1ns / 1ps
`default_nettype none
 
module RS232_SENDER(
 
    // Basic signals
    input wire clock_50,
    input wire reset,
    
    // Data and control signals
    input wire[7:0] data_in,
    input wire execute,
    output reg ready,
    
    // RS232 signals
    output reg rs232_tx
    
    );
    
    
    // Internal registers
    reg start_counter;
    reg[31:0] counter;
    reg[9:0] data_send;
    
    // Define sequential logic
    always @(posedge clock_50)  begin
        if(!reset) begin
            rs232_tx <= 1;
            ready <= 0;
            data_send <= 8'b11111111;
            counter <= 0;
            start_counter <= 0;
            
        end else begin
        
            if(!ready && !start_counter) begin  // This should handle the start up/reset condition
                ready <= 1;
            end
            
            if(ready && execute)    begin  // Detect execute signal(only when ready is high)
                ready <= 0;
                start_counter <= 1;
                data_send <= {1'b1, data_in, 1'b0};  // Read data and include start and stop bits
            end else if(counter == 184) begin // All data sent, go back to ready
                rs232_tx <= 1'b1;
            end else if(counter == 250) begin
                ready <= 1;
                start_counter <= 0;
            end
            
            
            if(start_counter) begin
                counter <= counter + 1;  // Count when ready not high
            end else begin
                counter <= 0;
            end
            
            // Write out data at approrate times
            if( counter == 1 || counter == 17 || counter == 34 || counter == 52 || counter == 68 || counter == 84 || counter == 100 || counter == 118 || counter == 134 || counter == 150) begin
                rs232_tx <= data_send[0];
                data_send <= {1'b0, data_send[9:1]};
            end else if(counter == 0) begin
                rs232_tx <= 1'b1;
            end else begin
                rs232_tx <= rs232_tx;
            end
            
        end
        
    end
    
endmodule

 

Attachments

  • scope_output.png
    scope_output.png
    47.5 KB · Views: 199
  • simulation_output.PNG
    simulation_output.PNG
    19.2 KB · Views: 186

Hi,

I didn't say "device manager", I said "user software" --> your python program. Read libusb documentation how to do this.

You have an async serial communication, therefore timing is very important.
UART timing usually references to the first falling edge (start bit)
--> I recommend to do it as perfect as possible.
Currently you use delta: 16-17-18-16-16-18-16-16
Use excel and the rounding function to get optimal values. The math shouldn't be a problem for you.

Why that high 3MBaud? Do you really need it?
Usually: the higher the more critical

Klaus
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top