USB-A Serial Communication

I'm working on a school project using the Arduino Giga R1 and I have multiple boards that need to communicate with the Giga, so RX and TX pins won't work. These external boards can write to a USB serial, so I was wondering if there was a way to read serial communication via the USB-A port rather than the USB-C port?

The inherent problem with an UART connection is that it's two terminals, only. I suppose theoretically you might be able to set up the USB1 on an STM32H7 as a USB host, connect several USB devices through a hub to it...however, the tricky bit will be to alternatingly start UART sessions with these slave devices. In the end, it would still boil down to the same challenge of running several UARTS directly to the microcontroller, just with the additional complication of USB on top of it.

So maybe it's hypothetically possible. I don't think it's worth the trouble, however, and there's a high chance of it not working at all, or being compromised inherently.

Why not run something that's intended as a proper bus, like CANBUS?

It is sort of hard to give any specific recommendations, without additional information, like how many devices, what level of communications are needed, etc.. But will throw out a few things, in case one of them might help.

For example, how many boards? The GIGA has 4 uarts: so you have Serial1-Serial4
Arduino GIGA R1 Cheat Sheet | Arduino Documentation

And yes, you can hook up USB Serial devices to the GIGA. For multiple devices as mentioned you would need a USB Hub.

If you look at the USB tutorial for the GIGA
Guide to Arduino GIGA USB Features | Arduino Documentation

You should download the library:
arduino-libraries/Arduino_USBHostMbed5 (github.com)
Either from github or the library manager.
I believe it has some rudimentary USB To Serial adapter support. Last time I looked it
only supported CDC ACM devices.

Note: I have my own slightly updated version of this library although looks like I have not synced it up to some of the most recent changes.
KurtE/Arduino_USBHostMbed5 at usb_host_fixes_lowspeed (github.com)
I have another branch there as well named WIP
I probably should look at both of them to remember what the changes are and sync back up...

Also I have my own library that uses the Arduino_USBHostMbed5 library to support or enhance several other USBHost devices:
KurtE/GIGA_USBHostMBed5_devices: Some USB Host device extension to Arduino_USBHostMBed5 library (github.com)
For example my USB to Serial adapter support, extends on the CDC ACM, plus it includes some support for FTDI and like devices.

Good luck

I am connecting two boards to it. An Arduino Uno R3 and a FTDI board that is connected to an esp32-cam board. I am simply printing something to serial from those boards and trying to read it from the Giga.

OK, can you comment on the feasibility of running several UART connections to individual devices over the same USB interface? I was wondering about that and couldn't think of a convenient/easy way to do this.

Oh, just use two hardware UARTs on the Giga, one for each of these two devices. Don't complicate things with USB; there's no need.

Well I’m also using the USB-A port to power these external boards

WARNING: Thinking back I am not sure if they are supporting multiple devices and hubs with the current code base. At the time, I believe we were testing some stuff in the fork/branch:
AndrewCapon/Arduino_USBHostMbed5 at USBHostMulti (github.com)
and ran into some serious low-level issues. And I think we all deferred until later.

But:
The easiest thing is to try it and see if it works. I have not done much with the GIGA for a while.
I mostly play on Teensy boards. So I don't remember how well their USBhost code handled multiple devices. The Teensy usb host support does. Although to do so you needed to add one or more HUB objects to your sketch.

Here is an example from my giga devices library, of a Serial object that everything that was sent to Serial was forwarded to USB Host Serial device and likewise from Host device to Serial...

//  Simple Echo USBHost Serial object with the main USB Serial object
#include <elapsedMillis.h>
//#include <LibPrintf.h>
#include <USBHostSerialDevice.h>
#include <GIGA_digitalWriteFast.h>
REDIRECT_STDOUT_TO(Serial)

USBHostSerialDevice hser(true);
int Fix_Serial_avalableForWrite = 0;
int Fix_hser_avalableForWrite = 0;

elapsedMillis emBlink;
uint32_t prev_serial_baud = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 5000) {}

  Serial.println("\nStarting USB host Serial device test...");

  // Enable the USBHost
  pinMode(PA_15, OUTPUT);
  digitalWrite(PA_15, HIGH);

  //hser.setDTR(false);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);
  pinMode(LED_RED, OUTPUT);

  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);

  wait_for_device_connection ();

  Fix_Serial_avalableForWrite = Serial.availableForWrite() ? 0 : 1;
  if (Fix_Serial_avalableForWrite) Serial.println("*** Serial does not support availableForWrite ***");
}

void wait_for_device_connection() {
  while (!hser.connect()) {
    Serial.println("No USB host Serial device connected");
    delay(5000);
  }

  printf("USB host Serial device(%x:%x) connected trying begin\n\r", hser.idVendor(), hser.idProduct());

  uint8_t string_buffer[80];
  if (hser.manufacturer(string_buffer, sizeof(string_buffer))) {
    Serial.print("Manufacturer: ");
    Serial.println((char*)string_buffer);
  }

  if (hser.product(string_buffer, sizeof(string_buffer))) {
    Serial.print("Product: ");
    Serial.println((char*)string_buffer);
  }
  if (hser.serialNumber(string_buffer, sizeof(string_buffer))) {
    Serial.print("Serial Number: ");
    Serial.println((char*)string_buffer);
  }

  prev_serial_baud = Serial.baud();
  printf("Baud: %lu\n\r", prev_serial_baud);
  hser.begin(prev_serial_baud);

  Fix_hser_avalableForWrite = hser.availableForWrite() ? 0 : 1;
  if (Fix_hser_avalableForWrite) Serial.println("*** USB Host Serial does not support availableForWrite ***");

}

uint8_t copy_buffer[64];

void loop() {
  int cbAvail;
  int cbAvailForWrite;

  if (!hser.connected()) {
    Serial.println("\n**** USB Serial Device was disconnected ***");
    // Not sure if needed or not, but
    hser.disconnect();
    wait_for_device_connection();
  }

  if (emBlink > 500) {
    emBlink = 0;
    digitalToggleFast(LED_GREEN);
  }

  if ((cbAvail = Serial.available())) {
    digitalToggleFast(LED_RED);
    cbAvailForWrite = max(hser.availableForWrite(), Fix_Serial_avalableForWrite);
    int cb = min(cbAvail, min(cbAvailForWrite, (int)sizeof(copy_buffer)));
    int cbRead = Serial.readBytes(copy_buffer, cb);
    //printf("S(%d)->HS(%d): %u %u\n\r", cbAvail, cbAvailForWrite, cb, cbRead);

    // Hack time, if first 3 characters are $$<0-3) try setting DTRRTS...
    if ((cbRead >= 3) && (copy_buffer[0] == '$') && (copy_buffer[1] == '$') &&
       (copy_buffer[2] >= '0') && (copy_buffer[2] <= '3')) {
        printf("Setting DTRRTS=%c\n\r", copy_buffer[2]);
        hser.setDTRRTS(copy_buffer[2] - '0');

       }
    else if (cbRead > 0) {
      hser.write(copy_buffer, cbRead);
    }
  }

  if ((cbAvail = hser.available())) {
    digitalToggleFast(LED_BLUE);
    cbAvailForWrite = max(Serial.availableForWrite(), Fix_Serial_avalableForWrite);
    int cb = min(cbAvail, min(cbAvailForWrite, (int)sizeof(copy_buffer)));
    //printf("HS(%d)->S(%d): %u\n\r", cbAvail, cbAvailForWrite, cb);
    int cbRead = hser.readBytes(copy_buffer, cb);
    if (cbRead > 0)  Serial.write(copy_buffer, cbRead);
  }

  // check to see if the user asked for the baud to change. 
  uint32_t current_baud = Serial.baud();
  if (current_baud != prev_serial_baud) {
    hser.end();
    prev_serial_baud = current_baud;
    printf("\n*** Baud rate changed to %lu ***\n\r", current_baud);
    hser.begin(current_baud);
  }
}

If you wish to support multiple USB Connections over Serial, you would have multiple of the USBHostSerialDevice objects.

And check for connections and if they have data available... in much the way you would do as if your devices were on Serial1 and Serial2.

1 Like

What libraries are you using in this code? I keep getting no such file or directory for the "#include"
files.

You need to add all these libraries to IDE

#include <elapsedMillis.h>
#include <USBHostSerialDevice.h>
#include <GIGA_digitalWriteFast.h>

Thanks,
elapsedMillis - is in library manager

USBHostSerilDevice is part of my github library: (Mentioned earlier in thread)
KurtE/GIGA_USBHostMBed5_devices: Some USB Host device extension to Arduino_USBHostMBed5 library (github.com)

I probably should remove the digitalWriteFast, here... could simply replace with
digitalWrite... Just is faster and I don't remember if I used the digitalToggleFast, which not have a straight replacement.

Sorry not exported very well:
UNOR4-stuff/libraries/GIGA_digitalWriteFast at main · KurtE/UNOR4-stuff (github.com)

Feel free to experiment, BUT realize very well that going down the path @KurtE hints at is likely one of the more complicated ways of trying to solve your problem. I take @KurtE's suggestion more as an academic exercise and not necessarily practical advice for your situation. I'd gladly stand corrected of course.

As I mentioned in the post. My guess is that Arduino does not currently (and may never) support multiple devices hooked up to their USB Host port. So not sure I am suggesting that....

As for what I would suggest... I don't know. It really depends on the exact needs.

You might be able to use Serail1, Serial2, ... Serail4, but it may or may not work for you. The
default implementations for Serial is to not buffer writes, That is if you do something like:

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  Serial2.begin(115200);
  Serial3.begin(115200);
  Serial4.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(250);
  Serial1.println("abcdefghijklmnopqrstuvwxyz");
  Serial2.println("abcdefghijklmnopqrstuvwxyz");
  Serial3.println("abcdefghijklmnopqrstuvwxyz");
  Serial4.println("abcdefghijklmnopqrstuvwxyz");
}

You will find out that the Serial objects are not buffered and your code sits in the Serial prints until the last character is output into the hardware buffer. As you can see if you look at the
logic analyzer output:

Note: this is true with the UNO R4 boards as well. But if you do the same on most other boards
the data is put into queues and all of the UARTS are outputting at the same time. For example I dragged out a real old MEGA 1280 and ran the same sketch minus Serial4

Sure enough:

Note: if I remember correctly, for some reason, Arduino decided to use the unbuffered Serial code within MBED for the hardware Serial objects. I believe one can use a buffered version of the code. I remember there was a thread where somone was able to use it.

Will it be fast enough? Maybe... Again, the best thing is to try it and see...

Good luck
Kurt

1 Like

Warning: If you try to connect up some of these boards to the GIGA. Be careful about the voltages you pass of the different boards. As the Giga is a 3.3v board and applying higher voltages to it's IO pins can be hazardous to the GIGA. As mentioned in several places including the Cheat Sheet
Arduino GIGA R1 Cheat Sheet | Arduino Documentation

I am guessing for example the Uno R3 is running at 5V. So you should use some form of level converter between the two boards.

As for the FTDI connected to esp32-cam board. Is the simply a USB To Serial adapter? If so maybe you can instead connect the esp32-cam board directly?

Certainly so!

Apologies; I did not intend to put words in your mouth.

That's interesting, and somewhat surprising as well. Although depending on the application, it may be tolerable. Thanks for pointing it out!

1 Like

Found the two spots on the forum that mention the buffered Serial class, including:

I have not tried it yet. Would be good if someone put up an example.

Hi, I tried your sketch, actually it's the only one that managed to work with a CP210X (I removed a lot from your sketch however but it worked).
I am now trying on a FTDI (FT232RL) but it prints "Unknown" when trying to identify the device. I tested it on my Windows computer using "usbipd list" in powershell and the VID/PID is excatly the same as the first one in the product_vendor_mapping_t of USBHostSerialDevice.cpp file (0x0403, 0x6001). Despite having a known PID/VID the script doesn't recognize it... any idea why ?

Here is the output of the GIGA_USBHost_Deviceinfo.ino script:

*** starting Device information sketch ***
Device:0x2400c714
VID: 103, PID: 0


Device Descriptor:
bcdUSB: 512
bDeviceClass: 0
bDeviceSubClass: 0
bDeviceProtocol: 0
bMaxPacketSize: 8
idVendor: 0x103
idProduct: 0x0
bcdDevice: 0
iManufacturer: 0
iProduct: 0
iSerialNumber: 0
bNumConfigurations: 0
Speed: 0


Size of configuration Descriptor: 32
Configuration Descriptor
2400E8D0 - 09 02 20 00 01 01 00 A0 FF 02 07 05 81 02 40 00 : .. ..... ......@.
2400E8E0 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ........ ........
Config:
wTotalLength: 32
bNumInterfaces: 1
bConfigurationValue: 1
iConfiguration: 0
bmAttributes: 160
bMaxPower: 255
Unknown: 2400E8D9 - 02 07 : ..
Unknown: 2400E8DB - 05 81 02 40 00 : ...@.

By the way if possible I would like to discuss with you in private as I saw you have done a lot for the GIGA board and the zephyr project. Two things I am currently learning to use and I am well placed to know knowledge is a precious thing in our domain...

Thanks for your help !!!

Update :

I managed to make it work by using the two links of this answer :

Quite a hard topic so sorry for this useless answer. Thanks @KurtE for this code even if this is still WIP !! :wink: