EmbeddedRelated.com
Forums

FTDI FTD2xx driver problem with DLP-2232PB device

Started by Kris February 8, 2006
Hello all!

I use the DLP-2332PB for development of the data acquisition device.
Using the internal A/D converters of the PIC I would like to sample the
incoming analog signal with the rate of 20MHz(per single channel)-1kHz.
The PIC-side code was written using CCS complier supplied with the
device. The host-side code written using C# 2.0 compiler and PInvoke
facilities.
Device driver is FTD2XX.
I use the following simple application for the communication test:

2332PB-side:

#include <16F877A.H>
#device ADC=10
#fuses HS,NOWDT,NOPUT,NOBROWNOUT,LVP,NOWRT,NOPROTECT
#use delay(clock=20000000)
#use FAST_IO(D)
#use FAST_IO(C)
#use FAST_IO(B)
#use FAST_IO(A)
#use FAST_IO(E)

#define WR        PIN_B2
#define RD        PIN_B1
#define SND       PIN_E1
#define TXE       PIN_E2
#define RXF       PIN_B4

#byte PORTD = 0x08

#inline
void write_byte(int data);

void main()
{
   long count=0;
   SET_TRIS_B(0x11);
   SET_TRIS_E(0x04);
   output_high(RD);

   while(TRUE)
   {
      SET_TRIS_D(0xff);
      while(input(RXF))
      ;
      SET_TRIS_D(0x00);
      while(!input(TXE) && count < 255)
      {
         write_byte(1);
         count++;
         write_byte(2);
         count++;
         write_byte(3);
         count++;
         write_byte(4);
         count++;
      }
   }
}

#inline
void write_byte(int data)
{
 PORTD = data;
   delay_us(1);
 output_low(WR);
   delay_us(1);
   output_high(WR);
}

The code is supposed to send 256 bytes of data with "1,2,3,4,1,2,3..."
pattern to PC after receiving anything from the PC side.
__________________________________
host side:

using System;
using System.Collections.Generic;
using System.Text;
using FTDIWrapper;
namespace tryPIC
{
class Program
{
static void Main(string[] args)
{
while(true)
{
while (!Wrapper.OpenDevice())
;
Wrapper.PurgeAll();
Wrapper.ReadData(Wrapper.CheckQueue());
Wrapper.WriteData(new byte[] { 0 });
System.Threading.Thread.Sleep(100);
byte[] data = Wrapper.ReadData(Wrapper.CheckQueue());
while(!Wrapper.CloseDevice())
;
Console.WriteLine("Data:");
for (int i = 0; i < data.Length; i++)
{
Console.WriteLine("byte #{0} is {1}", i, data[i]);
}
Console.WriteLine("Continue? (y/n)");
if(Console.ReadLine()!="y")
break;
}
}
}
}

And the "Wrapper" functions are calls to unmanaged code using DllImport
attributes. Functions' signatures are:

public static void WriteData(byte[] data);
public static byte[] ReadData(uint bytesToReceiveNum);
public static uint CheckQueue();
public static void PurgeAll();
public static bool OpenDevice();
public static bool CloseDevice();

This program sends "request" (any garbage) to the microcontroller,
waits approximately 100 milliseconds , then reads the contents of the
driver's buffer and prints it on the screen. This continues untill any
character other than "y" entered.

The following odd thing happens each and every time:
the first loop returns valid data, i.e., 256 values with "1,2,3,4..."
pattern;
the second returns "null" for the data;
during the third loop the program does not return from the call to the
FT_Write function at all.

Setting the timeout with FT_SetTimeouts to any value returns "IOError"
from the function at third call. And when I set the incoming data size
with FT_SetUSBParameters, the FT_Read returns "null" at first call.

Has anybody ever seen something similar? And how can I solve this?
Any advice will be appreciated.

Regards,
Kris.

In article <1139403181.718212.72010@f14g2000cwb.googlegroups.com>, 
kris.robin@gmail.com says...
> Hello all! > > I use the DLP-2332PB for development of the data acquisition device. > Using the internal A/D converters of the PIC I would like to sample the > incoming analog signal with the rate of 20MHz(per single channel)-1kHz. > The PIC-side code was written using CCS complier supplied with the > device. The host-side code written using C# 2.0 compiler and PInvoke > facilities. > Device driver is FTD2XX. > I use the following simple application for the communication test: > > 2332PB-side:
<<SNIP CODE>> Some things to try: 1. Open the device at the beginning of your host program and close it at the end. Don't open and close every time through the loop. The open and close operations may be interfering with the data flow at the PIC end, or may be doing a bunch of USB control transfers that are messing up the PIC or PC end. 2. Lose the threads stuff until you get it working in a non-threaded program. Mark Borgerson
First of all, thank you, Mark.
Second, simply to make it clear, the maximal sampling rate should be
20kHz, and not 20MHz, as I wrote before.

And now back to the main topic - I've tried the above in the following
way:
while (!Wrapper.OpenDevice())
               ;
            while (true)
            {
                Wrapper.SetTimeouts(100, 100);
                //Wrapper.SetUSBLatencyTimer(50);
                //Wrapper.SetUSBParams(256);
                Wrapper.PurgeAll();
                Wrapper.ReadData(Wrapper.CheckQueue());
                Wrapper.WriteData(new byte[] { 0 });
                for(short j=short.MaxValue; j>0; j--)
                ;
                byte[] data = Wrapper.ReadData(Wrapper.CheckQueue());

                Console.WriteLine("Data:");
                for (int i = 0; i < data.Length; i++)
                {
                    Console.WriteLine("byte #{0} is {1}", i, data[i]);
                }
                Console.Write("Continue? (y/n)  ");
                if (Console.ReadKey().KeyChar != 'y')
                    break;
            }
            while (!Wrapper.CloseDevice())
                ;

But the same thing happens. Moreover, closing the program after second
loop and then running it again, immediately returns "IOError" from the
first call to the FT_Write function.
Additional tests with loopback programs were successfull.
I've just thought about another possibility - could it be something
with the managed code? May be the old good native C/C++ is the way to
take care of this driver?

Regards,
Kris

Kris wrote:
> host side: > > using System; > using System.Collections.Generic; > using System.Text; > using FTDIWrapper;
What is that, C#? Where did you get FTDIWrapper? All I can tell you is that I've been using FTDI chips (FT245BM, mainly) for a couple of years now in embedded projects. But on the host side, we just use the D2XX driver from FTDI via Visual C++, and it works pretty much the way the documentation says it does. I would also echo the thought that opening/closing the device on every iteration is probably a bad idea. -- Dave Tweed
David Tweed wrote:
> Kris wrote: > > host side: > > > > using System; > > using System.Collections.Generic; > > using System.Text; > > using FTDIWrapper; > > What is that, C#? Where did you get FTDIWrapper? > > All I can tell you is that I've been using FTDI chips (FT245BM, mainly) > for a couple of years now in embedded projects. But on the host side, > we just use the D2XX driver from FTDI via Visual C++, and it works > pretty much the way the documentation says it does. > > I would also echo the thought that opening/closing the device on every > iteration is probably a bad idea. > > -- Dave Tweed
Hello, Dave. Yes, it's C#. FTDIWrapper is the namespace of my Wrapper class, that uses PInvoke for communication between managed code and unmanaged functions of the D2XX driver. These functions were tested before through a couple of loopback tests, and it was ok. Now, the "opening/closing" issue is addressed in the code snippet above. But, as I said before, this does not help - to leave the device open. Your experience with the FT245BM chips is very relevant in this case, I think, because the DLP-2232PB module is based on FT2232C - "double" FT245BM with some additions. May be you can tell me, transfer of what amounts of data and at what rate is involved in your applications. It could be the key to solution. Regards, Kris.
In article <1139496772.475156.255940@f14g2000cwb.googlegroups.com>, 
kris.robin@gmail.com says...
> David Tweed wrote: > > Kris wrote: > > > host side: > > > > > > using System; > > > using System.Collections.Generic; > > > using System.Text; > > > using FTDIWrapper; > > > > What is that, C#? Where did you get FTDIWrapper? > > > > All I can tell you is that I've been using FTDI chips (FT245BM, mainly) > > for a couple of years now in embedded projects. But on the host side, > > we just use the D2XX driver from FTDI via Visual C++, and it works > > pretty much the way the documentation says it does. > >
That's been my experience also. I haven't changed my host side software in several years.
> > I would also echo the thought that opening/closing the device on every > > iteration is probably a bad idea. > > > > -- Dave Tweed > > Hello, Dave. > Yes, it's C#. FTDIWrapper is the namespace of my Wrapper class, that > uses PInvoke for communication between managed code and unmanaged > functions of the D2XX driver. These functions were tested before > through a couple of loopback tests, and it was ok. > Now, the "opening/closing" issue is addressed in the code snippet > above. But, as I said before, this does not help - to leave the device > open. > Your experience with the FT245BM chips is very relevant in this case, I > think, because the DLP-2232PB module is based on FT2232C - "double" > FT245BM with some additions. > May be you can tell me, transfer of what amounts of data and at what > rate is involved in your applications. It could be the key to solution. > Regards, > Kris.
The source code for my windows host program uses the following to read a file transferred from the embedded system. The program is in Borland C++ builder. FTH is the handle for the FTDI FT245 device: void __fastcall TFormLink::BTXferClick(TObject *Sender) { char *fullstring, fnstring[15], cmdstring[16]; int i,spos; FILE *fp; static char spbuff[4098]; long bytecount; DWORD numwritten, num2read,numread; AnsiString str; char *fnp; if(FTH == 0) return; // exit if not open /// Snipped file opening code FT_Write(FTH,cmdstring, strlen(cmdstring), &numwritten); // //send the file name timeout = 50; // sets 5-second timeout to start file // at this point, the logger starts sending the file data while(timeout > 0){ fts = FT_GetQueueStatus(FTH, &num2read); if((fts == FT_OK) && (num2read > 0)){ FT_Read(FTH,&spbuff[0],num2read,&numread); if(numread > 0){ if(fp != NULL) fwrite(&spbuff[0], numread,1,fp); bytecount+= numread; EDCount->Text = bytecount; // show bytes sent timeout = 4; // reset timeout counter to 0.4 } } Application->ProcessMessages(); // check windows msgs } if(fp!= NULL) fclose(fp); } If you want any more help, you're going to have to show us what is going on inside your wrapper functions. You can find the logger-side source code at www.oes.to. Look for the USB-1 page. Mark Borgerson
Kris wrote:
> David Tweed wrote: >> Kris wrote: >>> host side: >>> >>> using System; >>> using System.Collections.Generic; >>> using System.Text; >>> using FTDIWrapper; >> What is that, C#? Where did you get FTDIWrapper? >> >> All I can tell you is that I've been using FTDI chips (FT245BM, mainly) >> for a couple of years now in embedded projects. But on the host side, >> we just use the D2XX driver from FTDI via Visual C++, and it works >> pretty much the way the documentation says it does. >> >> I would also echo the thought that opening/closing the device on every >> iteration is probably a bad idea. >> >> -- Dave Tweed > > Hello, Dave. > Yes, it's C#. FTDIWrapper is the namespace of my Wrapper class, that > uses PInvoke for communication between managed code and unmanaged > functions of the D2XX driver. These functions were tested before > through a couple of loopback tests, and it was ok. > Now, the "opening/closing" issue is addressed in the code snippet > above. But, as I said before, this does not help - to leave the device > open. > Your experience with the FT245BM chips is very relevant in this case, I > think, because the DLP-2232PB module is based on FT2232C - "double" > FT245BM with some additions. > May be you can tell me, transfer of what amounts of data and at what > rate is involved in your applications. It could be the key to solution. > Regards, > Kris. >
[Sorry for previous post, over hasty key press]

 >> What is that, C#? Where did you get FTDIWrapper?

[deletia]

 > Yes, it's C#. FTDIWrapper is the namespace of my Wrapper class, that
 > uses PInvoke for communication between managed code and unmanaged
 > functions of the D2XX driver. These functions were tested before
 > through a couple of loopback tests, and it was ok.

I've used the FTDI device with both C++ and C# without problems. It 
would be useful to see what some of your wrapper functions look like. 
The code that I wrote for C#, after finding and opening the device, 
wrote a command and read a result back (similar to yours but without the 
flush).

     Andrew

Kris wrote:
> Your experience with the FT245BM chips is very relevant in this case, I > think, because the DLP-2232PB module is based on FT2232C - "double" > FT245BM with some additions. > May be you can tell me, transfer of what amounts of data and at what > rate is involved in your applications. It could be the key to solution.
We have implemented a message protocol on top of the raw "byte stream" presented by the USB interface. Our primary traffic is a 38-byte message 200 times a second (about 8000 bytes/second) plus a few thousand bytes of other miscellaneous messages each second. It ends up being about 10K bytes/second on the average. Windows XP generally does a pretty good job of keeping up in real time, although we see occasional "hiccups" when it gets busy with something else. -- Dave Tweed
Mark Borgerson wrote:
> If you want any more help, you're going to have to show us what is > going on inside your wrapper functions.
Here are the functions from the Wrapper class: public class Wrapper { private static IntPtr m_USBhandler; [DllImport("FTD2XX.dll", EntryPoint="FT_Open")] public static extern uint FT_Open(int iDevice, ref IntPtr ftHandle); [DllImport("FTD2XX.dll", EntryPoint="FT_Close")] public static extern uint FT_Close(IntPtr ftHandle); [DllImport("FTD2XX.dll", EntryPoint="FT_Read")] public static extern uint FT_Read(IntPtr ftHandle, byte[] lpBuffer, uint dwBytesToRead, ref uint lpdwBytesReturned); [DllImport("FTD2XX.dll", EntryPoint="FT_Write")] public static extern uint FT_Write(IntPtr ftHandle, byte[] lpBuffer, uint dwBytesToWrite, ref uint lpdwBytesWritten); [DllImport("FTD2XX.dll", EntryPoint="FT_Purge")] public static extern uint FT_Purge(IntPtr ftHandle, uint dwMask); public static bool OpenDevice() { if (((FT_Status)Wrapper.FT_Open(1, ref m_USBhandler)) == FT_Status.Ok) { return true; } else { return false; } } public static bool CloseDevice() { if (((FT_Status)Wrapper.FT_Close(m_USBhandler)) == FT_Status.Ok) { return true; } else { return false; } } public static void PurgeAll() { FT_Status opResult; if ((opResult = (FT_Status)Wrapper.FT_Purge(m_USBhandler, (uint)FT_PurgeRXTX.TX & FT_PurgeRXTX.RX))) != FT_Status.Ok) { throw new USBException("Could not purge the buffers.", opResult); } } public static uint CheckQueue() { uint bytesToReceiveNum = 0; FT_Status opResult; if ((opResult = (FT_Status)Wrapper.FT_GetQueueStatus(m_USBhandler, ref bytesToReceiveNum)) != FT_Status.Ok) { throw new USBException("Could not check the USB device queue status.", opResult); } else { return bytesToReceiveNum; } } public static byte[] ReadData(uint bytesToReceiveNum) { uint readBytesNumber = 0; byte[] receivedBytes = new byte[bytesToReceiveNum]; FT_Status opResult; if ((opResult = (FT_Status)Wrapper.FT_Read(m_USBhandler, receivedBytes, bytesToReceiveNum, ref readBytesNumber)) != FT_Status.Ok) { throw new USBException("Could not read data from the USB device.", opResult); } else if (bytesToReceiveNum != readBytesNumber) { throw new USBException("Could not retreive the full data from the USB device.", FT_Status.OtherError); } else { return receivedBytes; } } public static void WriteData(byte[] data) { uint bytesToWriteNum = (uint)data.Length; uint writtenBytesNumber = 0; FT_Status opResult; if ((opResult = (FT_Status)Wrapper.FT_Write(m_USBhandler, data, bytesToWriteNum, ref writtenBytesNumber)) != FT_Status.Ok) { throw new USBException("Could not write the data into the USB device.", opResult); } else if (bytesToWriteNum != writtenBytesNumber) { throw new USBException("Could not write the full data into the USB device.", FT_Status.OtherError); } } } For me, it seems to be ok, but may be there is some problem. Kris