Testing the FTDI USB Serial

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

Testing the FTDI USB Serial

Postby Ultibo » Tue Jul 12, 2016 5:55 am

The latest commit for Ultibo core (1.2.073) included a USB driver for the FTDI USB to Serial devices and as noted in the release announcement this driver has not been tested because we do not have a device available at present.

Since there are literally hundreds of devices around that use the FTDI chip (actually one of several chips that all should be supported) there is a good chance that one of you already has a device on hand.

If you have one of these, which could be a USB to Serial cable like this https://www.adafruit.com/product/70 or could be one of the earlier Arduino models that had the FTDI chip built on the board or could even be one of the many custom boards that have been produced using this chip, and you are willing to do some simple tests it would be great to hear your results.

The simplest way to test would be to create a new project based on Example 13 (Serial Connection) from https://github.com/ultibohub/Examples, include the FTDISerial unit and make sure USB support is also included (simply include RaspberryPi/RaspberryPi2/RaspberryPi3 depending on your board).

You will also need to substitute the SerialOpen(), SerialRead(), SerialWrite() functions used in the example with the advanced versions from the Serial unit (SerialDeviceOpen, SerialDeviceRead etc) so you can pass a specific serial device to work with. You can easily obtain a pointer to the FTDI device like this:

Code: Select all

var
 SerialDevice:PSerialDevice;
 
begin
 SerialDevice:=SerialDeviceFindByDescription('FTDI USB to Serial');
 
 //Use the returned SerialDevice in calls to SerialDeviceOpen(), SerialDeviceRead() etc

What you have available will affect what sort of testing you can do, if the other device is an Arduino then you could write a little program to echo serial data back. The driver currently has debug logging enabled which might be helpful in capturing some information if it doesn't work.

If you have any questions or need further ideas on how to get a test working with your device please post a follow up here.
Ultibo.org | Make something amazing
https://ultibo.org
pjde
Posts: 444
Joined: Tue Feb 09, 2016 6:21 am
Location: Sydney, Australia

Re: Testing the FTDI USB Serial

Postby pjde » Wed Jul 13, 2016 11:38 pm

I tried the following code :-

Code: Select all

program SerialConnection;

{$mode objfpc}{$H+}

{ Example 13 Serial Connection                                                 }
{                                                                              }
{ This example uses the serial (UART) device in the Raspberry Pi to connect    }
{ to another computer and echo back any line of text it receives.              }
{                                                                              }
{ You will need a serial cable or a USB to serial converter to connect the Pi  }
{ to your computer, the Pi uses pin 14 (Transmit) and pin 15 (Receive) as well }
{ as a Ground pin to make the connection. The documentation shows you where to }
{ find each of the pins on the Raspberry Pi.                                   }
{                                                                              }
{ Raspberry Pi Model A and B (26 pin header)                                   }
{   https://www.raspberrypi.org/documentation/usage/gpio/                      }
{                                                                              }
{ Raspberry Pi Models A+/B+/Zero/2B/3B (40 pin header)                         }
{   https://www.raspberrypi.org/documentation/usage/gpio-plus-and-raspi2/      }
{                                                                              }
{ You will also need a terminal program running on your computer, you can use  }
{ something like PuTTY to create a serial connection to the COM port you are   }
{ using. For this example we'll use these connection settings:                 }
{                                                                              }
{ Speed: 9600                                                                  }
{ Data Bits: 8                                                                 }
{ Stop Bits: 1                                                                 }
{ Parity: None                                                                 }
{ Flow Control: None                                                           }
{                                                                              }
{  To compile the example select Run, Compile (or Run, Build) from the menu.   }
{                                                                              }
{  Once compiled copy the kernel7.img file to an SD card along with the        }
{  firmware files and use it to boot your Raspberry Pi.                        }
{                                                                              }
{  Raspberry Pi 3B version                                                     }
{   What's the difference? See Project, Project Options, Config and Target.    }

{Declare some units used by this example.}
uses
  RaspberryPi3,
  GlobalConst,
  GlobalTypes,
  Platform,
  Threads,
  Console,
  Framebuffer,
  BCM2837,
  BCM2710,
  SysUtils,
  FTDISerial,
  Serial;   {Include the Serial unit so we can open, read and write to the device}

{We'll need a window handle plus a couple of others.}
var
 Count:LongWord;
 Character:Char;
 Characters:String;
 WindowHandle:TWindowHandle;
 SerialDevice : PSerialDevice;


begin
  {Create a console window at full size}
  WindowHandle := ConsoleWindowCreate (ConsoleDeviceGetDefault, CONSOLE_POSITION_FULL, true);

  {Output some welcome text on the console window}
  ConsoleWindowWriteLn (WindowHandle, 'Welcome to Example 13 Serial Connection - FTDI');
  ConsoleWindowWriteLn (WindowHandle, 'Connect the Raspberry Pi to your computer using a serial cable or USB to Serial converter');
  ConsoleWindowWriteLn (WindowHandle, 'Open a terminal program like PuTTY on your computer and connect to the appropriate COM port');

 {First we need to open the serial device and set the speed and other parameters.

  We can use the SerialOpen function in the Platform unit to open the default serial
  device or we can use the SerialDeviceOpen function in the Serial unit if we need
  to specify which device to open.

  We'll use SerialOpen and specify 9600 as the speed with 8 data bits, 1 stop bit,
  no parity and no flow control. The constants used here can be found in the GlobalConst
  unit.

  The last 2 parameters allow setting the size of the transmit and receive buffers,
  passing 0 means use the default size.}


  SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
  if SerialDevice = nil then
      ConsoleWindowWriteLn (WindowHandle, 'Serial device is nil');

           //        function SerialDeviceOpen(Serial:PSerialDevice;BaudRate,DataBits,StopBits,Parity,FlowControl,ReceiveDepth,TransmitDepth:LongWord):LongWord;

  if SerialDeviceOpen (SerialDevice, 9600, SERIAL_DATA_8BIT, SERIAL_STOP_1BIT, SERIAL_PARITY_NONE, SERIAL_FLOW_NONE, 0, 0) = ERROR_SUCCESS then
    begin

      {Opened successfully, display a message}
      ConsoleWindowWriteLn (WindowHandle,'Serial device opened, type some text in your terminal program and press Enter');

      {Setup our starting point}
      Count := 0;
      Characters := '';

      {Loop endlessly waiting for data}
      while True do
        begin
          {Read from the serial device using the SerialRead function, to be safe we
          would normally check the result of this function before using the value}
          SerialDeviceRead (SerialDevice, @Character, SizeOf (Character), SERIAL_READ_NON_BLOCK, Count);
          //function SerialDeviceRead(Serial:PSerialDevice;Buffer:Pointer;Size,Flags:LongWord;var Count:LongWord):LongWord;
          // function SerialDeviceWrite(Serial:PSerialDevice;Buffer:Pointer;Size,Flags:LongWord;var Count:LongWord):LongWord;
          {Check what character we received}
          if Character = #13 then
            begin
              {If we received a carriage return then write our characters to the console}
              ConsoleWindowWriteLn (WindowHandle, 'Received a line: ' + Characters);

              {Check for the word Quit}
              if Uppercase (Characters) = 'QUIT' then
                begin
                  {If received then say goodbye and exit our loop}
                  Characters:='Goodbye!' + Chr (13) + Chr (10);
                  SerialDeviceWrite (SerialDevice, PChar (Characters),Length (Characters), SERIAL_WRITE_NON_BLOCK, Count);

                  {Wait for the data to be sent}
                  Sleep (1000);

                  Break;
                end;

              {Add a carriage return and line feed}
              Characters := Characters + Chr (13) + Chr (10);

              {And echo them back to the serial device using SerialWrite}
              SerialDeviceWrite (SerialDevice, PChar (Characters), Length (Characters), SERIAL_WRITE_NON_BLOCK, Count);

              {Now clear the characters and wait for more}
              Characters:='';
            end
          else
            begin
              {Add the character to what we have already recevied}
              Characters := Characters + Character;
            end;

          {No need to sleep on each loop, SerialRead will wait until data is received}
          sleep (100);
        end;

      {Close the serial device using SerialClose}
      SerialClose;

      ConsoleWindowWriteLn (WindowHandle, 'Serial device closed');
    end
  else
    begin
      { Must have been an error, print a message on the console }
      ConsoleWindowWriteLn (WindowHandle, 'An error occurred opening the serial device');
    end;

  {Halt the thread if we exit the loop}
  ThreadHalt(0);
end.       



and I kept getting "Serial Device is nil" whether the serial unit was plugged in or not.
The serial dongle uses a FTDI driver on my Win7 machine so I presume its a genuine FTDI device.

Regards

Paul
pjde
Posts: 444
Joined: Tue Feb 09, 2016 6:21 am
Location: Sydney, Australia

Re: Testing the FTDI USB Serial

Postby pjde » Wed Jul 13, 2016 11:51 pm

Using the USB example, the dongle reports as Vendor ID 403 Product ID 6001

Don't know if this helps.
User avatar
Ultibo
Site Admin
Posts: 2280
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Testing the FTDI USB Serial

Postby Ultibo » Thu Jul 14, 2016 12:12 am

pjde wrote:Using the USB example, the dongle reports as Vendor ID 403 Product ID 6001

Yep, this one should be supported as a genuine FTDI 8U232AM chip.

If you have a small amount of time it could be pretty easy to debug this, since it isn't creating a serial device at all. If you modify your test like this:

Code: Select all

uses
  RaspberryPi3,
  GlobalConfig,   //Add the global config unit
  GlobalConst,
  ...
  SysUtils,
  Logging,      //Add the logging unit
  FTDISerial,
  Serial;
 
begin
  //{Create a console window at full size}
  //WindowHandle := ConsoleWindowCreate (ConsoleDeviceGetDefault, CONSOLE_POSITION_FULL, true);
 
  //Change the window to the left side only
  WindowHandle := ConsoleWindowCreate (ConsoleDeviceGetDefault, CONSOLE_POSITION_LEFT, true);
 
  //Register console logging
  CONSOLE_REGISTER_LOGGING:=True;
  LoggingConsoleDeviceAdd(ConsoleDeviceGetDefault);
  LoggingDeviceSetDefault(LoggingDeviceFindByType(LOGGING_TYPE_CONSOLE));
 
 
  ...
 
 

this will add console logging to the example (you could use serial logging or network logging if you prefer) and when inserting the FTDI device you should see a bunch of log messages, hopefully with one of them indicating the reason the driver doesn't want to bind to the device.

If there is anything interesting in those messages it could help to pinpoint the problem.
Ultibo.org | Make something amazing
https://ultibo.org
pjde
Posts: 444
Joined: Tue Feb 09, 2016 6:21 am
Location: Sydney, Australia

Re: Testing the FTDI USB Serial

Postby pjde » Thu Jul 14, 2016 1:24 am

There doesn't seem to be anything that seems wrong.

The device is shown as "FTDI Serial" and binds "FTDI USB to Serial Driver".

If you give a few instructions on how to extract the log it I will email to you.

P.S. I plugged a mouse in to scroll through the results which generates a error messages about a buffer overflow.

Regards

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

Re: Testing the FTDI USB Serial

Postby Ultibo » Thu Jul 14, 2016 2:19 am

pjde wrote:If you give a few instructions on how to extract the log it I will email to you.

Simplest way is probably to log it to disk by changing the code like this:

Code: Select all

  ...
 
  //Register console logging
  //CONSOLE_REGISTER_LOGGING:=True;
  //LoggingConsoleDeviceAdd(ConsoleDeviceGetDefault);
  //LoggingDeviceSetDefault(LoggingDeviceFindByType(LOGGING_TYPE_CONSOLE));
 
  //Register file logging
  FILESYS_REGISTER_LOGGING:=True;
  LoggingDeviceSetDefault(LoggingDeviceFindByType(LOGGING_TYPE_FILE));
  LoggingDeviceSetTarget(LoggingDeviceFindByType(LOGGING_TYPE_FILE),'C:\log.txt');
 
  ...

This should write the logging to a file on the SD card which you can copy and email. Just try plugging the FTDI device in and out a couple of times (with a few seconds wait in between) to make sure there is something in the log.

pjde wrote:I plugged a mouse in to scroll through the results which generates a error messages about a buffer overflow.

This is normal, if nothing is reading the mouse buffer it overflows very quickly. The console isn't smart enough to support mouse yet.
Ultibo.org | Make something amazing
https://ultibo.org
User avatar
Ultibo
Site Admin
Posts: 2280
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Testing the FTDI USB Serial

Postby Ultibo » Thu Jul 14, 2016 2:42 am

pjde wrote:The device is shown as "FTDI Serial" and binds "FTDI USB to Serial Driver".

Ok, looking at the log you sent it does seem to be binding correctly. Maybe there isn't quite enough time before the SerialDeviceFindByDescription() so you could try this:

Code: Select all


  SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
  while SerialDevice = nil do
   begin
    ConsoleWindowWriteLn (WindowHandle, 'Serial device is nil');
    Sleep(1000);
   
    SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
   end;
  ConsoleWindowWriteLn (WindowHandle, 'Serial device is available');   


just to allow some time for USB to startup and scan for devices etc.
Ultibo.org | Make something amazing
https://ultibo.org
pjde
Posts: 444
Joined: Tue Feb 09, 2016 6:21 am
Location: Sydney, Australia

Re: Testing the FTDI USB Serial

Postby pjde » Thu Jul 14, 2016 4:08 am

OK Success

It looks like it needs somewhere between 600-900 ms to stabilise. In the code below succeeds in opening on its third attempt.

I configured an AV controller I had sitting around to output a text string to the Pi every 5 seconds and it is receiving the correct response from the Pi.

I used non-block for reading and block for writing.

I had to disable the debug logging as it was generating messages too fast to read. I think it was due to the non block reading mode.

Code as used

Code: Select all

program SerialConnection;

{$mode objfpc}{$H+}

{ Example 13 Serial Connection                                                 }
{                                                                              }
{ This example uses the serial (UART) device in the Raspberry Pi to connect    }
{ to another computer and echo back any line of text it receives.              }
{                                                                              }
{ You will need a serial cable or a USB to serial converter to connect the Pi  }
{ to your computer, the Pi uses pin 14 (Transmit) and pin 15 (Receive) as well }
{ as a Ground pin to make the connection. The documentation shows you where to }
{ find each of the pins on the Raspberry Pi.                                   }
{                                                                              }
{ Raspberry Pi Model A and B (26 pin header)                                   }
{   https://www.raspberrypi.org/documentation/usage/gpio/                      }
{                                                                              }
{ Raspberry Pi Models A+/B+/Zero/2B/3B (40 pin header)                         }
{   https://www.raspberrypi.org/documentation/usage/gpio-plus-and-raspi2/      }
{                                                                              }
{ You will also need a terminal program running on your computer, you can use  }
{ something like PuTTY to create a serial connection to the COM port you are   }
{ using. For this example we'll use these connection settings:                 }
{                                                                              }
{ Speed: 9600                                                                  }
{ Data Bits: 8                                                                 }
{ Stop Bits: 1                                                                 }
{ Parity: None                                                                 }
{ Flow Control: None                                                           }
{                                                                              }
{  To compile the example select Run, Compile (or Run, Build) from the menu.   }
{                                                                              }
{  Once compiled copy the kernel7.img file to an SD card along with the        }
{  firmware files and use it to boot your Raspberry Pi.                        }
{                                                                              }
{  Raspberry Pi 3B version                                                     }
{   What's the difference? See Project, Project Options, Config and Target.    }

{Declare some units used by this example.}
uses
  RaspberryPi3,
  GlobalConfig,   //Add the global config unit
  GlobalConst,
  GlobalTypes,
  Platform,
  Threads,
  Console,
  Framebuffer,
  BCM2837,
  BCM2710,
  SysUtils,
  Logging,      //Add the logging unit
  FTDISerial,
  Serial;   {Include the Serial unit so we can open, read and write to the device}

{We'll need a window handle plus a couple of others.}
var
 Count : LongWord;
 Character : char;
 Characters : string;
 WindowHandle : TWindowHandle;
 SerialDevice : PSerialDevice;


begin
  //{Create a console window at full size}
  WindowHandle := ConsoleWindowCreate (ConsoleDeviceGetDefault, CONSOLE_POSITION_FULL, true);

  //Change the window to the left side only
//  WindowHandle := ConsoleWindowCreate (ConsoleDeviceGetDefault, CONSOLE_POSITION_LEFT, true);

//Register console logging
//  CONSOLE_REGISTER_LOGGING := True;
//  LoggingConsoleDeviceAdd (ConsoleDeviceGetDefault);
//  LoggingDeviceSetDefault (LoggingDeviceFindByType (LOGGING_TYPE_CONSOLE));

  {Output some welcome text on the console window}
  ConsoleWindowWriteLn (WindowHandle, 'Welcome to Example 13 Serial Connection - FTDI v2h');
  ConsoleWindowWriteLn (WindowHandle, 'Serial Responder');


 {First we need to open the serial device and set the speed and other parameters.

  We can use the SerialOpen function in the Platform unit to open the default serial
  device or we can use the SerialDeviceOpen function in the Serial unit if we need
  to specify which device to open.

  We'll use SerialOpen and specify 9600 as the speed with 8 data bits, 1 stop bit,
  no parity and no flow control. The constants used here can be found in the GlobalConst
  unit.

  The last 2 parameters allow setting the size of the transmit and receive buffers,
  passing 0 means use the default size.}


  SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
  if SerialDevice = nil then
    begin
      ConsoleWindowWriteLn (WindowHandle, 'Attempt 1 Serial device is nil');
      sleep (300);
      SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
      if SerialDevice = nil then
        begin
          ConsoleWindowWriteLn (WindowHandle, 'Attempt 2 Serial device is nil');
          sleep (300);
          SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
          if SerialDevice = nil then
            begin
              ConsoleWindowWriteLn (WindowHandle, 'Attempt 3 Serial device is nil');
              sleep (300);
              SerialDevice := SerialDeviceFindByDescription ('FTDI USB to Serial');
              if SerialDevice = nil then
                begin
                  ConsoleWindowWriteLn (WindowHandle, 'Attempt 4 Serial device is nil');
                end;

            end;
        end;
    end;


  if SerialDeviceOpen (SerialDevice, 9600, SERIAL_DATA_8BIT, SERIAL_STOP_1BIT, SERIAL_PARITY_NONE, SERIAL_FLOW_NONE, 0, 0) = ERROR_SUCCESS then
    begin
      {Opened successfully, display a message}
      ConsoleWindowWriteLn (WindowHandle,'Serial device opened, type some text in your terminal program and press Enter');
      {Setup our starting point}
      Count := 0;
      Characters := '';

      { Loop endlessly waiting for data }
      while true do
        begin
          SerialDeviceRead (SerialDevice, @Character, SizeOf (Character), SERIAL_READ_NON_BLOCK, Count);
          if Count > 0 then  // non blocking so count may be 0
            begin
              {Check what character we received}
              if Character = #13 then
                begin
                  {If we received a carriage return then write our characters to the console}
                  ConsoleWindowWriteLn (WindowHandle, 'Received a line: ' + Characters);
                  Characters := 'You said ' + Characters + Chr (13) + Chr (10);
                  SerialDeviceWrite (SerialDevice, PChar (Characters),Length (Characters), SERIAL_WRITE_NONE, Count);
                  Characters:='';
                end
              else
                begin
                  {Add the character to what we have already recevied}
                  Characters := Characters + Character;
                end;
            end;
          sleep (100);
        end;
    end
  else
    begin
      { Must have been an error, print a message on the console }
      ConsoleWindowWriteLn (WindowHandle, 'An error occurred opening the serial device');
    end;

  {Halt the thread if we exit the loop}
  ThreadHalt (0);
end.
 
pjde
Posts: 444
Joined: Tue Feb 09, 2016 6:21 am
Location: Sydney, Australia

Re: Testing the FTDI USB Serial

Postby pjde » Thu Jul 14, 2016 4:10 am

One question

What is the result from SerialDeviceRead when no characters was read (non block mode)?
User avatar
Ultibo
Site Admin
Posts: 2280
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Testing the FTDI USB Serial

Postby Ultibo » Thu Jul 14, 2016 4:22 am

Thanks Paul, that's an excellent result.

Still happy to hear results from anyone else who has a different variation of this device.

pjde wrote:What is the result from SerialDeviceRead when no characters was read (non block mode)?

It should return ERROR_NO_MORE_ITEMS (Decimal 259) if there is nothing to read (and the Count should be 0).

Thanks again,

Garry.
Ultibo.org | Make something amazing
https://ultibo.org

Return to “Discussion”

Who is online

Users browsing this forum: No registered users and 2 guests