Intermittent USB HOST and MSC init failure in driveInfo.ino.

wwatson

Well-known member
Ran into a situation where a USB drive would fail to initialize properly. This showed up in two files. driveInfo.ino in the USBHost_t36 library and in an example sketch of mine copyFileUSB.ino. The drive init portion in setup() was incorrect:
Code:
  Serial.print("\nInitializing USB MSC drive...");
  // Wait for the drive to start.
  while (!myDrive) {
    myusb.Task();
  }
This waited for the drive to appear which it did. But sometimes the filesystem portion was not ready and any disk operation would fail. So changed it to:
Code:
  Serial.print("\nWaiting for partition to...");

  while (!myFiles) {
    myusb.Task();
  }

That fixed the problem. Will issue a PR for driveInfo.ino.
 
Ran into a situation where a USB drive would fail to initialize properly. This showed up in two files. driveInfo.ino in the USBHost_t36 library and in an example sketch of mine copyFileUSB.ino. The drive init portion in setup() was incorrect:
Code:
  Serial.print("\nInitializing USB MSC drive...");
  // Wait for the drive to start.
  while (!myDrive) {
    myusb.Task();
  }
This waited for the drive to appear which it did. But sometimes the filesystem portion was not ready and any disk operation would fail. So changed it to:
Code:
  Serial.print("\nWaiting for partition to...");

  while (!myFiles) {
    myusb.Task();
  }

That fixed the problem. Will issue a PR for driveInfo.ino.

Haven't run into that problem - don't think but definitely good to make that change - will have to check on one of the drives I have laying around that never worked
 
Ran into a situation where a USB drive would fail to initialize properly. This showed up in two files. driveInfo.ino in the USBHost_t36 library and in an example sketch of mine copyFileUSB.ino. The drive init portion in setup() was incorrect:
Code:
  Serial.print("\nInitializing USB MSC drive...");
  // Wait for the drive to start.
  while (!myDrive) {
    myusb.Task();
  }
This waited for the drive to appear which it did. But sometimes the filesystem portion was not ready and any disk operation would fail. So changed it to:
Code:
  Serial.print("\nWaiting for partition to...");

  while (!myFiles) {
    myusb.Task();
  }

That fixed the problem. Will issue a PR for driveInfo.ino.

Should it wait forever without a timeout?
 
@BriComp - No it should not and it does not...
This waited for the drive to appear which it did. But sometimes the filesystem portion was not ready and any disk operation would fail.
 
Code:
  Serial.print("\nWaiting for partition to...");

  while (!myFiles) {
    myusb.Task();
  }
Surely if for some reason myFiles NEVER becomes TRUE it will loop forever, or am I missing something?
 
@mjs513 - It happened much more consistently with the copyFile.ino sketch than it did with the driveInfo.ino sketch.
If anybody wants to test, here is the sketch that was failing intermittently:
Code:
/*
  MSC Drive read/write copy file
 
 This example code is in the public domain.
 */
 
#include <USBHost_t36.h>

// Setup USBHost_t36 and as many HUB ports as needed.
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);

// Setup MSC for the number of USB Drives you are using. (Two for this example)
// Mutiple  USB drives can be used. Hot plugging is supported. There is a slight
// delay after a USB MSC device is plugged in. This is waiting for initialization
// but after it is initialized ther should be no delay.
USBDrive myDrive(myusb);

USBFilesystem firstPartition(myusb);

File myFile;
File myFile1;

//************************************************
// Size of read/write buffer. Start with 4096.
// Have tried 4096, 8192, 16384, 32768 and 65536.
// Usually settle on 16384 
// 
//************************************************
const size_t BUF_SIZE = 16384;

// File size in MB where MB = 1,024,000 bytes.
const uint32_t FILE_SIZE_MB = 32;
// File size in bytes.
const uint32_t FILE_SIZE = 1024000UL*FILE_SIZE_MB;
FASTRUN uint8_t* buf[BUF_SIZE];
uint32_t t;
uint32_t flSize = 0;
float MBs = 1.0f;

void setup()
{
// Wait for port to open:
   while (!Serial) {
    yield();
  }

  // Start USBHost_t36, HUB(s) and USB devices.
  myusb.begin();


//*****************************************************
/*// This does not fail to init.
  Serial.print("\nInitializing USB MSC drive...");
  // Wait for claim proccess to finish.
  while(!firstPartition) {
    myusb.Task();
  }
*/
//*****************************************************

//*****************************************************
  // This portion of code fails to init properly
  // intermittently.
  Serial.print("\nInitializing USB MSC drive...");
  // Wait for the drive to start.
  while (!myDrive) {
    myusb.Task();
  }
//*****************************************************

  Serial.println("initialization done.");
  Serial.print("\nTesting Write, Copy and Read. BUF_SIZE = ");
  Serial.println(BUF_SIZE);

  Serial.println("\nDirectory Listing");
  File root = firstPartition.open("/");
  Serial.println("Directory listing for USB drive:");
  printDirectory(root, 0);

  // fill buf with known data
  if (BUF_SIZE > 1) {
    for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
      buf[i] = (uint8_t *)('A' + (i % 26));
    }
    buf[BUF_SIZE-2] = (uint8_t *)'\r';
  }
  buf[BUF_SIZE-1] = (uint8_t *)'\n';
  
  uint32_t n = FILE_SIZE/BUF_SIZE;

  if(firstPartition.exists("test.txt"))
	firstPartition.remove("test.txt");

  // open the file. 
  myFile = firstPartition.open("test.txt", FILE_WRITE_BEGIN);
  
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("\nWriting to test.txt...");
  t = millis();
  for (uint32_t i = 0; i < n; i++) {
    if (myFile.write(buf, BUF_SIZE) != BUF_SIZE) {
      Serial.printf("Write Failed: Stopping Here...");
      while(1);
    }
  }
  t = millis() - t;
  flSize = myFile.size();
  MBs = flSize / t;
  Serial.printf("Wrote %lu bytes %f seconds. Speed : %f MB/s\n",flSize, (1.0 * t)/1000.0f, MBs / 1000.0f);
  // close the file:
  myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("Error opening test.txt: Write Failed: Stopping Here...");
    while(1);
  }
  // re-open the file for reading:
  myFile = firstPartition.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
	if(firstPartition.exists("copy.txt"))
		firstPartition.remove("copy.txt");
    // open the second file for writing. 
    myFile1 = firstPartition.open("copy.txt", FILE_WRITE_BEGIN);
    // if the file opened okay, write to it:
    if (myFile1) {
      Serial.printf("Copying test.txt to copy.txt...");
	  t = millis();
      while(myFile.read(buf, BUF_SIZE) == BUF_SIZE) {
        if (myFile1.write(buf, BUF_SIZE) != BUF_SIZE) {
          Serial.printf("Write Failed: Stoppiing Here...");
          while(1);
        }
      }
    }
    t = millis() - t;
    flSize = myFile.size();
    MBs = flSize / t;
    Serial.printf("Copied %lu bytes %f seconds. Speed : %f MB/s\n",flSize, (1.0 * t)/1000.0f, MBs/1000.0f);
    // close the files:
    myFile.close();
    myFile1.close();
  } else {
  	// if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  // re-open the second file for reading:
  myFile1 = firstPartition.open("copy.txt");
  if (myFile1) {
    Serial.println("copy.txt:");
    // open the file for a read. 
    myFile1 = firstPartition.open("copy.txt");
    // if the file opened okay, write to it:
    if (myFile1) {
      Serial.printf("Reading File: copy.txt...");
	  t = millis();
      while(myFile1.read(buf, BUF_SIZE) == BUF_SIZE);
    }
    t = millis() - t;
    flSize = myFile1.size();
    MBs = flSize / t;
    Serial.printf("Read %lu bytes %f seconds. Speed : %f MB/s\n",flSize, (1.0 * t)/1000.0f, MBs/1000.0f);
    // close the files:
    myFile1.close();
  } else {
  	// if the file didn't open, print an error:
    Serial.println("Error opening copy.txt");
  }
  Serial.printf("Done..\n");
}

void loop()
{
	// nothing happens after setup
}

void printDirectory(File dir, int numSpaces) {
   while(true) {
     File entry = dir.openNextFile();
     if (! entry) {
       //Serial.println("** no more files **");
       break;
     }
     printSpaces(numSpaces);
     Serial.print(entry.name());
     if (entry.isDirectory()) {
       Serial.println("/");
       printDirectory(entry, numSpaces+2);
     } else {
       // files have sizes, directories do not
       printSpaces(48 - numSpaces - strlen(entry.name()));
       Serial.print("  ");
       Serial.println(entry.size(), DEC);
     }
     entry.close();
   }
}

void printSpaces(int num) {
  for (int i=0; i < num; i++) {
    Serial.print(" ");
  }
}

This was tested on both a T4.1 and T4.0. The failure:
Code:
Initializing USB MSC drive...initialization done.

Testing Write, Copy and Read. BUF_SIZE = 16384

Directory Listing
Directory listing for USB drive:
Error opening test.txt: Write Failed: Stopping Here...

There were three things I tried to consistently cause the failure:
1. Uploading sketch multiple time in a row.
2. Unplugging and replugging multiple times.
3. Pushing the program button multiple times.

It would init properly sometimes and sometimes not. Normal init output put looks like:

Code:
Initializing USB MSC drive...initialization done.

Testing Write, Copy and Read. BUF_SIZE = 16384

Directory Listing
Directory listing for USB drive:
test.txt                                          32768000                                         
copy.txt                                          32768000                                         
32MEGfile.dat                                     32768000                                         
MSCtesting.bas                                    534                                              
test.bas                                          95                                               
bench.dat                                         32768000

Writing to test.txt...Wrote 32768000 bytes 2.674000 seconds. Speed : 12.254000 MB/s
test.txt:
Copying test.txt to copy.txt...Copied 32768000 bytes 4.510000 seconds. Speed : 7.265000 MB/s
copy.txt:
Reading File: copy.txt...Read 32768000 bytes 1.501000 seconds. Speed : 21.830000 MB/s
Done..

You will see two init sections in the sketch. The working version is commented out.

@Paul merged the PR.
 
Code:
  Serial.print("\nWaiting for partition to...");

  while (!myFiles) {
    myusb.Task();
  }
Surely if for some reason myFiles NEVER becomes TRUE it will loop forever, or am I missing something?

I see what you are getting at. I thought you were talking about:
Code:
  while (!myDrive) {
    myusb.Task();
  }

The only time it will hang forever is if there is no drive plugged in. Which kinda defeats the whole idea:) I have a couple of failed USB sticks that I test with and when I test those the result is:
Code:
Initializing USB MSC drive...initialization done.

Testing Write, Copy and Read. BUF_SIZE = 16384

Directory Listing
Directory listing for USB drive:
Error opening test.txt: Write Failed: Stopping Here...

I suppose you could add a timeout but how long do you wait? The init times on some of these devices can be over a minute. Hard drive especially...

EDIT: I am working on several examples loosely related to SdFat and some of my previous examples. One of those will be examples of error checking. There is quite a bit of error checking going on in MSC already.
 
Last edited:
I see what you are getting at. I thought you were talking about:
Code:
  while (!myDrive) {
    myusb.Task();
  }

The only time it will hang forever is if there is no drive plugged in. Which kinda defeats the whole idea:) I have a couple of failed USB sticks that I test with and when I test those the result is:
Code:
Initializing USB MSC drive...initialization done.

Testing Write, Copy and Read. BUF_SIZE = 16384

Directory Listing
Directory listing for USB drive:
Error opening test.txt: Write Failed: Stopping Here...

I suppose you could add a timeout but how long do you wait? The init times on some of these devices can be over a minute. Hard drive especially...

EDIT: I am working on several examples loosely related to SdFat and some of my previous examples. One of those will be examples of error checking. There is quite a bit of error checking going on in MSC already.

I was most concerned about a failing (not completely failed) drive, but looks like you might have that handled.
 
I was most concerned about a failing (not completely failed) drive, but looks like you might have that handled.

Let's say I'm working on it:)

Just for an example, I run the driveInfo.ino sketch from the USBHost_t36 library and I forgot to plug in a USB drive I would see:
Code:
Initializing USB MSC drive...
Waiting for Drive to initialize...

Then wondering why nothing was happening I realize I did not plug in a drive. I plug it in and:
Code:
Waiting for Drive to initialize...
Device Info:
       connected: 1
     initialized: 1
   USB Vendor ID: 0781
  USB Product ID: 5590
      HUB Number: 1
        HUB Port: 1
  Device Address: 2
Removable Device: YES
        VendorID:  SanDisk
       ProductID:            Ultra
      RevisionID: 1.00
         Version: 6
    Sector Count: 60062499
     Sector size: 512
   Disk Capacity: 30751999488 Bytes

Partition Table
        part,boot,bgnCHS[3],type,endCHS[3],start,length
exFAT:  1,0,0x4,0x1,0x4,0x7,0xFE,0xC2,0xFF,2048,60059648
pt_#0:  2,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0,0
pt_#0:  3,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0,0
pt_#0:  4,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0,0
         < unused area starting at: 60061696 length 803 >

Volume name: 32GUSBEXFAT
Volume type: FAT64
Cluster Size: 32768 bytes
Volume size: 30745296896 bytes
 Space used: 131334144 bytes  (143 ms to compute)

Files:
2023-01-01 00:00     32768000 test.txt
2023-01-01 00:00     32768000 copy.txt
2019-01-01 00:00     32768000 32MEGfile.dat
2023-03-31 11:14          534 MSCtesting.bas
2023-04-04 14:34           95 test.bas
2023-01-01 00:00     32768000 bench.dat

Hot plugging is supported.

If the device is faulty I would see:
Code:
Waiting for Drive to initialize...
Device Info:
       connected: 1
     initialized: 0
   USB Vendor ID: 0000
  USB Product ID: 0000
      HUB Number: 0
        HUB Port: 0
  Device Address: 0
Removable Device: NO
        VendorID:         
       ProductID:                 
      RevisionID:     
         Version: 0
    Sector Count: 0
     Sector size: 0
   Disk Capacity: 0 Bytes

Volume name: 
Volume type: FAT0
Cluster Size: 0 bytes
Volume size: 0 bytes
 Space used: 0 bytes  (0 ms to compute)

Files:
Which shows something is definitely wrong.
The user can add a timeout to:
Code:
  // Wait for the drive to start.
elapsedMillis timeout;
  while (!myDrive) {
    myusb.Task();
if(timeout > 5000) {
  Serial.println("Timeout: no device detected. Halting...");
  while(1);
}
  }
And after let's say 5 seconds an error would be reported:
Code:
Waiting for Drive to initialize...
Timeout: no device detected. Halting...

There are several way's the user can handle timeouts. Kind of a dealers choice...
 
Back
Top