Go Down

Topic: USB serial communication with FTDI (Read 1 time) previous topic - next topic

Prieni

I'm still trying to get the communication with a FTDI245BL going. Here is what I'm trying to do:
The Arduino should send, via the USB Host Shield, an ASCII string, terminated with CR+LF, out to the device
(which is a line scan camera, not that this matters). The device is answering back with a copy of that string
(without the first character, which is the command identifier).

Arduino:BHello(CR+LF)
Device:Hello

This works when I plug in the device to the PC using the FTDI Windows drivers.

The code I'm using is derived from the USBFTDILoopback example sketch:
Code: [Select]

class FTDIAsync : public FTDIAsyncOper
{
public:
    virtual uint8_t OnInit(FTDI *pftdi);
};

uint8_t FTDIAsync::OnInit(FTDI *pftdi)
{
    uint8_t rcode = 0;
    
    rcode = pftdi->SetBaudRate(115200);

    if (rcode)
    {
        ErrorMessage<uint8_t>(PSTR("SetBaudRate"), rcode);
        return rcode;
    }
    rcode = pftdi->SetFlowControl(FTDI_SIO_DISABLE_FLOW_CTRL);
    
    if (rcode)
        ErrorMessage<uint8_t>(PSTR("SetFlowControl"), rcode);
            
    return rcode;
}

USB              Usb;
USBHub           Hub(&Usb);
FTDIAsync        FtdiAsync;
FTDI             Ftdi(&Usb, &FtdiAsync);

ADK adk(&Usb, "Arduino Demo Kit",  // Manufacturer Name
              "ArduinoSensor", // Model Name
              "Sketch to interface to USB PM Sensor", // Description (user-visible string)
              "1.0",             // Version
              "http://www.android.com", // URL (web page to visit if no installed apps support the accessory)
              "123456789");      // Serial Number (optional)


uint32_t next_time;

void setup()
{
  Serial.begin( 115200 );
  Serial.println("Start");

  // As it seems that initialization is a bit hit and miss
  // we loop here until it works out
  // until it does we print lines of .
  
  while (Usb.Init() == -1)
   {
    Serial.println(".");
    delay( 1000 );
   }
    Ftdi.SetFlowControl(FTDI_SIO_DISABLE_FLOW_CTRL);
    // Ftdi.SetBaudRate(57600);
  next_time = millis() + 5000;
}

void loop()
{ // JJ
  char *str;
  char *p;
  int  field,count;
  long PMValue;
  byte msg[5];
  uint16_t len;
  uint8_t rcode;
  count = 0;
    Usb.Task();
    if( Usb.getUsbTaskState() == USB_STATE_RUNNING )
    { // II
        char strbuf[] = "DEADBEEF123";
        //char strbuf[] = "The quick brown fox jumps over the lazy dog";
        //char strbuf[] = "This string contains 61 character to demonstrate FTDI buffers"; //add one symbol to it to see some garbage
        // Serial.print("."); // this is to show that it gets inside here, USB is running

        // let's try first if we get an echo
        strcpy(strbuf,"BH\a\0");
        Serial.print(strbuf);
        Serial.println(strlen(strbuf));
        rcode = Ftdi.SndData(strlen(strbuf), (uint8_t*)strbuf);
        if (rcode)
          {
           // throw error msg if rcode is not equal 0
           // gives back error message on serial monitor
           ErrorMessage<uint8_t>(PSTR("SndData"), rcode);
           Serial.print("y");
         }

        //delay(50);

        // make a buffer and clear it
        uint8_t  buf[64];
        for (uint8_t i=0; i<64; i++)
            buf[i] = 0;

        uint16_t rcvd = 7;
        // uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
        rcode = Ftdi.RcvData(&rcvd, buf);

        if (rcode && rcode != hrNAK)
         {
          ErrorMessage<uint8_t>(PSTR("Ret"), rcode);
          Serial.print("x");
         }
         else
         {
          Serial.print("!");
          Serial.print(rcvd,HEX);
         }

        Serial.print("Received data: ");
        Serial.print((char*)buf);
        Serial.println("\nEnd of received data");

        delay(10000);
    } //II   - USB State
    
} //JJ - loop


I have enabled debug output and get the following after start:
Code: [Select]

Start
flow control:00
FTDI Init
Addr:01
NC:01
0000: 09 02 20 00 01 01 00 80 32 09 04 00 00 02 FF FF
0010: FF 02 07 05 81 02 40 00 00 07 05 02 02 40 00 00
Conf.Val: 01
Iface Num: 00
Alt.Set: 00
Endpoint descriptor:
Length: 07
Type: 05
Address: 81
Attributes: 02
MaxPktSize: 0040
Poll Intrv: 00
Conf.Val: 01
Iface Num: 00
Alt.Set: 00
Endpoint descriptor:
Length: 07
Type: 05
Address: 02
Attributes: 02
MaxPktSize: 0040
Poll Intrv: 00
NumEP:03
Conf:01
baud_value:001A
baud_index:0000
flow control:00
FTDI configured
BHello
 8
!0Received data:
End of received data
BHello
 8
!0Received data:
End of received data


The first thing I wonder is,
1. how do I know what endpoint to address and
2. how do I control to which endpoint I'm sending (and try to receive from)?
As far as I can see Ftdi.SndData() does not have a parameter specifying the address,
so I guess there must be another function or parameter that I have to set.

Any pointers?

Robin2

#1
Jul 05, 2016, 03:12 pm Last Edit: Jul 05, 2016, 03:13 pm by Robin2
Please provide a link to your earlier Thread so we have all the info. Even better, ask the Moderator to merge this with the earlier Thread.

If the purpose of the FTDI device is to convert USB into parallel data I don't really see why you are using one with an Arduino when the Arduino can perfectly well create parallel data directly?

I have no idea whether your FTDI device can work with an Arduino USB host shield. I think the host shield has fairly limited competence, but I don't have one so I may be wrong.

An Arduino Yun has a "proper" USB host connection.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Prieni

Thanks for taking the time to answer. The earlier thread is here
http://forum.arduino.cc/index.php?topic=408154.0

I have started a new thread with a specific question in this other sub-forum (as I thought maybe the other one wasn't the right one for this type of question). I don't really see how the other thread is relevant for that question but now people can judge that for themselves.

Basically I have a device that I can control over the USB (virtual com port) with the PC and now want to do the same using the Arduino with USB host shield as the controller.

The device is bought in and I cannot modify it, thus I won't be able to get to the parallel signals. This device has all the electronics, RAM, clock, amplifiers etc. pp. to do the job and offers a simple control via simple ASCII commands. I need to get to a result quickly as I have a cruise coming up where I will need to get this working under water and there are many other issues to tackle (optics, pressure resistant housing, sensor chemistry to name a few). So while the FTDI chip on my device may be there to convert parallel data in serial ones, the device itself does a lot more.

The FTDI device should be able to work with the USB host shield from what I gather (but I'm not 100% certain, of course). It seems that the FTDI init works all right and the FTDI class holds some promise. The host shield may have limited competence but what I need to do seems fairly basic to me (i.e. give commands like "E2", "S" and "R10" to the device and read back 2048 comma separated integers on one of the commands).

It's the first time that I have to deal with USB on low level and I'm lacking knowledge of the inner workings of USB protocols. I tried to get some readable information but so far failed. I've also looked for some documentation on the USB host shield library but failed on that one as well. This is why I posted my question here and tried to be as specific as possible.

The Arduino Yun may well be better suited but I guess I would need to program the communication with my device in pretty much the same way and would end up at the same questions:

How do I control which endpoint I'm sending data to?

Answering that question may help me to get talking to my device (or, more likely, leads to the next questions, that hopefully could be as specific as this one).

It may be the case that I'm just not smart enough to scroll through the source of the library files and understand how it all works together. And maybe that is what it needs if I want to make any progress. I just thought that in this forum there were some clever people who may have been before where I am now and were able to help.
I would gladly take pointers to some documentation of the inner workings of USB communication in general and the USB host shield library in particular. I don't want anyone to do the work for me, I'm crying out for help to the community.

   

Robin2

Quote
How do I control which endpoint I'm sending data to?
Sorry but that means nothing to me so I can't help.

You should be easily able to do with the Linux side of a Yun what you can do with a PC.

Maybe what I really don't understand (even after a quick look at your other Thread) is why you want to use an Arduino at all?

What features of the Arduino do you want to use that would not be available on, for example, a RaspberryPi?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Prieni

Thanks for your answer, Robin.
I don't specifically need an Arduino, but I'm limited in the power budget (and time). I will operate that instrument over a DSL line where the power goes over a 600 m cable and power is needed for a suite of instruments, so our sensor will only be one and every mA counts. Another scenario is the use in a mooring where the instrument will be under water for three months and powered from rechargeable batteries, again a few mA can make a difference.
Size is another issue in the longer term (though not as important now).
We also bought a Raspberry but I decided to go with the Arduino thinking the large community should be able to point me to solutions quickly. I didn't know about the state of documentation for it and the shields. No idea if that is any better in the Raspberry world.
However, I think my current problem is more in understanding the USB interface. And I would have that with a Raspberry as well.

Yesterday I came across a "USB in a nutshell" article here
http://www.beyondlogic.org/usbnutshell/usb1.shtml

Haven't looked through it, yet, but it certainly is a much easier read than the USB specs.

Regarding my question: From the FTDI init information it seems to me that there are two endpoints that the USB host can see and I don't know which one I have to talk to. They have different addresses, so there must be a mechanism that allows me to choose which one to talk to. With that mechanism I could try both and perhaps that's all I need to get a step further. At least that's my hope.


Robin2

Sorry if I am keeping my nose in where it is not useful ...

If a Windows PC can figure out the FTDI stuff automatically I would also expect a RaspberryPi to do so. And FTDI my have specific advice and program snippets for using their device with Linux.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Prieni

No problem with your nose. :)
I appreciate the intention to help. And if, in that process, you happen to stick my nose close to the solution, then all the better.

I have to say that the Windows PC, as clever as it may be, does not figure out that FTDI stuff automatically. FTDI does provide drivers for Windows. In fact, to make these drivers work with my device's FTDI chip (said FT245BL) I had to modify the inf-file for the ftdiport driver (nothing fancy, just replacing the device ID) to make it work.

Power requirements:
A quick search came up with 200 mA @ 5V for the Raspberry Pi Model A (lowest of the list).

The figures for the Arduino Uno (in this forum: http://forum.arduino.cc/index.php?topic=264083.0 ) I found was between 20 mA and 80 mA. I guess I have to add the power for the USB host shield (that I wouldn't need on the Raspberry Pi) (difficult to judge - no documentation on that, even in the hardware manual I didn't find it https://www.circuitsathome.com/usb-host-shield-hardware-manual ) and the SD shield (another 20 mA))
So even in worst case the Arduino is still taking only half of what the Raspberry Pi takes.

On top of that I have to power the device itself (which tells in it's USB information a max current of 100 mA).

The slightly longer boot time of the Raspberry Pi after power on shouldn't be a problem in my use scenarios. I either power up before the measurement starts (from the ship) or I have to wait for the data logger and other instruments to power up anyway (and I have about a minute in reserve in that case).

A further quick read on the Raspi PI documentation of USB use (yes, there is proper documentation you can read!) https://www.raspberrypi.org/documentation/hardware/raspberrypi/usb/README.md
does ring my alarm bells. I may get stuck with that in the same way and at a higher power cost...
FTDI has drivers for Linux, I'm not sure, though, that they would run easily with the OTG host on the Raspberry Pi. 

Anyways, I haven't just twiddled my thumbs and with the help of that USB-in-a-NutShell guide I mentioned I was able to solve the endpoint problem (and could decode the information I get from my sketch in the FTDI init messages).
So apparently my device has three endpoints, endpoint 0, which is a control endpoint, endpoint 1 for input and endpoint 2 for output. From that I do infer that I don't need to address specific endpoints and am now fairly confident that it is handled by the library routines FTDI.SndData() and FTDI.RcvData()

Which, of course, doesn't leave an idea for ways forward... I've learned quite a bit, though, about USB in the process.

I would be glad if you keep nosing around ;) , seems you are the only one reading this and spending some thoughts... (which probably explains your good karma!)

Robin2

From Reply #2
Quote
The device is bought in and I cannot modify it, thus I won't be able to get to the parallel signals. This device has all the electronics, RAM, clock, amplifiers etc. pp. to do the job and offers a simple control via simple ASCII commands. I need to get to a result quickly as I have a cruise coming up where I will need to get this working under water and there are many other issues to tackle (optics, pressure resistant housing, sensor chemistry to name a few).
From Reply #4
Quote
I don't specifically need an Arduino, but I'm limited in the power budget (and time). I will operate that instrument over a DSL line where the power goes over a 600 m cable and power is needed for a suite of instruments, so our sensor will only be one and every mA counts. Another scenario is the use in a mooring where the instrument will be under water for three months and powered from rechargeable batteries, again a few mA can make a difference.
I have looked again at your earlier Thread and I confess I don't have a clear picture of what you are trying to attempt.

The initial idea in my mind was that you want to control a camera that requires ascii data that is normally sent over an FTDI cable from a control program on a PC.

But now there seems to be an energy budget and other sensors to complicate matters.

And you seem to be saying that the FTDI system required some hacking which leads me to wonder what the original system was?

Maybe you can provide diagrams showing the "traditional" working system and the new system that you want to implement. And also a description of how you want the system to work.

Is it possible to use sleep mode to reduce energy consumption (for the RPi or the Arduino)?

I get the feeling there is a strong element of XY Problem here.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Prieni

Ok, I try to recap the problem:

What we do in the lab:
As part of a sensor we are building we are using a 2048 element line camera as a detector. At the moment we have that instrument in the lab where the camera is connected to a laptop via USB cable. On this laptop, that runs a 32-bit Windows we can use the software and drivers that were provided with the camera (the drivers are the FTDI drivers, btw.).

What I do at the PC:
My desktop runs a 64-bit Windows and there are no FTDI drivers for the FTDI chip on the camera controller. That's why I had to modify the driver inf-file.
On the PC I treat the camera controller, that is connected to the PC as a virtual com-port. I can send the simple ASCII-commands (see below) with a terminal program (e.g. PuTTY) to the camera controller and get the data back from the camera controller via USB-cable.
On the PC I don't work with the actual sensor, I have just the camera and the controller connected to the PC (and the camera controller powered from the mains socket).

What we want to do out at sea:
Once the sensor is all housed up to be ready to go underwater there will not be a PC or laptop to control it. We will need to periodically (let's say about every second) ask the line camera to make a measurement and send the data, then write the data to a SD card together with the time of taking that measurement. This is the task that I have assigned to the Arduino with a data logger shield and a USB host shield.

The boundary conditions:
The energy constraints come into play as we either need to provide power under water from a battery (on longer deployments) or over a cable that already provides power for a multitude of other sensors and devices.

How I want the system to work:
Arduino sends to the camera (via USB):
i100
r1
e2
f,
(that is the setup sequence that only needs to be sent once)
It then goes into a loop and
every time it initiates a measurement it sends
s
and then waits for the answer
DONE
after which it sends
g
The camera then sends 2048 integer values with , separation to the Arduino.
The Arduino gets the current time from the RTC on the data logger shield, writes it to the SD card and then writes all the integer values it got from the camera to the SD card.

end of the loop

And that pretty much is what I want.

The situation I'm stuck at now:
I have the Arduino with USB host shield connected to the camera controller via USB cable from the host shield to the camera. I have my PC connected to the Arduino via USB to upload the program and read the diagnostics through the serial monitor.
The Arduino does identify the camera controller board when it is plugged in and does the initialisation.
I try sending the string "BHello" with CR+LF to the camera controller, which seems to be working (i.e. the function SndData() does not return an error and the number of transferred bytes seems right.
The command "BHello" with CR+LF, when send from the PC to the camera controller, does cause the camera controller to send back "Hello" to the PC.
I cannot see anything sent back when the camera controller is connected to the Arduino, the function RcvData() does return hrNAK, which it is supposed to do if there is nothing to receive. hrNAK, as far as I can make out, is something that actively is send from the camera controller.

I hope I made my problem clear and demonstrated, that I know what I want. Yes, the echo procedure BHello is not what I ultimately want but if I would be able to receive that echo I'm sure the next steps would be straight forward (not so sure about the 2048 counter values coming back - there could lurk the next problem).

Thanks for keeping up with me and my problem.

Robin2

Thanks. That makes things a lot clearer.

I can't recall, but I assume you are using a Mega if you need to gather 2048 bytes of data.

Am I correct to think the camera has a regular USB connection and its FTDI chip is inside the camera?

If that is wrong please provide details of the connection.

Assuming I am correct I think I am all out of ideas. I don't have any of your hardware.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Prieni

So far I'm using an Uno. Do you think it should be a Mega for the bigger chunks of data?
For now I would be happy receiving a handful of bytes.

Yes, the FTDI chip is inside the camera (or rather on the controller, controller and camera chip are on PCBs, no housing, yet) and camera controller and Arduino are connected by USB cable.

I agree, it's very difficult to get to the root of it without the hardware. It's also difficult to simulate the camera behaviour (which is simple enough to describe for the simpler commands) as you would need to simulate the exact behaviour of that specific FTDI chip.
However, I would think that since the camera seems to work, everyone who has done simple communication between the USB host shield and a device with an FTDI chip (they are rather common, I think) should have crossed the point where I stand at the moment.

Thanks again for your time and thoughts.

MirkoZhou

I have the exact same issue. Have you solved this ?

Robin2

@MirkoZhou, you have re-awakened a very old Thread

I suggest you start your own new Thread and describe your problem from the bottom up.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up