USB Host with a SAMD21: receiving and sending data issues

I am using an Arduino SAMD21 controller as an USB Host.

The library I found for this is the following: USB_Host_Library_SAMD.

Maybe there are other libraries that could work - do you know any ??

The USB counter part I would like to read and write to is a custom Controller from a 3rd-party company that normally connects via USB-FTDI COM port to a computer.

I would like to directly connect this 3rd-party Controller to my SAMD21 USB-Host.

By the below code example1, I achieved to read from the 3rd-party controller !!
I used the existing example for a PL2303 from the given USB_Host_Library_SAMD library. And this PL2303 example seemed to work best to interact with my 3rd-party Controller.

However, there are still two problems:

  1. about every 10th reading is only partially received (i.e. letters in receiving-string are missing)
  2. I cannot send yet (I can only receive)

As for the first problem: erroneous readings:
Some readings are cut-off parts of the receiving string. Most receiving-communication works. There is just about every 10th cmd from the 3rd-party controller that is only partially transmitted (i.e. partially received). I tried to change the delay in the receiving routine as can be seen in example1 below. But without success.

Do you have any idea what I could do in order to get 100% successful data readings ?

Example1: Receiving data from the 3rd-party Controller to a SAMD21 USB-Host:

#include <usbhub.h>
#include <cdcacm.h>
#include <cdcprolific.h>

class PLAsyncOper : public CDCAsyncOper {
    public:
        uint8_t OnInit(ACM *pacm);
};

uint8_t PLAsyncOper::OnInit(ACM *pacm) {
    
    uint8_t rcode;

    // Set DTR = 1
    rcode = pacm->SetControlLineState(1);

    if (rcode) {
        ErrorMessage<uint8_t>(PSTR("SetControlLineState"), rcode);
        return rcode;
    }

    LINE_CODING	lc;
    lc.dwDTERate = 115200;
    lc.bCharFormat	= 0;
    lc.bParityType	= 0;
    lc.bDataBits	= 8;

    rcode = pacm->SetLineCoding(&lc);

    if (rcode) {
        ErrorMessage<uint8_t>(PSTR("SetLineCoding"), rcode);
    }

    return rcode;
}

USBHost         UsbH;
PLAsyncOper     AsyncOper;
PL2303          Pl(&UsbH, &AsyncOper);

void setup() {
    
  Serial1.begin(115200); // receiving from 3rd-party controller and sending to Serial1
  delay(2000);

  if (UsbH.Init()) {
      Serial1.println("USB host did not start");
  }

  delay( 200 );
}

void loop() {
    
    UsbH.Task();

    if( UsbH.getUsbTaskState() == USB_STATE_RUNNING ) {
        
        uint8_t rcode;
        
        uint8_t  buf[32];
        uint16_t rcvd = 32;
        rcode = Pl.RcvData(&rcvd, buf);
        if (rcvd) { // more than zero bytes received
            String receivedStr = "";
            for (uint16_t i=0; i < rcvd; i++ ) {
                receivedStr += (char)buf[i];
                delay(3);
                // delay(5);       // ...other delays did not have an effect, unfortunately
                // delay(10);    // ... but without any delay, every cmd is only received partailly. So I think there must be a delay even tough it makes the entire reading slower....
                // delay(20);
                // delay(100);
            }
            Serial1.write(receivedStr.c_str());
        }
    }
}

Also, I tried to write to the 3rd-party Controller - but this did not work at all. See code-example 2

Example2: Sending data to the 3rd-party Controller from a SAMD21 USB-Host:

#include <usbhub.h>
#include <cdcacm.h>
#include <cdcprolific.h>

class PLAsyncOper : public CDCAsyncOper {
    public:
        uint8_t OnInit(ACM *pacm);
};

uint8_t PLAsyncOper::OnInit(ACM *pacm) {
    
    uint8_t rcode;

    // Set DTR = 1
    rcode = pacm->SetControlLineState(1);

    if (rcode) {
        ErrorMessage<uint8_t>(PSTR("SetControlLineState"), rcode);
        return rcode;
    }

    LINE_CODING	lc;
    lc.dwDTERate = 115200;
    lc.bCharFormat	= 0;
    lc.bParityType	= 0;
    lc.bDataBits	= 8;

    rcode = pacm->SetLineCoding(&lc);

    if (rcode) {
        ErrorMessage<uint8_t>(PSTR("SetLineCoding"), rcode);
    }

    return rcode;
}

USBHost         UsbH;
PLAsyncOper     AsyncOper;
PL2303          Pl(&UsbH, &AsyncOper);

void setup() {
    
  Serial1.begin(115200); // receiving from 3rd-party controller and sending to Serial1
  delay(2000);

  if (UsbH.Init()) {
      Serial1.println("USB host did not start");
  }

  delay( 200 );
}

void loop() {
    
    UsbH.Task();

    if( UsbH.getUsbTaskState() == USB_STATE_RUNNING ) {
        
        uint8_t rcode;
        
        // sending to the 3rd-party controller
        if (Serial1.available()) {                    
            uint8_t data= Serial1.read();
            rcode = Pl.SndData(1, &data);
        }
    }
}

There was no data transmission at all. What could be improved ??

Questions:

  1. Are there other USB-Host libraries for the SAMD21 that might work better ? if yes, which ones ?
  2. What can I do to improve the data-receiving ? (i.e. how to get rid of missing receive-strings ?)
  3. What can I do to get data-sending working at all ?

Here is a complete printout of the 3rd-party USB chip that my 3rd-party Controller contains:

String Descriptors:
Manufacturer:           Prolific Technology Inc. 
Product:                USB-Serial Controller D

Device descriptor: 
Descriptor Length:      12
Descriptor type:        01
USB version:            0110
Device class:           00
Device Subclass:        00
Device Protocol:        00
Max.packet size:        40
Vendor  ID:             067B
Product ID:             2303
Revision ID:            0400
Mfg.string index:       01
Prod.string index:      02
Serial number index:    00
Number of conf.:        01

Configuration descriptor:
Total length:           0027
Num.intf:               01
Conf.value:             01
Conf.string:            00
Attr.:                  80
Max.pwr:                32

Interface descriptor:
Intf.number:            00
Alt.:                   00
Endpoints:              03
Intf. Class:            FF
Intf. Subclass:         00
Intf. Protocol:         00
Intf.string:            00

Endpoint descriptor:
Atr:oint address03      81
                  axpktsie              00
olin iteva:     0

ndpin dsrito:
npontaddes:02
             At.:               0
Polig ntrvl     000
Enpintdecrpor
Atr.t ddes:     0
Polig ntrvl:0   000
Adr1(.01)

Does this mean this kind of devices connected one after another?

Windows-Computer-USB-Port----USB-FTDI-COM-Port-device----3rd-Party-device?

If Yes the 3rd-Party-device uses a serial-interface
the things in common between such a serial-interface and a USB-interface end right after the word serial.

A native USB-device has nothing in common with a serial-device except that both do send / receive data serial.
All the rest is totally different.

receiving / sending data to a device that needs an USB-FTDI COM for connecting to a windows-computer that has only USB-ports,

is simply done by connecting the Tx/Rx-lines of this device to the Rx/Tx-IO-pins of any type of microcontroller.
Depending on the voltage-levels you might need a voltage-level-converter but nothing else

best regards Stefan

Here is a better explanation in how the devices are connected:

This is the original setup:
Windows-Computer-USB-Port<-------->3rd-Party-device
(i.e. the 3rd-party device is recognised as a COM-port on the computer)

My wish is:
Arduino SAMD21-USB-HOST<-------->3rd-Party-device

Again, the receive of cmds works! (except that about every 20th cmd is incomplete)

And the biggest need is to be able to send string-cmds to the 3rd-Party-device from the Arduiono-USB-Host.

Any ideas ?

Does your device have the USB-plug connected this way :

USB-Plug--------cable----------Device-housing
Like on a USB-cable-mouse


which means the cable goes into the housing?

You wrote that this device is recognised as a virtual comport (FTDI-Chip) from the computer.

This fact means that inside your device there is a super-normal-standard serial interface which could connect directly to any kind of microcontroller.

Do you see any chance to get to that pins inside your device where the FTDI-chip is connected to?

Without direct connection your arduino must act as the USB-host which means

inside your device with serial-COM-Port translate to USB (FTDI-Chip)---------USB-Host-----receive-serial-data

While a direct connection would be
device-serial-port---------serial-port-of-Arduino___________all done

best regards Stefan

The 3rd-party device, for sure, has an FTDI-Chip inside its housing. Otherwise it wouldn't be recognised by the PC as a COM-Port.

And I understand your idea to pinout-directly in front of the FTDI-chip from inside the housing. Unfortunately, this is not really an option since used >50 times and I do not want to tinker 50 times. This is not an option for our product. But rather have a reliable connection.

The USB_Host_Library_SAMD library is made for such applications. The problem is only that sending does not work.

And it most likely will need a deep dive into the USB-protocol of this library in order to solve my need.

I was hoping that somebody can understand from the 3-rd party USB-chip printout (see my original question above) what to do in the USB-Host library.

Is there other USB-Host libraries that might work for the USB-Chip at question?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.