AnsweredAssumed Answered

LPC43XX USB HOST Mass storage class - drive fails the second time it is plugged in

Question asked by lpcware Employee on Jun 15, 2016
Latest reply on Oct 4, 2016 by Nataraj Balasubramanian
Content originally posted in LPCWare by iemc on Thu Oct 15 17:59:51 MST 2015

Chip: LPC4357 (1MB internal flash)
Manual: UM10503.pdf Rev. 1.9 — 18 February 2015
LPCOpen: lpcopen_2_16_lpcxpresso_nxp_lpcxpresso_4337.zip

Using the LPCUSBlib_MassStorageHost example code.

In release code I want the software to detect a drive being plugged in to the USB Host port which can happen multiple times. I have discovered two problems using the mass storage example code when I try to do this.

The first problem I have been able to work around, which I will explain below. The second problem I haven't been able to find a fix for. Please note that the example code works perfectly the first time a thumb drive is plugged in. It only fails when the drive is removed and plugged in again.

Is it expected to use the LPCOpen code for production software as is? I see this comment in the source code "Software that is described herein is for illustrative purposes only". Should I be looking for a commercial USB library?

Here is how I modified the LPCUSBlib_MassStorageHost example code.

When the event function EVENT_USB_Host_DeviceAttached is called I set a flag for the main loop to run the file test. The idea is to run the test each time a USB thumb drive is plugged in.

File: LPCUSBlib_MassStorageHost\example\src\MassStorageHost.c

bool    DoTestUSBHost; /* flag set by attached event to trigger test code */

int main(void)
{
  SetupHardware();

  while (1)
  {
    if (DoTestUSBHost)
    {
      DEBUGOUT("Mass Storage Host Demo running.\r\n");
      USB_ReadWriteFile();
      DEBUGOUT("Example completed.\r\n");
      DoTestUSBHost = false;
    }
  }
}

void EVENT_USB_Host_DeviceAttached(const uint8_t corenum)
{
  DEBUGOUT(("Device Attached on port %d\r\n"), corenum);
  DoTestUSBHost = true;
}


When I run this code it succeeds the first time I plug in a thumb drive. When I remove the drive and plug it in a second time I get the following error.

Error reading device block.

Which is in LPCUSBlib_MassStorageHost\example\src\MassStorageHost.c in this code.

/* Read sectors */
int FSUSB_DiskReadSectors(DISK_HANDLE_T *hDisk, void *buff, uint32_t secStart, uint32_t numSec)
{
  if (MS_Host_ReadDeviceBlocks(hDisk, 0, secStart, numSec, DiskCapacity.BlockSize, buff)) {
    DEBUGOUT("Error reading device block.\r\n");
    USB_Host_SetDeviceConfiguration(FlashDisk_MS_Interface.Config.PortNumber, 0);
    return 0;
  }
  return 1;
}


I traced this problem to fatfs\src\fs_usb.c

/* Disk Status */
static volatile DSTATUS Stat = STA_NOINIT;

/* Initialize Disk Drive */
DSTATUS disk_initialize(BYTE drv)
{
  if (drv) {
    return STA_NOINIT;        /* Supports only single drive */
  }
  /*  if (Stat & STA_NODISK) return Stat; *//* No card in the socket */

  if (Stat != STA_NOINIT) {
    return Stat;          /* card is already enumerated */

  }

  #if !_FS_READONLY
  FSUSB_InitRealTimeClock();
  #endif

  /* Initialize the Card Data Strucutre */
  hDisk = FSUSB_DiskInit();

  /* Reset */
  Stat = STA_NOINIT;

  FSUSB_DiskInsertWait(hDisk); /* Wait for card to be inserted */

  /* Enumerate the card once detected. Note this function may block for a little while. */
  if (!FSUSB_DiskAcquire(hDisk)) {
    DEBUGOUT("Disk Enumeration failed...\r\n");
    return Stat;
  }

  Stat &= ~STA_NOINIT;
  return Stat;

}


The Stat variable is initialized to STA_NOINIT. The first time disk_initialize() is called it clears the STA_NOINIT bit before returning.

So the when the drive is plugged in the second time and disk_initialize() is called again it returns at this statement.

  if (Stat != STA_NOINIT) {
    return Stat;          /* card is already enumerated */
  }


The code after that is therefore not called and the USB does not enumerate the thumb drive properly. The Stat variable is never set back to STA_NOINIT.

To work around this I added this function to MassStorageHost.c to do the necessary initialization that disk_initialize() failed to do.

bool USBHostWaitForReady(void)
{
  FSUSB_DiskInsertWait(&FlashDisk_MS_Interface);
  return (USB_HostState[FlashDisk_MS_Interface.Config.PortNumber] == HOST_STATE_Configured);
}


I then call this new function in the function USB_ReadWriteFile just before the call to f_mount().

/* Function to do the read/write to USB Disk */
static void USB_ReadWriteFile(void)
{
...snip...

  if (!USBHostWaitForReady()) /* FIX for disk_initialize(): STA_NOINIT is never reset! */
  {
    DEBUGOUT("\rUSBHostWaitForReady failed");
    return;
  }

  f_mount(0, &fatFS);   /* Register volume work area (never fails) */
...


With this change the drive is enumerated correctly the second time and the test succeeds.

But now another problem happens. When the test finished I see a spurious unattach, attach event. The test tried to run again and hangs. My debug log look like this.

EVENT_USB_Host_DeviceAttached
TestUSBHost started
FSUSB_DiskInsertWait begin
Total LUNs: 1 - Using first LUN in device.
Mass Storage Device Enumerated.
FSUSB_DiskInsertWait end
Create a new file (hello.txt).
Write a text data. (Hello world!)14 bytes written.
Close the file.
Opened file HELLO.TXT from USB Disk. Printing contents...
Hello world!

Close the file.
Deleted HELLO.TXT from USB Disk.
Test completed.
Example completed.
EVENT_USB_Host_DeviceUnattached
EVENT_USB_Host_DeviceAttached
TestUSBHost started
FSUSB_DiskInsertWait begin
Total LUNs: 1 - Using first LUN in device.
Mass Storage Device Enumerated.
FSUSB_DiskInsertWait end
Create a new file (hello.txt).
(hangs)

At this point I am stuck.

Outcomes