GIGA R1 USB Mass Storage does not seem to support partitioned drives

First I agree with this thread: USB mass storage does not work with other 0.0.3 - if I use the lasted just hangs and gives the red flashing light.

GIGA R1 USB Mass Storage examples : has anyone managed to run an example project ? - Hardware / GIGA R1 - Arduino Forum

Now for partitioned drives issue I managed to read the mbr for fat32 drives (doesn't read exFat drives at all) and shows that my thumb drive has 2 partitions:

Mounting USB device... done.
Disk read Result: FR_OK

**Master Boot Record**
**  Partition: 0 first Sector: 2112 total Sectors: 53610496**
**  Partition: 1 first Sector: 53614529 total Sectors: 67530815**
**Total partions on Disk: 2**

First partition Sector
Disk read Result: FR_OK

First partition Sector
Disk read Result: FR_NO_FILE
FAT32
bytes per sector :512
sectors per cluster :32

Second partition Sector
Disk read Result: FR_NO_FILE
FAT32
bytes per sector :512
sectors per cluster :32
Done...!

Now if I try to mount the partitions the sketch fails with:

Test diskio
done.
Partition 1 not found
Mount both error: 1

This is the sketch I am using to test the ability to access the partitions:


/* ======================================================= *
*    https://github.com/ARMmbed/mbed-os/issues/4526        *
* ======================================================== */

#include <LibPrintf.h>
#include <ff.h>
#include <FATFileSystem.h>
#include <DigitalOut.h>
#include <Arduino_USBHostMbed5.h>
#include "MBRBlockDevice.h"
#include <errno.h>

USBHostMSD msd;

PARTITION VolToPart[] = {{0, 1},
                         {0, 2}, 
                         {0, 3}, 
                         {0, 4} 
                         };

mbed::MBRBlockDevice part1(&msd, 1);
mbed::MBRBlockDevice part2(&msd, 2);
mbed::FATFileSystem fs1("fs1");
mbed::FATFileSystem fs2("fs2");

void setup() {
  Serial.begin(115200);
    
  pinMode(PA_15, OUTPUT); //enable the USB-A port
  digitalWrite(PA_15, HIGH);
    
  // put your setup code here, to run once:

  while(!Serial);
  Serial.println("Test diskio");


    while (!msd.connect()) {
        //while (!port.connected()) {
        delay(1000);
    }

    Serial.println("done.");

    int err = forcemountboth();
    printf("forcemountboth %d\n", err);

    char buf[256];

    err = unmountboth();
    printf("unmountboth %d\n", err);

  pinMode(13,OUTPUT);
}

void loop() {
  digitalWrite(13,!digitalRead(13));
  delay(1000);
}


int mountboth() {
  int err;
    err = part1.init();
      if (!err) {
          Serial.println("partition 1 exists\n");
          err =  fs1.mount(&part1); // checkfor FAT filesystem
          if (!err) {
              Serial.println("FAT filesystem exists on partition 1");
          }
      } else {
        Serial.println("Partition 1 not found");
        return 1;
      }

     err = part2.init();
      if (!err) {
          Serial.println("partition 2 exists\n");
          err =  fs1.mount(&part2); // checkfor FAT filesystem
          if (!err) {
              Serial.println("FAT filesystem exists on partition 2");
          }
      } else {
        Serial.println("Partition 2 not found");
        return 1;
      }

     return 0;
}

int forcemountboth() {
  int err = mountboth();
  if (err) {
      Serial.print("Mount both error: "); Serial.println(err);
      while(1){}
  }

    return mountboth();
}

int unmountboth() {
    int err = fs1.unmount();
    if (err) {
        Serial.print("fs1 Unmount error: "); Serial.println(err);
        while(1){}
    }

    err = fs2.unmount();
    if (err) {
        Serial.print("fs2 Unmount error: "); Serial.println(err);
        while(1){}
    }

    err = part1.deinit();
    if (err) {
        Serial.print("part1 deinit error: "); Serial.println(err);
        while(1){}
    }

    err = part2.deinit();
    if (err) {
        Serial.print("part2 deinit error: "); Serial.println(err);
        while(1){}
    }

    return 0;
}

The MBR sketch :

#include <LibPrintf.h>
#include <DigitalOut.h>
#include <MemoryHexDump.h>

#include <ff.h>
#include <FATFileSystem.h>
#include <diskio.h>
#include <Arduino_USBHostMbed5.h>

USBHostMSD msd;
mbed::FATFileSystem usb("usb");

/* ================================================================ */

#define hexDump false

PARTITION VolToPart[] = {{0, 1},
                         {0, 2}, 
                         {0, 3}, 
                         {0, 4}, 
                         };

/*
* for APL see http://elm-chan.org/fsw/ff/00index_e.html
*/
#define TEST_DRV 0

const char *fileSystem[] = {"No FS", "FS_FAT12","FS_FAT16","FS_FAT32","FS_EXFAT"};

const char *FR_ERROR_STRING[] = {
	"FR_OK",				/* (0) Succeeded */
	"FR_DISK_ERR",			/* (1) A hard error occurred in the low level disk I/O layer */
	"FR_INT_ERR",				/* (2) Assertion failed */
	"FR_NOT_READY",			/* (3) The physical drive cannot work */
	"FR_NO_FILE",				/* (4) Could not find the file */
	"FR_NO_PATH",				/* (5) Could not find the path */
	"FR_INVALID_NAME",		/* (6) The path name format is invalid */
	"FR_DENIED",				/* (7) Access denied due to prohibited access or directory full */
	"FR_EXIST",				/* (8) Access denied due to prohibited access */
	"FR_INVALID_OBJECT",		/* (9) The file/directory object is invalid */
	"FR_WRITE_PROTECTED",		/* (10) The physical drive is write protected */
	"FR_INVALID_DRIVE",		/* (11) The logical drive number is invalid */
	"FR_NOT_ENABLED",			/* (12) The volume has no work area */
	"FR_NO_FILESYSTEM",		/* (13) There is no valid FAT volume */
	"FR_MKFS_ABORTED",		/* (14) The f_mkfs() aborted due to any problem */
	"FR_TIMEOUT",				/* (15) Could not get a grant to access the volume within defined period */
	"FR_LOCKED",				/* (16) The operation is rejected according to the file sharing policy */
	"FR_NOT_ENOUGH_CORE",		/* (17) LFN working buffer could not be allocated */
	"FR_TOO_MANY_OPEN_FILES",	/* (18) Number of open files > FF_FS_LOCK */
	"FR_INVALID_PARAMETER"	/* (19) Given parameter is invalid */
};

const char *STAT_ERROR_STRING[] = {
	"STA_OK", //		0x00	/* No error */
	"STA_NOINIT", //		0x01	/* Drive not initialized */
	"STA_NODISK", //		0x02	/* No medium in the drive */
	"STA_UNKNOWN", //		0x03	/* unknown error*/
	"STA_PROTECT" //		0x04	/* Write protected */
};

struct partitionTable {
  uint8_t  boot;
  uint8_t  beginHead;
  unsigned beginSector : 6;
  unsigned beginCylinderHigh : 2;
  uint8_t  beginCylinderLow;
  uint8_t  type;
  uint8_t  endHead;
  unsigned endSector : 6;
  unsigned endCylinderHigh : 2;
  uint8_t  endCylinderLow;
  uint32_t firstSector;
  uint32_t totalSectors;
} __attribute__((packed));
typedef struct partitionTable part_t;

struct masterBootRecord {
  uint8_t  codeArea[440];
  uint32_t diskSignature;
  uint16_t usuallyZero;
  part_t   part[4];
  uint8_t  mbrSig0;
  uint8_t  mbrSig1;
} __attribute__((packed));
typedef struct masterBootRecord mbr_t;

struct guid {
  uint8_t signature[8];  //8 bytes
  uint8_t revision[4];  //pos 3
  uint8_t hdr_sz[4];    //pos 1
  uint32_t crc32;     //single 32bit val
  uint8_t reserved[4];
  uint8_t prim_lba[8];  //pos 1 always = 1
  uint8_t back_lba[8];  //Address of backup LBA
  uint8_t first_lba[8];
  uint8_t last_lba[8];
  uint8_t disk_guid[16];
  uint8_t part_entry_lba[8];
  uint8_t number_parts[4];
  uint8_t sz_parts[4];
  uint32_t part_entry_crc32;
  uint8_t temp1[420];
}__attribute__((packed));
typedef struct guid guid_t;

struct fat32_boot {
  uint8_t jump[3];
  char    oemId[8];
  uint16_t bytesPerSector;
  uint8_t  sectorsPerCluster;
  uint16_t reservedSectorCount;
  uint8_t  fatCount;
  uint16_t rootDirEntryCount;
  uint16_t totalSectors16;
  uint8_t  mediaType;
  uint16_t sectorsPerFat16;
  uint16_t sectorsPerTrack;
  uint16_t headCount;
  uint32_t hidddenSectors;
  uint32_t totalSectors32;
  uint32_t sectorsPerFat32;
  uint16_t fat32Flags;
  uint16_t fat32Version;
  uint32_t fat32RootCluster;
  uint16_t fat32FSInfo;
  uint16_t fat32BackBootBlock;
  uint8_t  fat32Reserved[12];
  uint8_t  driveNumber;
  uint8_t  reserved1;
  uint8_t  bootSignature;
  uint32_t volumeSerialNumber;
  char     volumeLabel[11];
  char     fileSystemType[8];
  uint8_t  bootCode[420];
  uint8_t  bootSectorSig0;
  uint8_t  bootSectorSig1;
}__attribute__((packed));
typedef struct fat32_boot fat32_boot_t;

typedef uint16_t  le16_t;
typedef uint32_t  le32_t;
typedef uint64_t  le64_t;

struct exfat_super_block
{
  uint8_t jump[3];        /* 0x00 jmp and nop instructions */
  char oem_name[8];      /* 0x03 "EXFAT   " */
  uint8_t __unused1[53];      /* 0x0B always 0 */
  le64_t sector_start;      /* 0x40 partition first sector */
  le64_t sector_count;      /* 0x48 partition sectors count */
  le32_t fat_sector_start;    /* 0x50 FAT first sector */
  le32_t fat_sector_count;    /* 0x54 FAT sectors count */
  le32_t cluster_sector_start;  /* 0x58 first cluster sector */
  le32_t cluster_count;     /* 0x5C total clusters count */
  le32_t rootdir_cluster;     /* 0x60 first cluster of the root dir */
  le32_t volume_serial;     /* 0x64 volume serial number */
  struct              /* 0x68 FS version */
  {
    uint8_t minor;
    uint8_t major;
  }
  version;
  le16_t volume_state;      /* 0x6A volume state flags */
  uint8_t sector_bits;      /* 0x6C sector size as (1 << n) */
  uint8_t spc_bits;       /* 0x6D sectors per cluster as (1 << n) */
  uint8_t fat_count;        /* 0x6E always 1 */
  uint8_t drive_no;       /* 0x6F always 0x80 */
  uint8_t allocated_percent;    /* 0x70 percentage of allocated space */
  uint8_t __unused2[397];     /* 0x71 always 0 */
  le16_t boot_signature;      /* the value of 0xAA55 */
} __attribute__((packed));
typedef struct exfat_super_block exfat_boot_t;

void die(const char *text, FRESULT rc)
{ printf("%s: Failed with rc=%s.\r\n", text,FR_ERROR_STRING[rc]);  while(1) asm("wfi"); }

FRESULT rc;       /* Result code */
FATFS fatfs;      /* File system object */
FIL fil;          /* File object */
FATFS_DIR dir;          /* Directory object */
FILINFO fno;      /* File information object */
UINT bw, br, wr;

uint32_t buffer[128];
void setup() {
  Serial.begin(115200);
    
  pinMode(PA_15, OUTPUT); //enable the USB-A port
  digitalWrite(PA_15, HIGH);
    
  // put your setup code here, to run once:

  while(!Serial);
  Serial.println("Test diskio");

    // if you are using a Max Carrier uncomment the following line
    // start_hub();

    while (!msd.connect()) {
        //while (!port.connected()) {
        delay(1000);
    }

    Serial.print("Mounting USB device... ");
    int err = usb.mount(&msd);
    if (err) {
        Serial.print("Error mounting USB device ");
        Serial.println(err);
        while (1);
    }
    Serial.println("done.");

  BYTE pdrv = TEST_DRV;
  uint8_t sector_buffer[512];

  BYTE* buff = (BYTE *) buffer;
  DWORD sector = 0;
  DWORD sector1 = 0;
  UINT count = 1;
  UINT count1 = 1;

  DRESULT res = disk_read (pdrv, sector_buffer, sector, count);
  Serial.print("Disk read Result: "); Serial.println(FR_ERROR_STRING[res]);
  if(hexDump) MemoryHexDump(Serial, sector_buffer, sizeof(sector_buffer), false);

  mbr_t *mbr = (mbr_t *) sector_buffer;
  Serial.println("\nMaster Boot Record");
  for(int ii=0;ii<4;ii++)
  {
    if(mbr->part[ii].totalSectors == 0) {
      Serial.print("Total partions on Disk: "); Serial.println(ii);
      break;
    }
    Serial.print("  Partition: "); Serial.print(ii);
    Serial.print(" first Sector: ");
    Serial.print(mbr->part[ii].firstSector);
    Serial.print(" total Sectors: ");
    Serial.println(mbr->part[ii].totalSectors);
  }

  // read now first partition sector
  Serial.println("\nFirst partition Sector");
  sector = mbr->part[0].firstSector;
  count = 1;
  res = disk_read (pdrv, sector_buffer, sector, count);
  Serial.print("Disk read Result: "); Serial.println(FR_ERROR_STRING[res]);
  if(hexDump) MemoryHexDump(Serial, sector_buffer, sizeof(sector_buffer), false);

  fat32_boot_t * ptr1=(fat32_boot_t *) sector_buffer;
  exfat_boot_t * ptr2=(exfat_boot_t *) sector_buffer;

  if(mbr->part[0].type == 0xee)
  {
    // read now first partition sector
    Serial.println("\nFirst partition Sector");
    sector = mbr->part[0].firstSector;
    sector1 = mbr->part[1].firstSector;
    count = 1;
    res = disk_read (pdrv, sector_buffer, sector, count);
    Serial.print("Disk read Result: "); Serial.println(FR_ERROR_STRING[res]);
    if(hexDump) MemoryHexDump(Serial, sector_buffer, sizeof(sector_buffer), false);

    guid_t * ptr1=(guid_t *) buffer;

    Serial.println("====  GPT GUID HEADER ====");
    Serial.print("Signature: ");
    for(uint8_t ii = 0; ii<8; ii++){ 
      Serial.print(ptr1->signature[ii], HEX);
      Serial.print(", ");
    }
    Serial.println();
  
    Serial.print("Number of Partitions: ");
    Serial.println(ptr1->number_parts[0], HEX);
  } 
  else 
  {
    // read now first partition sector
    Serial.println("\nFirst partition Sector");
    sector = mbr->part[0].firstSector;
    sector1 = mbr->part[1].firstSector;
    count = 1;
    res = disk_read (pdrv, sector_buffer, sector, count);
    Serial.print("Disk read Result: "); Serial.println(FR_ERROR_STRING[res]);
    if(hexDump) MemoryHexDump(Serial, sector_buffer, sizeof(sector_buffer), false);

    fat32_boot_t * ptr1=(fat32_boot_t *) sector_buffer;
    exfat_boot_t * ptr2=(exfat_boot_t *) sector_buffer;
  
    if(strncmp(ptr1->fileSystemType,"FAT32",5)==0)
    {
      Serial.println("FAT32");
      Serial.print("bytes per sector :");Serial.println(ptr1->bytesPerSector);
      Serial.print("sectors per cluster :");Serial.println(ptr1->sectorsPerCluster);
    }
    else if(strncmp(ptr2->oem_name,"EXFAT",5)==0)
    {
      Serial.println("EXFAT");
      Serial.print("bytes per sector :");Serial.println(1<<ptr2->sector_bits);
      Serial.print("sectors per cluster :");Serial.println(1<<ptr2->spc_bits);
    }
  
    // read now Second partition sector
    Serial.println("\nSecond partition Sector");
    count = 1;
    res = disk_read (pdrv, sector_buffer, sector1, count);
    Serial.print("Disk read Result: "); Serial.println(FR_ERROR_STRING[res]);
    if(hexDump) MemoryHexDump(Serial, sector_buffer, sizeof(sector_buffer), false);

    if(strncmp(ptr1->fileSystemType,"FAT32",5)==0)
    {
      Serial.println("FAT32");
      Serial.print("bytes per sector :");Serial.println(ptr1->bytesPerSector);
      Serial.print("sectors per cluster :");Serial.println(ptr1->sectorsPerCluster);
    }
    else if(strncmp(ptr2->oem_name,"EXFAT",5)==0)
    {
      Serial.println("EXFAT");
      Serial.print("bytes per sector :");Serial.println(1<<ptr2->sector_bits);
      Serial.print("sectors per cluster :");Serial.println(1<<ptr2->spc_bits);
    }
  }

  Serial.println("Done...!");

  pinMode(13,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(13,!digitalRead(13));
  delay(1000);
}
1 Like

Great stuff!

If I remember correctly, in order to try to use partitions, you need to edit the variant file mbed_config.h

and change the line:
#define MBED_CONF_FAT_CHAN_FF_MULTI_PARTITION 0 // set by library:fat_chan

To non- zero.

Will have to play :smiley:

1 Like

Yep I forgot to mention that. I am also using LibPrintf that you can download from the library manager since it is not natively supported.

MemoryHexDump can be downloaded from: KurtE/MemoryHexDump: Simple Arduino Memory Dump (github.com)