Can anyone recommend low level USB host mass storage code for Due?

I have written a general FAT12/FAT16/FAT32 library that should work with almost any block device.

I would like to try it with a USB flash drive on Due.

I need low level USB host mass storage code for Due. Any recommendations?

Does Atmel Studio 6 have a USB mass storage demo for Due?

Have you seen this?

http://forum.arduino.cc/index.php?topic=135218.0

Have you seen this?

An example of Arduino Due as an USB host mass storage - Arduino Due - Arduino Forum

Too bad, I was hoping not to use Atmel Studio 6 code. Maybe Teensy 3.0 has USB mass storage host code.

I have worked on a USB host mass storage library, but it only worked with some usb sticks. But I could play stereo audio from it.

Hello fat16lib.

My current project calls for USB Mass Storage along with a custom-made daughter board and so I am not going the Ethernet-shield route. I don't need the RJ-45 Ethernet -- I need 802.11g/n WiFi! That left me with the only option of driving the Native USB port with a card-reader/USB-thumb-drive attached to it.

For about last 3 months I have been ramping up my knowledge on the OTG port hardware of SAM3X/A and have been able to come up with a rudimentary read/write mechanism (no performance, no DMA) on it.

So, I have taken up your code base sdfatlib20130629 and have made changes in the Sd2Card.cpp/h to interface with the front-end of my MINMSC (minimal Mass Storage Class) driver. I have tried to make the MINMSC plug-n-play and it should drive most card readers that are out there. Real spinning hard disks are a different story. My 320GB WD Passport is recognized but MINMSC cannot drive it because it doesn't report a SCSI Transparent Cmd Set.

Right now I am in the process of linking 4 things (USBHost lib, sdfat lib, MINMSC lib, libsam) together to make a build that works and then I can go back to MINMSC to clean it up and add AHB-speed DMA to it. At least two months of work is needed to complete it. And I have no intention of keeping it private ... it will have the same GNU FSF license as yours.

So, if you are interested, maybe we can share the code among ourselves first and find out the best way to interface, etc.

You wont believe how many hardware related gotchas are in there on the OTG port of DUE that would discourage most people but having spent most of my life in that hardware/software boundary and RTOS, I have been able to make some slow progress.

My congrats and gratitude to you for providing such a useful library for open software community.
Regards.

haturi,

I am writing a new FAT12/FAT16/FAT32 library that cleanly separates the FAT filesystem code from the block device driver. I am now testing with SD cards on SPI but the library supports any block device derived from this class.

class FatBlockDevice {
 public:
  // Return a code for an I/O error.
  virtual uint8_t hwErrorCode() const = 0;
  
  // Return extra data describing an I/O error.
  virtual uint8_t hwErrorData() const = 0;
  
  // Read a block from the device.
  virtual bool readBlock(uint32_t lbn, uint8_t* dst) = 0;

  // Write a block to the device.
  virtual bool writeBlock(uint32_t lbn, const uint8_t* src) = 0;

#if USE_MULTI_BLOCK_IO
  // Optional multiple block transfers.
  virtual bool readBlocks(uint32_t lbn, uint16_t count, uint8_t* dst) = 0;

  virtual bool writeBlocks(uint32_t lbn, uint16_t count, const uint8_t* src) = 0;
#endif  // USE_MULTI_BLOCK_IO 
 };

For SD on SPI I use the class SdSpiCard that is defined like this:

class SdSpiCard : public FatBlockDevice {
  ...
};

This is how the equivalent of SdFat is setup:

#include <FatLib.h>
#include <SdSpiCard.h>

SdSpiCard card;

// The argument of FatFilesystem has type FatBlockDevice * .
FatFilesystem sd(&card);

FatPrintFile file;
void setup() {
  Serial.begin(9600);

  if (!card.begin() || !sd.begin()) {
    Serial.println("begin failed");
    return;
  }
  file.open("SIZE_TST.TXT", O_RDWR | O_CREAT | O_AT_END);

  file.println("Hello");

  file.close();
  Serial.println("Done");
}

I am looking for a class for a USB flash drive to replace SdSpiCard. For example a class UsbFlashDrive that is derived from FatBlockDevice like this:

class UsbFlashDrive : public FatBlockDevice {
  ...
};

Would this be possible with your setup/code?

I still need to do some development and cleanup and then I could send you my FatLib library.

Hi fat16lib,
Your example sketch will need two more class defs... one for USBHost and one for MINMSC. Then it should be possible to run the setup().

There are three examples that use USBHost: ADK, Mouse/KDB-driver, and Android communication device (?). The way I thought of fitting in MINMSC is to make it follow USBHost interface because when I started looking into it, that was all I could find. However, I am not terribly interested in maintaining conformity with USBHost. I make use of following features of USBHost:

  1. USB Bus State Machine in USBHost.task()
  2. The general scheme to assign an USB address
  3. Ctl Pipe Xfr calls
  4. Very valuable set of header files (specially Chapter-9 Dev Framework)

I don't quite understand descriptor handling by USBHost and so I wrote that part myself. How important is it to be compatible with USBHost?

There is another subtle problem. Even though there is no hub-support in USBHost/MINMSC, there is a way to have multiple media being open at the same time on the bus. The Kingston 4-slot card reader I have can mount 4 different media types all at once... same usb-bus-adr, same dev-adr, but different luns. Note, there is only one USB device. MINMSC will allow opening handles to all these slots/luns (whether it has media or not) and the user of MINMSC (your lowest level code in this case) can drive all 4 handles at once. Under RTOS, the first I/O will proceed and the other 3 will block. Under executive loop, I may have to do the queuing myself or reject the other 3 with error.

All this means the 1-1 correspondence between an Sd2Card object and a MINMSC object cannot be maintained. So, the MINMSC is a singleton class that has multiple devices (4 for 4-slot card readers). Each higher level block-dev object will bind with exactly one of these devices under MINMSC.

Here is a short version of the header file with MINMSC class def. With this interface it should be pretty easy to open, read/write and close a block device.

typedef struct  msc_devList_entry_st
{
    uint8_t         vendorId[ 8];   // SCSI Inquiry Vendor Id Field as is
    uint8_t         productId[ 16]; // SCSI Inquiry Product Id Field as is
    uint8_t         busId;          // USB Bus Id ( DUE, PgmPort=0, Native=1)
    uint8_t         bAddress;       // Configured USB Bus Address
    uint8_t         lunCount;       // # LUNs ( Always at least 1 or more).
    uint8_t         unused;
}   MSC_DEVLIST_ENTRY;


typedef struct  msc_client_st
{
    uint8_t         clState;    // Client State: One of MSC_CLST_xxx numbers.
    uint8_t         lun;        // The 'lun' of MSC_DEV being used by client.
    uint16_t        msecCount;  // # millisecs spent while in zombie state.
    MSC_DEV     *   pMscDev;    // The MSC_DEV being used by client.
    CLIENT_CB_PTR   pClientCb;  // Ptr to client's callback function.
    void        *   pContext;   // Client's Context to pass during callback.
}   MSC_CLIENT;


class MINMSC : public USBDeviceConfig, public UsbConfigXtracter
{
    friend class    Sd2Card;

private:
    uint32_t        cbwTag;         //  Changes on every new CBW-CSW pair.
    uint32_t        mscDevCount;
    MSC_DEV         mscDev[ MSC_MAXCNT_DEV];
    MSC_CLIENT      mscClientTable[ MSC_MAXCNT_CL_ENTRY];
    void *                pMasterClientContext;
    MASTER_CLIENT_CB_PTR  pMasterClientCb;  // Only 1 master client allowed.
    //  The idea of having a master client is to allow someone who can monitor
    //  the USB Bus Events like disconnect, power problem, etc.  Individual
    //  devices are opened by regular clients and they receive device level
    //  notifications like media insertion in an empty slot, media removal.
    //  All regular clients are accounted for in mscClientTable[] array.


protected:
	/* Mandatory members */
	USBHost  *              pUsb;

public:
	MINMSC( USBHost *pUsb);

    //  Do not call following.  They are ISR related and cannot be Private.
    void        mscUsbIsr( MINMSC *);  // Don't call! ISRs => outside of class.
    void        mscDelayedClose( void);
    void        mscDetectMediaChange( void);
    //  End of Do Not Call stuff.

    uint32_t    mscGetVersion(   char    *, uint32_t bufSize);

    int32_t     mscRegGenTimerIsr(       void * pContext, ISR_CB_PTR  pIsr);
    void        mscUnregGenTimerIsr(     int32_t handle);
    void        mscReadHiPrecTimer( uint32_t * pTimerHi32,   uint32_t * pTimerLo32);
    inline
    uint32_t    mscReadHiPrecTimer_Lo32( void)
    {
        return
               MSC_TCBASE(MSC_TIMER_TC)->
                           TC_CHANNEL[ MSC_TIMER_TCCH_HI_PREC_CLOCK].TC_CV;
    }
    uint32_t    mscRegisterMasterClient( void * pContext,  MASTER_CLIENT_CB_PTR  pMasterClientCb);
    uint32_t    mscDevList( MSC_DEVLIST_ENTRY * pFirst, uint32_t  maxEntries);

    //----------------  I/O Interface  ----------------------
    int32_t  mscOpen( uint8_t usbBusId, uint8_t devAdr, uint8_t lun,  CLIENT_CB_PTR pCb, void * pContext);
    uint32_t mscReadCapacity( int32_t hndl, uint32_t * pLastBlkNum,   uint32_t * pBlkSize);
    uint32_t mscReadBlock(    int32_t hndl, uint32_t startBlkNum,  uint32_t blkCount, uint8_t * pBuf);
    uint32_t mscWriteBlock(   int32_t hndl, uint32_t startBlkNum,  uint32_t blkCount, uint8_t * pBuf);
    uint32_t mscWriteZero(    int32_t hndl, uint32_t startBlkNum,   uint32_t blkCount);
    uint32_t mscClose( int32_t hndl);

	// USBDeviceConfig implementation -- Conforming to USBHost Library.
	virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed);
	virtual uint32_t Release();
	virtual uint32_t Poll();
	virtual uint32_t GetAddress();
	virtual bool     isReady();

	// UsbConfigXtracter implementation -- Conforming to USBHost Library.
	virtual void EndpointXtract( uint32_t conf, uint32_t iface, uint32_t alt,
                                 uint32_t proto,
                                 const USB_ENDPOINT_DESCRIPTOR *ep);

    /* Timer Related */

    MSC_TICOM       mscGenTimer;    // The general multi-ISR 250 usec timer
    MSC_TIMER_CB    mscGenTimerCb[ MSC_MAXCNT_ISR];//Gen Timer callbacks(ISRs).

    MSC_TICOM       mscHiPrecClock; // Hi precision clock offered by MINMSC.
    uint32_t        mscHiPrecClock_hi32;    // The "lo32" comes from TC h/w.

    /*  Debugging related  */
    uint8_t mscDebug;       //  Has a collection of bits like MSCDEBUG_xxx.
};

I shall try to contact you within next few hours from my gmail account to yours and send you the Sd2Card.cpp/h for MINMSC.
Thanks.

fat16lib:
haturi,

I am writing a new FAT12/FAT16/FAT32 library that cleanly separates the FAT filesystem code from the block device driver. I am now testing with SD cards on SPI but the library supports any block device derived from this class.

class FatBlockDevice {

public:
  // Return a code for an I/O error.
  virtual uint8_t hwErrorCode() const = 0;
 
  // Return extra data describing an I/O error.
  virtual uint8_t hwErrorData() const = 0;
 
  // Read a block from the device.
  virtual bool readBlock(uint32_t lbn, uint8_t* dst) = 0;

// Write a block to the device.
  virtual bool writeBlock(uint32_t lbn, const uint8_t* src) = 0;

#if USE_MULTI_BLOCK_IO
  // Optional multiple block transfers.
  virtual bool readBlocks(uint32_t lbn, uint16_t count, uint8_t* dst) = 0;

virtual bool writeBlocks(uint32_t lbn, uint16_t count, const uint8_t* src) = 0;
#endif  // USE_MULTI_BLOCK_IO
};




For SD on SPI I use the class SdSpiCard that is defined like this:


class SdSpiCard : public FatBlockDevice {
  ...
};




This is how the equivalent of SdFat is setup:


#include <FatLib.h>
#include <SdSpiCard.h>

SdSpiCard card;

// The argument of FatFilesystem has type FatBlockDevice * .
FatFilesystem sd(&card);

FatPrintFile file;
void setup() {
  Serial.begin(9600);

if (!card.begin() || !sd.begin()) {
    Serial.println("begin failed");
    return;
  }
  file.open("SIZE_TST.TXT", O_RDWR | O_CREAT | O_AT_END);

file.println("Hello");

file.close();
  Serial.println("Done");
}




I am looking for a class for a USB flash drive to replace SdSpiCard. For example a class UsbFlashDrive that is derived from FatBlockDevice like this:


class UsbFlashDrive : public FatBlockDevice {
  ...
};




Would this be possible with your setup/code?

I still need to do some development and cleanup and then I could send you my FatLib library.

That's very nice! That way I could implement my mass storage lib.

Your example sketch will need two more class defs... one for USBHost and one for MINMSC. Then it should be possible to run the setup().

My new FAT library has a totally different structure than SdFat. The Sd2Card interface is not used.

My new FatLib doesn't handle device initialization. You either do that in your sketch before calling FatFilesystem::begin() or write a wrapper class that integrates your device code with FatLib.

I wrote a simple wrapper class to implement the new SdFat.

All this means the 1-1 correspondence between an Sd2Card object and a MINMSC object cannot be maintained. So, the MINMSC is a singleton class that has multiple devices (4 for 4-slot card readers). Each higher level block-dev object will bind with exactly one of these devices under MINMSC.

With the new FatLib you can have four file systems. Just write a higher level wrapper class for the singleton and create an object for each lun. This is no different than multiple SD cards on one SPI or SDIO bus.

You can have filesystems on multiple device types and multiple instances for each device type.

SdSpiCard card;

UsbFlashDrive usbDev.

FatFilesystem sd(&card);

FatFilesystem key(&usbDev);

void setup() {
  // initialize the SPI bus and SD card here
  ...
  // initialize the USB host and MINMSC here.
  ...

// initialize the file systems here
  if (!sd.begin() || !key.begin()) {
    // filesystem init error.
 }
}

Ok. Higher level wrapper class for MINMSC which will create objects for each lun. That's what I will shoot for.
Thanks.