eblot / pyftdi

FTDI device driver written in pure Python
Other
509 stars 211 forks source link

FT232R - port.write() only works at second call #213

Open mani9876 opened 4 years ago

mani9876 commented 4 years ago

Hello,

there seems to be one more problem with the FT232R and the pyftdi library.

I have this very simple test program:

#!/usr/bin/env python3

import pyftdi.serialext import time

port = pyftdi.serialext.serial_for_url('ftdi://ftdi:232:AR4SOIOR/1', baudrate=19200, timeout=10)

i=1

while 1: print(i) port.write(b'Hello World\r') time.sleep(1) i=i+1

However on the first call of port.write(..) I don't get any output on the Tx Port (measured with oscilloscope) All the other writes 2,3,4,... works fine.

But everytime I start my program, the first attempt to write to the UART failes.

At the moment I always make a dummy port.write(..) before the real ones, but I think that problem should be investigated.

Any ideas on how to do that?

Thanks and Best regards Manuel

mcprat commented 4 years ago

What if you run that script in debug mode, where each line of each iteration happens slowly?

or you can have 1 second sleep between iterations

Just curious if there is a difference, I am thinking it is a cache issue

mani9876 commented 4 years ago

Hello,

I have checked the problem again today, and it is even stranger than I thought. I changed my program to this:

#!/usr/bin/env python3

import pyftdi.serialext import time

port = pyftdi.serialext.serial_for_url('ftdi://ftdi:232:AR4SOIOR/1', baudrate=19

i=1

while i<=3: print(i) port.write(b'Hello World\r') time.sleep(1) i=i+1

So that I can vary how often the port.write(..) is executed.

And the behaviour is like that: good situation: .) I set the loop count to an even number (e.g. 4) .) I start my program several times -> everything is fine, every port.write(..) is written to the bus

bad situation: .) I set the loop count to an odd number (e.g. 3) .) I start my program several times -> the first port.write(..) of each start is NOT written to the bus, the 2nd and 3rd writes are written.

And it doesn't depend on the loop count of the program running at the moment, it depends on the loop count the program was running before.

That means: I start python and run port.write(..) 3 times. I close python I start python and run port.write(..) 2 times. -> first write failes.

Other situation: I start python and run port.write(..) 2 times. I close python I start python and run port.write(..) 3 times. -> everything is fine I close python I start python and run port.write(..) 2 times. _> first write failes.

If I only start python and execute port.write(..) one time, close python, start it with one write execution, and so on, nothing get's ever written to the bus.

@mpratt14: I've tested your suggestions, and started pdb and steped through the program with "next", but nothing changes. It doesn't seem to be a cache problem.

I hope you can understand how I've investigated that problem, so everytime I execute port.write(..) an odd number of times, restart python, the first write attempt failes.

Thanks Manuel

eblot commented 4 years ago

I never experienced such a problem, even with FT232R devices... So it is either a regression that has been added recently, or an issue with your setup.

I do lack time to work on PyFtdi at the moment. Do you have another FT232 device to check if you can reproduce this issue?

If you have used PyFtdi to program the EEPROM, it might be worth to reinitialise it with the official FT_PROG tool from FTDI, maybe there is a wrong setting somewhere, as EEPROM support is still experimental.

mani9876 commented 4 years ago

Hello,

I had an FT2232D laying around and I've tested this device.

Here are my results:

With device GL.iNet GL-MT300N-V2 running OpenWRT 19.07.3 -> both FT232R and FT2232D have the same problem as described above. With a Raspberry Pi 3 running OpenWRT 19.07.3 -> same result as with the GL.iNet -> FT232R and FT2232D have the mentioned problem With a Raspberry Pi 3 running the latest Raspberry Pi OS -> FT232R have this error, FT2232D not! (The CBUS error with FT232R is also the same with Raspos)

I've programmed both the FT232R and the FT2232D with the original FT_PROG tool. I also resetted the FT232R with the standard template, and it doesn't change a thing, the problem still persists.

I am going to set up an Ubuntu on an x86 machine, to test the FT232R an such a device also, and I will tell you the results.

EDIT: I made a test with Ubuntu 20.04 on my notebook. Both, the FT232R and the FT2232D don't show the problem as mentioned above. Every port.write(..) is sent to the bus. The CBUS error also persists on Ubuntu. So it must have something to do with OpenWRT and the CPU, right? Any ideas, on how to find that problem?

Thanks!

eblot commented 4 years ago

I'm not able to reproduce your issue with a FT232R (UM232R dev board).

I've slightly modified you code snippet as:

#!/usr/bin/env python3

import pyftdi.serialext
import time

port = pyftdi.serialext.serial_for_url('ftdi:///1', baudrate=19200, timeout=10)

i=1

while 1:
    print(i)
    port.write(b'Hello %d World\r' % i)
    time.sleep(.01)
    i=i+1
    # break

so that I can see the packets indices, and not a single one is missing. I also commented out the break instruction to emit a single packet, and every time I start this code snippet, it is received on the TXD pin of the FTDI.

I run it on macOS (Big Sur beta)

eblot commented 4 years ago

OpenWRT... ok, is pyusb working on this one?

I've been bitten years ago with another buildroot/uclibc environment: pyusb is using ctypes to communicate with the native libusb library.

For some reason (libc reason IIRC), some C structures did not have the same size as the one expected and defined by pyusb. The net result was a memory corruption and weird behaviour. I cannot tell if you're encountering the same issue, but this is definitely some point that needs to be checked.

You would need to check whether the structure in your pyusb backend match all the libusb structures that are defined in the libusb header file - as well as the actual options used to build the library do match (enum size for example).

ps: please try not to mix issues within a single ticket. This one is about the write() issue, CBUS issue should be reported in its own ticket.

mani9876 commented 4 years ago

Thank you for testing with your UM232R test board. So yes, it seems to be something OpenWRT or platform related (as on Raspos and Raspberry PI it's also not running with FT232R)

PyUSB installs fine, and I can't find any serious bug reporting regarding PyUSB and OpenWRT, also nothing about PyUSB and Raspberry PI with the Raspian/Raspos.

I've also tried again, using pyserial with the FT232R on OpenWRT, and this works fine, without any issues. But yes, this doesn't depend on the PyUSB, right?

You would need to check whether the structure in your pyusb backend match all the libusb structures that are defined in the libusb header file - as well as the actual options used to build the library do match (enum size for example).

Sorry but I am not very well experienced with Linux and compiling, but I think I need the source files of libusb-1.0-0 and the source of pyusb, to check what you've mentioned, right?

I also tried your code - if I uncomment the break statement, I don't get any data on the Bus, no matter how often I start the program.

Thank you!

phorn1 commented 3 years ago

I had the same issue. Sometimes the first write seemed to fail, even so all the following write calls worked fine.

I realised that unplugging and plugging in my ftdi usb adapter fixed this behavior. It was my mistake not to close the port properly, which caused the first write call to fail.

Opening the serial port in a with-statement takes care of the port closing.