Testing the FTDI USB Serial

General discussion about anything related to Ultibo.
User avatar
Ultibo
Site Admin
Posts: 2303
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Testing the FTDI USB Serial

Postby Ultibo » Fri Jul 19, 2019 10:14 am

Hi,

So as you've discovered there was a big update to the FTDI drivers a little while ago thanks to some excellent work by sbk58, you will need at least version 2.0.651 of the RTL in order to get good support for RTS/CTS with these devices.

Just a few other follow ups from your posts.

dieselnutjob wrote:With ultibo the flow control seems to be specified in the deviceopen. Is it possible to change flow control on the fly with an already open port?

Depending on your requirements simply closing and reopening the serial device (SerialDeviceClose, SerialDeviceOpen) with the new parameters might give you the result you need, doing that does clear the RX and TX buffers but if you are just doing an initial handshake to check for a device being present then that might be okay.

Of course there are potentially other options as well, you could enable flow control from the start and use the non blocking mode of the serial API to check for data being received within a specified timeout window.

Probably best to get some initial communications going first and then refine this part further based on that.

dieselnutjob wrote:I get $0000006 if my device is powered up and $00000004 if it is not.

The FTDISerial driver doesn't currently implement reading the status "on demand", what is returned is the status values that were provided with the last received data.

It possibly could be added to the driver if there was a need for it.

dieselnutjob wrote:in the log window I have idVendor=0403 and idProduct=6001

this doesn't seem to match these lines in ftdiserial.pas

Don't worry too much about the descriptions shown in ftdiserial.pas these come from the Linux driver and are pretty much just the first usage of each VID:PID pair. The text shown in the log is actually read from the USB device and should be correct (at least as far as the manufacturer got it right anyway). There are literally thousands of these FTDI devices floating around, as long as the actual VID:PID is listed in the source then consider it a supported device.
Ultibo.org | Make something amazing
https://ultibo.org
dieselnutjob
Posts: 18
Joined: Wed Jun 26, 2019 12:48 am

Re: Testing the FTDI USB Serial

Postby dieselnutjob » Fri Jul 19, 2019 10:42 am

ok thanks.
I think that there is something else going on here with the status.
With processor power off I get status of $0000004
With processor power off and RI shorted to GND I get status of $00004004
I need to figure out what's going on.
User avatar
Ultibo
Site Admin
Posts: 2303
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Testing the FTDI USB Serial

Postby Ultibo » Sat Jul 20, 2019 12:59 am

dieselnutjob wrote:I think that there is something else going on here with the status.
With processor power off I get status of $0000004
With processor power off and RI shorted to GND I get status of $00004004

I'm not sure I understand the significance of the RI (Ring Indicator) pin in this case, does your device require it to be used or is there something about the communications that needs it?

There is not a lot we can control about the communications from the FTDI device, the company don't supply any complete documentation and the Windows DLL is not open source so our only real reference is the Linux driver which we have followed for all the major elements of the communication.

Are you completely sure that the device requires RTS/CTS flow control and that all of the other parameters are exactly as required? Do you have a link to more detailed information about the device you are using?
Ultibo.org | Make something amazing
https://ultibo.org
dieselnutjob
Posts: 18
Joined: Wed Jun 26, 2019 12:48 am

Re: Testing the FTDI USB Serial

Postby dieselnutjob » Sat Jul 20, 2019 10:58 am

The "device" contains an FT232R chip which is powered from the USB cable, and an ATMEGA164P which is powered by a separate 5V power supply.

The FT232R is connected like this:-

VCC connected to USB socket 5V
VIO connected to USB socket 5V
3V3 connected to a capacitor to 0V and nothing else
USBDM connected to USB socket data line
USBDP connected to USB socket data line
RST# connected to a resistor divider giving USB socket 5V divided by two
TEST connected to 0V
CB0..CB4 not connected to anything
TXD connected to RXD on the ATMEGA164P
RXD connected to TXD on the ATMEGA164P
RTS# connected to CTS on the ATMEGA164P
CTS# connected to RTS on the ATMEGA164P
RI connected through a resistor to the ATMEGA164P 5V supply.

The significance of RI is simply this:-
If the user of the "device" has plugged the "device" into their laptop but forgotten to power up the "device" then the PC software can detect this condition by querying the "modem status" API.
This modem status API:-
Works in Windows using a Freepascal program which uses ftd2xx.dll
Works in Linux (i386 or AMD64 or Raspbian) using a Freepascal program which uses units serial, termio, baseunix
Doesn't work in OSX. The product works using a Freepascal program but the user doesn't get warned if they haven't powered it up. I never succeeded in querying modem status in MacOSX.

So for ftd2xx / Linux / OSX the significance of the RI is only that it is used as a way to detect the presence or absense of a 5V power supply for the ATMEGA processor. It has nothing to do with the serial communication.

Next, about the ATMEGA processor:-

The firmware inside the ATMEGA listens to the RTS# pin and the TX pin of the FT232R chip.
The firmware inside the ATMEGA transmits to the CTS# pin and the RX pin of the FT232R chip.
These four lines are the only connection between the ATMEGA and the FT232R (RX, TX, RTS# and CTS#).

When the ATMEGA is booted up it does this (to the best of my understanding):-
If the FT232R sets its RTS# output to 5V then the ATMEGA does nothing.
If the FT232R sets its RTS# output to 0V then the ATMEGA transmits a status packet continuously every 500ms

I wrote an ultibo program that simply loops around transmitting a reset packet sequence to the FT232R. The ATMEGA program should receive this and understand that it goes back to it's initial power up state. The ultibo program then listens for packets from the FT232R. It should see the status packets coming from the ATMEGA every 500ms.

what actually happens is that the ultibo program received one byte every 500ms until I switch off the ATMEGA. At the moment that the ATMEGA is switched off the ultibo program suddenly sees a bunch of status packets.

My enterpretation of this is that the ATMEGA is transmitting status packets and that for some reason the FT232R is internally buffering them.
When the ATMEGA is powered off the FT232R is still powered by USB and suddenly transmits everything in its buffer.

The question for me is why does the FT232R only send its buffer to the ultibo program when the ATMEGA is powered off? It must be something to do with either the CTS# line or the RI line on the FT232R, because there is nothing else that can change.

Finally, I understand that the ftd2xx.dll is closed source, but, there is a Linux freepascal version that uses only freepascal libraries, and that one works. If the ultibo FTDI library could be made to behave the same as the Linux FTDI driver with the Linux Freepascal code that would be perfect.

Maybe my next step is to write a very simple Linux freepascal program to test the "device" and then share that code in this thread? I have never written a "simple" Linux program for this device because I started with Windows and got that working first. By that time I ported it to Linux it was already a pretty big complex program but as it just worked I never tried anything simple.
dieselnutjob
Posts: 18
Joined: Wed Jun 26, 2019 12:48 am

Re: Testing the FTDI USB Serial

Postby dieselnutjob » Sat Jul 20, 2019 9:19 pm

slightly embarrassingly
it works now.
I'm not sure why (yet) that it didn't before

Code: Select all

program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  SysUtils,
  Serial;
  {$ENDIF}
  {$IFDEF ULTIBO}
  RaspberryPi,
  GlobalConfig,
  GlobalConst,
  GlobalTypes,
  Platform,
  Threads,
  SysUtils,
  Classes,
  Ultibo,
  Console,
  FTDISerial,
  Serial;
  {$ENDIF}

const
  BAUD_115200 = 115200;
  DATA_BITS_8 = 8;
  STOP_BITS_1 = 1;
  {$IFDEF UNIX}
  PARITY_NONE = NoneParity;
  {$ENDIF}
  {$IFDEF ULTIBO}
  PARITY_NONE = 0;
  {$ENDIF}


var
  {$IFDEF UNIX}
  ser: TSerialHandle;
  {$ENDIF}
  {$IFDEF ULTIBO}
  Ser: PSerialDevice;
  WindowHandle: TWindowHandle;
  {$ENDIF}
  buffer: shortstring;
  Count1: longword=0;
  Count2: longword;
  Timer: word;
  HexText: ansistring;


begin
  {$IFDEF UNIX}
  WriteLn ('Starting');
  {$ENDIF}
  {$IFDEF ULTIBO}
  WindowHandle:= ConsoleWindowCreate (ConsoleDeviceGetDefault, CONSOLE_POSITION_LEFT, true);
  ConsoleWindowWriteLn (WindowHandle, 'Starting');
  {$ENDIF}

  {$IFDEF UNIX}
  ser:=SerOpen('/dev/ttyUSB0');
  if ser>0 then
  begin
    SerSetParams(ser,BAUD_115200,DATA_BITS_8,PARITY_NONE,STOP_BITS_1,[RtsCtsFlowControl]);
    WriteLn ('Port opened');
  end
  else WriteLn ('Port not opened');
  {$ENDIF}
  {$IFDEF ULTIBO}
  ser:=nil;
  while ser=nil do
  begin
    Ser:=SerialDeviceFindByDescription ('FTDI USB to Serial');
    if ser=nil then sleep(200);
  end;
  if SerialDeviceOpen (Ser, BAUD_115200, DATA_BITS_8, STOP_BITS_1, PARITY_NONE, SERIAL_FLOW_RTS_CTS, 0, 0)
     = ERROR_SUCCESS then
     ConsoleWindowWriteLn (WindowHandle, 'Port opened')
     else
     begin
       Ser:=nil;
       ConsoleWindowWriteLn (WindowHandle, 'Port not opened');
     end;
  {$ENDIF}

  {$IFDEF UNIX}
  while ser>0 do
  {$ENDIF}
  {$IFDEF ULTIBO}
  while ser<>nil do
  {$ENDIF}
  begin
    buffer:=chr(6)+chr(5)+chr(4)+chr(3)+chr(2)+chr(1);
    Timer:=0;
    {$IFDEF UNIX}
    Count1:=SerWrite(ser,buffer,Length (buffer));
    WriteLn ('SerWrite:'+IntToStr(Count1));
    {$ENDIF}
    {$IFDEF ULTIBO}
    SerialDeviceWrite (Ser, @buffer[1],Length (buffer), SERIAL_WRITE_NONE, Count1);
    ConsoleWindowWriteLn (WindowHandle, 'SerWrite:'+IntToStr(Count1));
    {$ENDIF}
    setlength(buffer,255);
    repeat
      {$IFDEF UNIX}
      Count1:=SerRead(ser,buffer,255);
      {$ENDIF}
      {$IFDEF ULTIBO}
      SerialDeviceRead (Ser, @buffer[1], Length (buffer), SERIAL_READ_NON_BLOCK, Count1);
      {$ENDIF}
      if Count1=0 then
      begin
        sleep(1);
        inc(Timer);
      end;
    until (Count1>0) OR (Timer>1000);
    HexText:='';
    if Count1>0 then
    begin
      for Count2:=1 to Count1 do HexText:=HexText+IntToHex(ord(buffer[Count2]),2);
      {$IFDEF UNIX}
      WriteLn (HexText);
      {$ENDIF}
      {$IFDEF ULTIBO}
      ConsoleWindowWriteLn (WindowHandle, HexText);
      {$ENDIF}
    end;
    sleep(1000);
  end;
end.


User avatar
Ultibo
Site Admin
Posts: 2303
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Testing the FTDI USB Serial

Postby Ultibo » Sun Jul 21, 2019 11:28 pm

dieselnutjob wrote:it works now.

That's good, let us know if you need anything extra for handling the modem status or if we can help with anything else.
Ultibo.org | Make something amazing
https://ultibo.org

Return to “Discussion”

Who is online

Users browsing this forum: No registered users and 38 guests