Arduino USB Host Shield services misbehave

INTRODUCTION: Hello there. I am working on a project that requires the connection of a USB device and communication through its virtual serial port. Unfortunately, it does not have a HW serial connection. I purchased a USB Host Shield (version 2) and implemented the USB Host Shield Library 2.0 (repo link). The protocol used is ACM. Original Arduino Mega is used under the shield. I am using code snippets from the official example on cdcacm communication.

PROBLEM: The USB connection is initialized properly when the Arduino is connected via the main USB port to my computer. In other words, there is an existing USB connection already. When I disconnect it and power it just from a voltage source, the connection isn't established.

ALREADY TRIED: I've checked the HW regarding power. The shield is properly set to 5 V, and the input voltage is 12 V. I am not using any pins used by the shield. In fact, I've stripped the project of everything except the shield. So now it is Arduino Mega + the shield and one connected USB device.

DETAILS: The USB device is a radio controller for LED light props. It takes simple commands in an ASCII manner. It is clearly visible on my lights when the commands are coming through or not. No acknowledgment or other synchronized communication processes are needed. I include the code snippets below.

SUMMARY: Everything works properly when connected to a PC; otherwise, it does not. I suspect incorrect library services that make various USB connections somehow dependent. I am not advanced enough to understand the communication interface services. Please help.

FT2remote.cpp

#include <FT2remote.h>

USB Usb;
ACMAsyncOper AsyncOper;
ACM Acm(&Usb, &AsyncOper);

FT2remote::FT2remote() {};

void FT2remote::begin() {
  if (Usb.Init() == -1)
    Serial.println("USB: OSCOKIRQ failed to assert");
}

void FT2remote::sendPacket(String packet) {
  Serial.println("FT2: Sending command: " + packet);
  
  Usb.Task();
  if (Acm.isReady()) {
    Serial.println("ACM ready.");
    //String str = "lprog 0x00000002,mMeCOcBL\n";       // test string
    String str = packet;
    char charArr[str.length()+1];
    str.toCharArray(charArr, str.length()+1);
    Acm.SndData(str.length(),(uint8_t*)charArr);
  }
}

FT2remote.h includes ACMAsyncOper.h

ACMAsyncOper.h

#include <Arduino.h>
#include <cdcacm.h>

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

ACMAsyncOper.cpp

#include <ACMAsyncOper.h>

uint8_t ACMAsyncOper::OnInit(ACM *pacm) {
    uint8_t rcode;
    // Set DTR = 1 RTS=1
    rcode = pacm->SetControlLineState(3);

    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;
}

main.cpp

FT2remote ft2;            // object servicing the FT2 remote controller

void setup() {
  Serial.begin(9600);
  ft2.begin();
  delay(200);

void loop() {
  ft2.setColor(true,1);   // this calls a lot of functions constructing the final string command and calling void FT2remote::sendPacket(String packet)
  delay(1000);
  ft2.setColor(true,2);
  delay(1000);

sounds like a GND or power issue

do you mean you power the MEGA from its Jack with a 12V power supply? How much current is available from that power supply ?

Grounds are properly connected between all the devices. Yes, the MEGA is powered by 12 V with plenty of headroom with the current. The power supply is 100 W. The stack drains about 150 mA.

what happens if you comment out the Serial.begin and all Serial.prints?
(should not matter but...)

I've already tried this one. However, I only omitted the serial initialization as there are a lot of prints in the enclosed library.

how is the radio controller powered ? from the USB connection ?

The radio remote controller has a built-in battery. It is being charged when connected by the USB. I've measured the port with an in-between meter, and it shows 22 mA and 4.73 V

OK I still suspect (guts feeling) a GND issue but not sure how to explore this

PROBLEM: The USB connection is initialized properly when the Arduino is connected via the main USB port to my computer. In other words, there is an existing USB connection already. When I disconnect it and power it just from a voltage source, the connection isn't established.

Try turning on UHS2 lib debug. This might help pinpoint where the failure occurs. The code is pretty complex so this may not help unless you are willing to invest time studying code. I doubt UHS2 cares about the power source but I am not sure what else to do.

I am sure it is not about the power supply but more about the established connection with the PC. The problem is that I am not sure how to debug when I need to omit the serial connection to the console.

On Mega, Serial is a UART port, not USB. The UART port is connected to an external chip that handles UART to USB. I do not see how this affects the USB host shield.

One possibilty is to connect a display and print debug message to the display. This removes the need for the connection to the PC.

If you hit a dead end, there are boards that can do USB Host using Arduino such as Teensy 4.1 and rp2040/Pi Pico. Rapsberry Pi boards also have USB host.

Yeah, I am aware of the interface architecture. I don't have a display on hand currently, but I should try it, I guess. I am using RasPi right now, but it's a tremendous waste of current since it drains a lot, and my device is mobile and works on batteries.

I have set logging through a plain serial port, and I get USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL error code from ACM::Init(...) in cdcacm.cpp
I have tried to investigate further into the library but with no luck so far. Can anyone give me some advice?

is it there or the call

leading to

More information from power supply testing:

  1. Powered only from 12V - NOT WORKING
  2. Powered through USB from 230V socket adapter - NOT WORKING
  3. Powered through 12V first, and then connected to USB - NOT WORKING even after restart; When the 12V is turned off, it starts working immediately.

It should not be unssuported class when there are cases when it's working properly.

OK.

You could modify the code est to find out exactly where the error code comes from. that might help you narrow down the issue.

Some random thoughts in no particular order.

  1. So this means the mega is still connected to a PC but using a different UART port and UART to USB converter?

I have set logging through a plain serial port, and I get
USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL error code from ACM::Init(...) in
cdcacm.cpp

  1. The posted code does not call Usb.Task() for long periods because the loop function call delay(1000) twice. The USH2 example acm_terminal calls Usb.Task() far more frequently and uses short delays. Does the acm_terminal sketch work? Does it still work if it is modifed to use the other UART mentioned in 1?

  2. I would first capture the debug output of the successful case to have a guide of how it works. Then compare the successful case log with a failure case log. The failure case might diverge from the success case before the error occurs.

  3. Serial.begin(115200) works better because slow baud rates like 9600 will slow down the entire program especially when printing lots of debug.

@CarryCZ

As for the error code, you could dig backwards to AllocAddress.

bAddress = addrPool.AllocAddress(parent, false, port);

AllocAddress returns 0 (error) in 3 cases so add debug to see which one is triggering. If FindAddressIndex returns 0, dig back from there. I hope there is no USB hub since hubs add complications.

Thank you for all the tips. I will try to incorporate them. So far, I have used an FTDI converter so I can listen to the plain serial port without utilizing the conversion on the board. I have tried to debug it further in the methods that you stated but did not get full logs for some reason. Maybe it's the low baud. I also compared the successful run with the unsuccessful one but did not get any useful info yet. It's really a hustle to write logging messages everywhere :slight_smile: