USBHost_t36 USB Mass Storage Driver Experiments

@wwatson - I would like to start playing around some as I know these capabilities would be great addition to Teensy world.

Are the instructions up at: https://forum.pjrc.com/threads/5582...er-Experiments?p=231523&viewfull=1#post231523
Maybe the best thing to try things out?

It looks like you had a delta to usbhost_t36? has this already been folded int a Pull Request or do we need to?

Would be fun to try this stuff out, and maybe see if it can feed through to MTP...

I have been watching the development of LittleFS and MTP_T4 and at the same time working with SdFat and MSC. The driver part of MSC is now part of USBHost_t36 thanks @Paul. A lot of things have changed from the original MSC. MSC now works with Sdfat.

The first versions were:
https://forum.pjrc.com/threads/64784-Sdfat-beta-now-ported-to-USB-Mass-Storage-devices-two-ways?highlight=sdfat+ways

But as per a conversation with Bill Greiman in a post that I can't find now he did not want to modify SdFat for use with MSC. So what I have come up and still testing is this:
https://github.com/wwatson4506/UsbMscFat.

This uses SdFat and FS and does not modify SdFat in any way. It is working with both the latest SdFat and the file abstraction of FS using TD 1.54B6. This is still WIP and I have already found several issues with it that I am working on. Working with hot plugging both USB drives and SD cards and getting volume names. Initially working.

There are several examples that can be used to test this library and I am working on more of them. All that is needed is TD1.54B6 and UsbMscFat. I know that Paul is also planning to work with MSC so I really am being cautious about how much effort I put into this.

Hopefully I have not confused you:) Going back to to a double shift at work now:(

Edit: MSC still works with uSDFS.
 
Last edited:
@wwatson
Just downloaded UsbMscFat and so far examples working a couple different devices I tried - 32 thumb drive, SD Card in adapter and a SSD drive. Here some info from one of the examples:
Code:
init time: 1341 ms

Drive type: USB Drive.
msc1 Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X0,0X20,0X21,0X0,0X7,0XFE,0XFF,0XFF,2048,204800000
2,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,204802048,29634560
3,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0

Scanning FAT, please wait.

Volume is exFAT
sectorsPerCluster: 256
clusterCount:      799960
freeClusterCount:  465956
fatStartSector:    4096
dataStartSector:   12288

type any character to start
and
Code:
Type any character to start
FreeStack: 396520
Type is exFAT
Card size: 120.03 GB (GB = 1E9 bytes)
FILE_SIZE_MB = 32
BUF_SIZE = 32768 bytes
Starting write test, please wait.

write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
26214.40,1250,1250,1250
9595.31,145375,1250,3414

Starting read test, please wait.

read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
Filesize = 32768000.00
23831.27,1729,1375,1375
Filesize = 32768000.00
23831.27,1375,1368,1374

Done
 
@wwatson
Just downloaded UsbMscFat and so far examples working a couple different devices I tried - 32 thumb drive, SD Card in adapter and a SSD drive. Here some info from one of the examples:
Code:
init time: 1341 ms

Drive type: USB Drive.
msc1 Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X0,0X20,0X21,0X0,0X7,0XFE,0XFF,0XFF,2048,204800000
2,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,204802048,29634560
3,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0

Scanning FAT, please wait.

Volume is exFAT
sectorsPerCluster: 256
clusterCount:      799960
freeClusterCount:  465956
fatStartSector:    4096
dataStartSector:   12288

type any character to start
and
Code:
Type any character to start
FreeStack: 396520
Type is exFAT
Card size: 120.03 GB (GB = 1E9 bytes)
FILE_SIZE_MB = 32
BUF_SIZE = 32768 bytes
Starting write test, please wait.

write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
26214.40,1250,1250,1250
9595.31,145375,1250,3414

Starting read test, please wait.

read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
Filesize = 32768000.00
23831.27,1729,1375,1375
Filesize = 32768000.00
23831.27,1375,1368,1374

Done

Glad to see that it working. I was hoping that other people could test with there USB drives. 'mscFS.h' is an MSC version of 'SD.h' and 'littleFS.h' setup to use 'USBFat.h' which also includes 'SdFat.h'. This allows SdFat to access a USB drive as a block device. This also allows usage of SdFat with USB drives without having to modify SdFat in any way which is what Bill Greiman requested and gave me examples of how to implement it. What I have is probably not the most efficient way to do it as it is still WIP. Any ideas are very welcome.

Other than fixing obvious bugs and programming errors I am adding:

1 - Better error reporting using sense code keys, ASC (additional sense codes) and ASCQ (additional sense code qualifiers). These are working.
2 - Getting volume names. This is easy with Fat32 formatted drive. Not so much with ExFat formatted drives.
3 - Hot plugging USB drives and SD cards. This is initially working with SD cards but is just calling the begin() function to see if the SD card is still there.
- I do not think it is the proper way to do this.

One other thing I am trying to understand is how to unmount an SD card or a USB drive in SdFat.
 
I have done a little playing here with the MTP-test to add an MSC drive. I turned it off by default as you need to install the libraries mentioned here.

I also did a Pull Request to change the #define that was in conflict with other libraries: https://github.com/wwatson4506/UsbMscFat/pull/1

I was able to have AN USB drive plugged in when the program started and it showed up in the Teensy object on the PC. I was then able to drag and drop files into it which appeared to copy to the drive.
I was able to run it again with that in the drive and double click on the image I copied there and it loaded it up in photoshop :D

I am testing with MTP + serial .

Lots of interesting things to test and see what makes sense with MTP with MSC...

How do I setup multiple drives? What about partitions? How to handle them coming and going. ...

But it is fun to see some baby steps :D
 
I have done a little playing here with the MTP-test to add an MSC drive. I turned it off by default as you need to install the libraries mentioned here.

I also did a Pull Request to change the #define that was in conflict with other libraries: https://github.com/wwatson4506/UsbMscFat/pull/1

I was able to have AN USB drive plugged in when the program started and it showed up in the Teensy object on the PC. I was then able to drag and drop files into it which appeared to copy to the drive.
I was able to run it again with that in the drive and double click on the image I copied there and it loaded it up in photoshop :D

I am testing with MTP + serial .

Lots of interesting things to test and see what makes sense with MTP with MSC...

How do I setup multiple drives? What about partitions? How to handle them coming and going. ...

But it is fun to see some baby steps :D

That is awesome:) I always was wondering how to set USB mass storage devices up with MTP but never had the time to really keep up with the development.

Multiple drives are just a matter of creating another instance of msController. Obviously you will need USB HUB. If you look at the 'copyFilesUSB.ino' sketch in the examples folder you will see how that is done. This sketch is is very terse but shows how to use SD cards both SDIO and external SPI with MSC. Right now it does not use the the FS file abstraction layer but is what I needed to test UsbMSCFat with SdFat. This is a start to mixing FS and Sdfat API's. I still am trying to fully understand Sdfat and it's inner workings. There is a lot to try and understand:)

All of the example sketches in UsbMSCFat I have tried to match with SD and SdFat examples. You will notice that the filenames end in 'USB.ino'

Again, not knowing what the structure of FS, SD, littleFS and MTP will finally be and what @Paul has in mind I am going to keep fly swatting bugs in UsbMSCFat:)

Thanks KurtE

Edit: Have not played with multiple partitions yet but it is available in SdFat.
 
@KurtE - @wwatson

Not sure where to post this (kind of crosses - Integration Thread)

Anyway not sure how this would work but SDFat does have a FatPartition Class that looks like it would allow you address partitions. Not sure if @wwatson has the linkage though - need to get some sleep.

But looking at it you would need to:
Code:
#include <FatPartition.h>
and then

create an instance of FilePartion() the guess you would have to init(block device, part #);. FatFile is a friend class so you get access that way.
 
@mjs513 and @wwatson @wmxz @paul - That is why I started playing and why I started that other thread. Sometimes hard to know what is going to happen when you try to integrate several of these sub-systems.
Or some of the big questions, like do we try to get all of these libraries to optionally support Unicode?

I see the copy files sketch now which has two msc objects, so I see way to try with two, then see how partitions work...

Some of the reasons to do this including keep swatting bugs in UsbMSCFat and the like, is by doing so at minimum we can have a working system, and maybe better it gives us a good idea of what things we should try to merge back in to the version of SDFat that ships with Teensyduino.

Also trying out a few different test programs and the like helps us figure out how we might need to improve the interfaces.

Example: I keep meaning to take a diversion and maybe have an MTP/MSC/ILI9341 (or better with bigger screen) touch sketch that can maybe be used for a framework.
That maybe setup for N storage like a T4.1 with SD, MSC, LittleFS on chip...

On the display have maybe default screen that shows summary of the N storage units, with maybe showing name, total size, free space...
Maybe simple click to show some of the contents. Maybe options to format drive... And if you choose to format a drive than you want progress bar. So the '.' char passed in to low format may not be sufficient.

Now suppose someone copies a file from PC to your storage, how to you find out that something changed, as to update your display? What if this sketch also has something that generates new files, like maybe I use the CSI interface and every so often take a picture and store it. How do I tell MTP that the system changed (I added stuff already in my version)... Likewise maybe the screen code allows user to delete stuff, so need to tell MTP about this...

Likewise maybe there is a configuration file you keep in one of the stores that configures the program, like maybe what picture(s) to use a screensaver or how often to take picture... How does the sketch find out if this file changed?

...

Again it is hard to know where is the best place to post something like this. Sorry I know that a lot of this is off topic.
 
@KurtE
Was poking around SDFat and not 100% sure it directly supports multiple partitions. Why, Blockdevice* dev I believe has to point to the SDCard but doesn't appear we have access to that. Bill points to card into via sd.card()..... Can't wait to see what you come up with. Going to think about it and look at UsbMscFat.
 
As I asked in the MTP thread:

My next question to self and others maybe other thread
is to support multiple MSC drives, I was using the global object (MSC) to add the one MSC object as is in the FilesUSB object.

Thought I would try the stuff out of copyFilesUSB.ino sketch which is setup for two MSC objects which it has as msc1 and msc2.

Probably is: MSC global is of the class MSCClass
which is class MSCClass : public FS

So works to add to storage.

But: UsbFs msc1;
and: class UsbFs : public UsbBase<FsVolume> {

Which is not based on FS...

So need to figure out the relationship...
 
First attempt is to substitute MSCClass for UsbFs and it compiles and runs for 1 item...

Again hard to know if should talk about it here or MTP or...

But my MTP test code is setup now like:
Code:
#if USE_MSC_FAT > 0
#if defined(__IMXRT1062__) || defined(ARDUINO_TEENSY36)
#include <mscFS.h>
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);

// start off with one controller. 
msController msDrive[USE_MSC_FAT](myusb);
MSCClass msc[USE_MSC_FAT];

Where instead of looking for == 1 I look for > 0 and use that as count of max number to support...
Will see what happens when I put in the code to see if they exist and add both...

for the one I just have:
Code:
  Serial.print("\nInitializing USB MSC drive...");

  if (!msc[0].begin(&msDrive[0]))
    { Serial.printf("MSC Storage failed or missing"); Serial.println();
    }
    else
    {
      storage.addFilesystem(msc[0], "MSC");
      uint64_t totalSize = msc[0].totalSize();
      uint64_t usedSize  = msc[0].usedSize();
      Serial.printf("Storage MSC "); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
    return;
  }
now to loop over count and see what happens. Then next up see if your check to see if
your function in copy files:
Code:
bool driveAvailable(msController *pDrive,UsbFs *mscVol) {
	if(pDrive->checkConnectedInitialized()) {
		return false; // No USB Drive connected, give up!
	}
	if(!mscVol->fatType()) {  // USB drive present try mount it.
		if (!mscVol->begin(&msDrive1)) {
			mscVol->initErrorPrint(&Serial); // Could not mount it print reason.
			return false;
		}
	}
	return true;
}
Will work with the updated class...
 
@mjs513

Bill points to card into via sd.card().....

This is a pointer to the SD card object (driver) for a particular SD card. This is found in 'SdFat.h'. The equivalent is found in the UsbMSCFat folder 'UsbFat.h' and would be msc1.usbDrive()->. This allows access to methods in the driver layer. Here is an example of it's usage:

Code:
// Get Fat32 volume name.
bool getFat32VolumeLabel(uint8_t  drvType) {
  uint8_t buf[512];
  uint32_t rootDir = 0;
  
  if(drvType == msDrive) {
    [COLOR="#FF0000"]msc1.usbDrive()->readSector(msc1.dataStartSector(),buf);[/COLOR]
  }

  if(drvType == sdDrive) {
    rootDir =  sd.dataStartSector();
    [COLOR="#FF0000"]sd.card()->readSector(sd.dataStartSector(),buf);[/COLOR]
  }	 
  Serial.print(F("Volume Name: "));
  for (size_t i = 0; i < 11; i++) {
    Serial.write(buf[i]);
  }
  Serial.println();
  return true;
}

I have been working on getting volume names. In this case Fat32 volume names.
As stated before getting ExFat volume labels is more involved.
 
Morning @KurtE

Was trying to implement your changes and found you already implement them in the repository example so.... Using just 1 MSC object ran into a couple of problems with some devices:
1. SD Card using a Lexar adapter: Seems to set a MSC0 drive but doesn't in Windows explorer
Capture.PNG
Code:
Storage MSC0 31902400512 3833856

Setup done
CMD: 1002(OPEN_SESSION)l: 16 T:0 : 1
RESP:2001(RSP:OK)l: 16 T:0 : 1
CMD: 1001(GET_DEVICE_INFO)l: 12 T:1
RESP:2001(RSP:OK)l: 12 T:1
CMD: 1014(GET_DEVICE_PROP_DESC)l: 16 T:2 : d402
RESP:2001(RSP:OK)l: 16 T:2 : d402
CMD: 1004(GET_STORAGE_IDS)l: 12 T:3
RESP:2001(RSP:OK)l: 12 T:3
CMD: 1005(GET_STORAGE_INFO)l: 16 T:4 : 1
RESP:2001(RSP:OK)l: 16 T:4 : 1
CMD: 1005(GET_STORAGE_INFO)l: 16 T:5 : 2
RESP:2001(RSP:OK)l: 16 T:5 : 2
CMD: 1005(GET_STORAGE_INFO)l: 16 T:6 : 3
RESP:2001(RSP:OK)l: 16 T:6 : 3
CMD: 1005(GET_STORAGE_INFO)l: 16 T:7 : 4
RESP:2001(RSP:OK)l: 16 T:7 : 4
CMD: 1005(GET_STORAGE_INFO)l: 16 T:8 : 5
RESP:2001(RSP:OK)l: 16 T:8 : 5
CMD: 1005(GET_STORAGE_INFO)l: 16 T:9 : 6
RESP:2001(RSP:OK)l: 16 T:9 : 6
CMD: 1005(GET_STORAGE_INFO)l: 16 T:a : 7
RESP:2001(RSP:OK)l: 16 T:a : 7
CMD: 1005(GET_STORAGE_INFO)l: 16 T:b : 8
RESP:2001(RSP:OK)l: 16 T:b : 8
CMD: 1005(GET_STORAGE_INFO)l: 16 T:c : 9
RESP:2001(RSP:OK)l: 16 T:c : 9

2. SSD recognized in Windows explorer - as mentioned earlier.

3. Old Microcenter 2GB thumb drive - works no issues

4. Cruze Fit 32GB Thumb - same thing happens as with the 32GB SD/Lexar combo - does show data in serial monitor:

Code:
MTP_test
sd_addFilesystem: 0 20005d68 RAM1
RAM Storage 0 RAM1 199936 512
sd_addFilesystem: 1 20005e30 RAM2
RAM Storage 1 RAM2 3999744 4096
sd_addFilesystem: 2 20005ca0 PROGM
Program Storage 0 PROGM 983040 8192
sd_addFilesystem: 3 200034e4 QSPI
QSPI Storage 0 QSPI 16777216 8192
sd_addFilesystem: 4 200035b8 sflash5
SPIFlash Storage 0 5 sflash5 67108864 8192
sd_addFilesystem: 5 20003690 sflash6
SPIFlash Storage 1 6 sflash6 67108864 8192
SPIFlash Storage 2 7 prop failed or missing
Flash ID: EF AA 21
Flash size is 125.50 Mbyte
Device ID: 0xEFAA21
sd_addFilesystem: 6 200063e0 WINBOND1G
Storage 0 3 WINBOND1G 131596288 9175040
Flash ID: EF AA 22
Flash size is 253.00 Mbyte
Device ID: 0xEFAA22
sd_addFilesystem: 7 200064d0 WINBOND2G
Storage 1 4 WINBOND2G 265289728 9306112

Initializing USB MSC drives...
sd_addFilesystem: 8 200066c4 MSC0
Storage MSC0 32000016384 10393780224

Setup done

If I run mscFS SDInfo on the Lexar/SD combo:
Code:
Initializing USB MSC drive 1...
myDrive1 Info:
   connected 1
   initialized 1
   USB Vendor ID: 05dc
  USB Product ID: b051
      HUB Number: 0
        HUB Port: 0
  Device Address: 1
Removable Device: YES
        VendorID: Lexar   
       ProductID: microSD RDR     
      RevisionID: 0815
         Version: 6
    Sector Count: 62333951
     Sector size: 512
   Disk Capacity: 31914982912 Bytes

                       4364 LOG_0816.csv
                     153666 OV7670.bmp
                          0 mtpindex.dat
                       5363 datalog.txt
                         21 test1.txt
                      86201 LOG_0001.csv
                     326837 512-07.jpg
                       4303 D435 Obs-slam Links.txt
2020-06-26 15:21     121978 LOG_0000-afternno.csv
2020-06-26 17:03      65318 LOG_00001.csv
2020-06-27 09:41     183998 LOG_62620.csv
2020-11-01 09:39      34910 perf.jpg
2020-11-01 09:39      39057 squirrel_dither.jpg
2020-11-01 09:40      40582 demo.jpg
2020-11-02 00:09     289750 num3.wav
2020-11-02 00:09     260436 num4.wav
2020-11-02 00:09     276426 num5.wav
2020-11-02 00:09     260818 num6.wav
2020-11-02 00:09     300028 num1.wav
2020-11-02 00:09     266528 num2.wav

Volume type is FAT32
Cluster Size (bytes): 32768
Volume size (Kbytes): 31154688
Volume size (Mbytes): 30424

Initializing USB MSC drive 2...
initialization failed with code: 40

Just thought you should know.
 
@mjs513



This is a pointer to the SD card object (driver) for a particular SD card. This is found in 'SdFat.h'. The equivalent is found in the UsbMSCFat folder 'UsbFat.h' and would be msc1.usbDrive()->. This allows access to methods in the driver layer. Here is an example of it's usage:

Code:
// Get Fat32 volume name.
bool getFat32VolumeLabel(uint8_t  drvType) {
  uint8_t buf[512];
  uint32_t rootDir = 0;
  
  if(drvType == msDrive) {
    [COLOR="#FF0000"]msc1.usbDrive()->readSector(msc1.dataStartSector(),buf);[/COLOR]
  }

  if(drvType == sdDrive) {
    rootDir =  sd.dataStartSector();
    [COLOR="#FF0000"]sd.card()->readSector(sd.dataStartSector(),buf);[/COLOR]
  }	 
  Serial.print(F("Volume Name: "));
  for (size_t i = 0; i < 11; i++) {
    Serial.write(buf[i]);
  }
  Serial.println();
  return true;
}

I have been working on getting volume names. In this case Fat32 volume names.
As stated before getting ExFat volume labels is more involved.

Thanks - the dummy that I am. So with that ran it but I created 4 volumes 3 are FAT32 and 1 is exFAT. This is running the SDInfo without Partition info set up:
Code:
SdFat version: 2.0.5-beta.1
Assuming an SDIO interface.

type any character to start
init time: 21 ms

Card type: SDXC

Manufacturer ID: 0X3
OEM ID: SD
Product: SN128
Version: 8.0
Serial number: 0X17DCCFC4
Manufacturing date: 7/2014

cardSize: 127865.45 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true

OCR: 0XC0FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X80,0X20,0X21,0X0,0XC,0XC2,0X22,0X20,2048,524288
2,0X0,0XC2,0X23,0X20,0XC,0XFE,0XFF,0XFF,526336,65536000
3,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,66062336,65536000
4,0X0,0XFE,0XFF,0XFF,0XF,0XFE,0XFF,0XFF,131598336,118138880

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 4
clusterCount:      129024
freeClusterCount:  129020
fatStartSector:    8222
dataStartSector:   10240

Here is running through the 4 partitions (partition 4 is exFat):
Code:
SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X80,0X20,0X21,0X0,0XC,0XC2,0X22,0X20,2048,524288
2,0X0,0XC2,0X23,0X20,0XC,0XFE,0XFF,0XFF,526336,65536000
3,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,66062336,65536000
4,0X0,0XFE,0XFF,0XFF,0XF,0XFE,0XFF,0XFF,131598336,118138880

Partion 1

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 4
clusterCount:      129024
freeClusterCount:  129020
fatStartSector:    8222
dataStartSector:   10240
------------------------------- 
 
Partion 2

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 32
clusterCount:      2046976
freeClusterCount:  2046973
fatStartSector:    527118
dataStartSector:   559104
------------------------------- 
 
Partion 3

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 32
clusterCount:      2046976
freeClusterCount:  2046973
fatStartSector:    66063118
dataStartSector:   66095104
------------------------------- 
 
Partion 4

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0
--------------------------
Here is the sketch if you want to play:
Code:
/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include "SdFat.h"
#include "sdios.h"
/*
  Set DISABLE_CS_PIN to disable a second SPI device.
  For example, with the Ethernet shield, set DISABLE_CS_PIN
  to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
  Change the value of SD_CS_PIN if you are using SPI
  and your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif  // HAS_SDIO_CLASS

//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);

FatPartition Part[4];

//------------------------------------------------------------------------------
bool cidDmp() {
  cout << F("\nManufacturer ID: ");
  cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
  cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << m_cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(m_cid.mdt_month) << '/';
  cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
bool csdDmp() {
  bool eraseSingleBlock;
  if (m_csd.v1.csd_ver == 0) {
    eraseSingleBlock = m_csd.v1.erase_blk_en;
    m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
  } else if (m_csd.v2.csd_ver == 1) {
    eraseSingleBlock = m_csd.v2.erase_blk_en;
    m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
  } else {
    cout << F("m_csd version error\n");
    return false;
  }
  m_eraseSize++;
  cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
  if (sd.sdErrorCode()) {
    cout << F("SD errorCode: ") << hex << showbase;
    printSdErrorSymbol(&Serial, sd.sdErrorCode());
    cout << F(" = ") << int(sd.sdErrorCode()) << endl;
    cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
  }
}
//------------------------------------------------------------------------------
bool mbrDmp() {
  MbrSector_t mbr;
  bool valid = true;
  if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
    cout << F("\nread MBR failed.\n");
    errorPrint();
    return false;
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    MbrPart_t *pt = &mbr.part[ip - 1];
    if ((pt->boot != 0 && pt->boot != 0X80) ||
        getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
      valid = false;
    }
    cout << int(ip) << ',' << uppercase << showbase << hex;
    cout << int(pt->boot) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->beginCHS[i]) << ',';
    }
    cout << int(pt->type) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->endCHS[i]) << ',';
    }
    cout << dec << getLe32(pt->relativeSectors) << ',';
    cout << getLe32(pt->totalSectors) << endl;
  }
  if (!valid) {
    cout << F("\nMBR not valid, assuming Super Floppy format.\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void dmpVol(uint8_t i) {
  cout << F("\nScanning FAT, please wait.\n");
  uint32_t freeClusterCount = Part[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(Part[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(Part[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << Part[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << Part[i].fatStartSector() << endl;
  cout << F("dataStartSector:   ") << Part[i].dataStartSector() << endl;
  if (Part[i+1].dataStartSector() % m_eraseSize) {
    cout << F("Data area is not aligned on flash erase boundary!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }
}
//------------------------------------------------------------------------------
void printCardType() {

  cout << F("\nCard type: ");

  switch (sd.card()->type()) {
    case SD_CARD_TYPE_SD1:
      cout << F("SD1\n");
      break;

    case SD_CARD_TYPE_SD2:
      cout << F("SD2\n");
      break;

    case SD_CARD_TYPE_SDHC:
      if (sdCardCapacity(&m_csd) < 70000000) {
        cout << F("SDHC\n");
      } else {
        cout << F("SDXC\n");
      }
      break;

    default:
      cout << F("Unknown\n");
  }
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
  if (DISABLE_CS_PIN < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CS_PIN to disable an SPI device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CS_PIN) << endl;
    pinMode(DISABLE_CS_PIN, OUTPUT);
    digitalWrite(DISABLE_CS_PIN, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
  cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
  (void)config;
  cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }
  cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
  printConfig(SD_CONFIG);

}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  clearSerialInput();

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
  uint32_t t = millis();
  if (!sd.cardBegin(SD_CONFIG)) {
    cout << F(
           "\nSD initialization failed.\n"
           "Do not reformat the card!\n"
           "Is the card correctly inserted?\n"
           "Is there a wiring/soldering problem?\n");
    if (isSpi(SD_CONFIG)) {
      cout << F(
           "Is SD_CS_PIN set to the correct value?\n"
           "Does another SPI device need to be disabled?\n"
           );
    }
    errorPrint();
    return;
  }
  t = millis() - t;
  cout << F("init time: ") << t << " ms" << endl;

  if (!sd.card()->readCID(&m_cid) ||
      !sd.card()->readCSD(&m_csd) ||
      !sd.card()->readOCR(&m_ocr)) {
    cout << F("readInfo failed\n");
    errorPrint();
    return;
  }
  printCardType();
  cidDmp();
  csdDmp();
  cout << F("\nOCR: ") << uppercase << showbase;
  cout << hex << m_ocr << dec << endl;
  if (!mbrDmp()) {
    return;
  }
  if (!sd.volumeBegin()) {
    cout << F("\nvolumeBegin failed. Is the card formatted?\n");
    errorPrint();
    return;
  }
  for(uint8_t i = 0; i <4; i++){
    cout << F("\nPartion ") << (int) i+1 << F("\n");
    Part[i].init(sd.card(), (int) i+1);
    dmpVol(i);
    cout << F("------------------------------- \n ");
  }
}
 
Thanks - the dummy that I am. So with that ran it but I created 4 volumes 3 are FAT32 and 1 is exFAT. This is running the SDInfo without Partition info set up:
Code:
SdFat version: 2.0.5-beta.1
Assuming an SDIO interface.

type any character to start
init time: 21 ms

Card type: SDXC

Manufacturer ID: 0X3
OEM ID: SD
Product: SN128
Version: 8.0
Serial number: 0X17DCCFC4
Manufacturing date: 7/2014

cardSize: 127865.45 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true

OCR: 0XC0FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X80,0X20,0X21,0X0,0XC,0XC2,0X22,0X20,2048,524288
2,0X0,0XC2,0X23,0X20,0XC,0XFE,0XFF,0XFF,526336,65536000
3,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,66062336,65536000
4,0X0,0XFE,0XFF,0XFF,0XF,0XFE,0XFF,0XFF,131598336,118138880

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 4
clusterCount:      129024
freeClusterCount:  129020
fatStartSector:    8222
dataStartSector:   10240

Here is running through the 4 partitions (partition 4 is exFat):
Code:
SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X80,0X20,0X21,0X0,0XC,0XC2,0X22,0X20,2048,524288
2,0X0,0XC2,0X23,0X20,0XC,0XFE,0XFF,0XFF,526336,65536000
3,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,66062336,65536000
4,0X0,0XFE,0XFF,0XFF,0XF,0XFE,0XFF,0XFF,131598336,118138880

Partion 1

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 4
clusterCount:      129024
freeClusterCount:  129020
fatStartSector:    8222
dataStartSector:   10240
------------------------------- 
 
Partion 2

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 32
clusterCount:      2046976
freeClusterCount:  2046973
fatStartSector:    527118
dataStartSector:   559104
------------------------------- 
 
Partion 3

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 32
clusterCount:      2046976
freeClusterCount:  2046973
fatStartSector:    66063118
dataStartSector:   66095104
------------------------------- 
 
Partion 4

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0
--------------------------
Here is the sketch if you want to play:
Code:
/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include "SdFat.h"
#include "sdios.h"
/*
  Set DISABLE_CS_PIN to disable a second SPI device.
  For example, with the Ethernet shield, set DISABLE_CS_PIN
  to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
  Change the value of SD_CS_PIN if you are using SPI
  and your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif  // HAS_SDIO_CLASS

//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);

FatPartition Part[4];

//------------------------------------------------------------------------------
bool cidDmp() {
  cout << F("\nManufacturer ID: ");
  cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
  cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << m_cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(m_cid.mdt_month) << '/';
  cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
bool csdDmp() {
  bool eraseSingleBlock;
  if (m_csd.v1.csd_ver == 0) {
    eraseSingleBlock = m_csd.v1.erase_blk_en;
    m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
  } else if (m_csd.v2.csd_ver == 1) {
    eraseSingleBlock = m_csd.v2.erase_blk_en;
    m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
  } else {
    cout << F("m_csd version error\n");
    return false;
  }
  m_eraseSize++;
  cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
  if (sd.sdErrorCode()) {
    cout << F("SD errorCode: ") << hex << showbase;
    printSdErrorSymbol(&Serial, sd.sdErrorCode());
    cout << F(" = ") << int(sd.sdErrorCode()) << endl;
    cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
  }
}
//------------------------------------------------------------------------------
bool mbrDmp() {
  MbrSector_t mbr;
  bool valid = true;
  if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
    cout << F("\nread MBR failed.\n");
    errorPrint();
    return false;
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    MbrPart_t *pt = &mbr.part[ip - 1];
    if ((pt->boot != 0 && pt->boot != 0X80) ||
        getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
      valid = false;
    }
    cout << int(ip) << ',' << uppercase << showbase << hex;
    cout << int(pt->boot) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->beginCHS[i]) << ',';
    }
    cout << int(pt->type) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->endCHS[i]) << ',';
    }
    cout << dec << getLe32(pt->relativeSectors) << ',';
    cout << getLe32(pt->totalSectors) << endl;
  }
  if (!valid) {
    cout << F("\nMBR not valid, assuming Super Floppy format.\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void dmpVol(uint8_t i) {
  cout << F("\nScanning FAT, please wait.\n");
  uint32_t freeClusterCount = Part[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(Part[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(Part[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << Part[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << Part[i].fatStartSector() << endl;
  cout << F("dataStartSector:   ") << Part[i].dataStartSector() << endl;
  if (Part[i+1].dataStartSector() % m_eraseSize) {
    cout << F("Data area is not aligned on flash erase boundary!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }
}
//------------------------------------------------------------------------------
void printCardType() {

  cout << F("\nCard type: ");

  switch (sd.card()->type()) {
    case SD_CARD_TYPE_SD1:
      cout << F("SD1\n");
      break;

    case SD_CARD_TYPE_SD2:
      cout << F("SD2\n");
      break;

    case SD_CARD_TYPE_SDHC:
      if (sdCardCapacity(&m_csd) < 70000000) {
        cout << F("SDHC\n");
      } else {
        cout << F("SDXC\n");
      }
      break;

    default:
      cout << F("Unknown\n");
  }
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
  if (DISABLE_CS_PIN < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CS_PIN to disable an SPI device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CS_PIN) << endl;
    pinMode(DISABLE_CS_PIN, OUTPUT);
    digitalWrite(DISABLE_CS_PIN, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
  cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
  (void)config;
  cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }
  cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
  printConfig(SD_CONFIG);

}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  clearSerialInput();

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
  uint32_t t = millis();
  if (!sd.cardBegin(SD_CONFIG)) {
    cout << F(
           "\nSD initialization failed.\n"
           "Do not reformat the card!\n"
           "Is the card correctly inserted?\n"
           "Is there a wiring/soldering problem?\n");
    if (isSpi(SD_CONFIG)) {
      cout << F(
           "Is SD_CS_PIN set to the correct value?\n"
           "Does another SPI device need to be disabled?\n"
           );
    }
    errorPrint();
    return;
  }
  t = millis() - t;
  cout << F("init time: ") << t << " ms" << endl;

  if (!sd.card()->readCID(&m_cid) ||
      !sd.card()->readCSD(&m_csd) ||
      !sd.card()->readOCR(&m_ocr)) {
    cout << F("readInfo failed\n");
    errorPrint();
    return;
  }
  printCardType();
  cidDmp();
  csdDmp();
  cout << F("\nOCR: ") << uppercase << showbase;
  cout << hex << m_ocr << dec << endl;
  if (!mbrDmp()) {
    return;
  }
  if (!sd.volumeBegin()) {
    cout << F("\nvolumeBegin failed. Is the card formatted?\n");
    errorPrint();
    return;
  }
  for(uint8_t i = 0; i <4; i++){
    cout << F("\nPartion ") << (int) i+1 << F("\n");
    Part[i].init(sd.card(), (int) i+1);
    dmpVol(i);
    cout << F("------------------------------- \n ");
  }
}

Thanks @mjs513 - I most certainly want to play:)

I just finished up the last of my honey do's and got my wife off to work. You guys amaze me with how fast you can figure out this stuff and program.

Anyway, I have a little bit of time to play before dinner and zzzzz's.

Thanks again
 
Last edited:
@mjs13 - I modified the sketch to show info about the ExFat partition. ExFat is treated differently than Fat32. With the sketch you provided partition 4 was showing this:
Code:
Partition 4

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0
--------------------------

Which is is not being recognized by:
Code:
FatPartition Part[4];

For ExFat partitions you need to use:
Code:
ExFatPartition ExPart[4];

Also:
Code:
dataStartSector()
Is not used with ExFat:( This I discovered when I was trying get the volume name from an ExFat formatted volume. ExFat works differently than Fat32 in a lot of ways.

I modified the sketch (shown in red):
Code:
/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include "SdFat.h"
#include "sdios.h"
/*
  Set DISABLE_CS_PIN to disable a second SPI device.
  For example, with the Ethernet shield, set DISABLE_CS_PIN
  to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
  Change the value of SD_CS_PIN if you are using SPI
  and your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif  // HAS_SDIO_CLASS

//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);

FatPartition Part[4];
[COLOR="#FF0000"]ExFatPartition ExPart[4];[/COLOR]

//------------------------------------------------------------------------------
bool cidDmp() {
  cout << F("\nManufacturer ID: ");
  cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
  cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << m_cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(m_cid.mdt_month) << '/';
  cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
bool csdDmp() {
  bool eraseSingleBlock;
  if (m_csd.v1.csd_ver == 0) {
    eraseSingleBlock = m_csd.v1.erase_blk_en;
    m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
  } else if (m_csd.v2.csd_ver == 1) {
    eraseSingleBlock = m_csd.v2.erase_blk_en;
    m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
  } else {
    cout << F("m_csd version error\n");
    return false;
  }
  m_eraseSize++;
  cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
  if (sd.sdErrorCode()) {
    cout << F("SD errorCode: ") << hex << showbase;
    printSdErrorSymbol(&Serial, sd.sdErrorCode());
    cout << F(" = ") << int(sd.sdErrorCode()) << endl;
    cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
  }
}
//------------------------------------------------------------------------------
bool mbrDmp() {
  MbrSector_t mbr;
  bool valid = true;
  if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
    cout << F("\nread MBR failed.\n");
    errorPrint();
    return false;
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    MbrPart_t *pt = &mbr.part[ip - 1];
    if ((pt->boot != 0 && pt->boot != 0X80) ||
        getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
      valid = false;
    }
    cout << int(ip) << ',' << uppercase << showbase << hex;
    cout << int(pt->boot) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->beginCHS[i]) << ',';
    }
    cout << int(pt->type) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->endCHS[i]) << ',';
    }
    cout << dec << getLe32(pt->relativeSectors) << ',';
    cout << getLe32(pt->totalSectors) << endl;
  }
  if (!valid) {
    cout << F("\nMBR not valid, assuming Super Floppy format.\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void dmpVol(uint8_t i) {
  cout << F("\nScanning FAT, please wait.\n");
  uint32_t freeClusterCount = Part[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(Part[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(Part[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << Part[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << Part[i].fatStartSector() << endl;
  cout << F("dataStartSector:   ") << Part[i].dataStartSector() << endl;
  if (Part[i+1].dataStartSector() % m_eraseSize) {
    cout << F("Data area is not aligned on flash erase boundary!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }
}
[COLOR="#FF0000"]//------------------------------------------------------------------------------
void dmpExVol(uint8_t i) {
  cout << F("\nScanning FAT, please wait.\n");
  uint32_t freeClusterCount = Part[i].freeClusterCount();
  if (ExPart[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(ExPart[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(ExPart[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << ExPart[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << ExPart[i].fatStartSector() << endl;
//  cout << F("dataStartSector:   ") << ExPart[i].dataStartSector() << endl;
//  if (ExPart[i+1].dataStartSector() % m_eraseSize) {
//    cout << F("Data area is not aligned on flash erase boundary!\n");
//    cout << F("Download and use formatter from www.sdcard.org!\n");
//  }
}[/COLOR]
//------------------------------------------------------------------------------
void printCardType() {

  cout << F("\nCard type: ");

  switch (sd.card()->type()) {
    case SD_CARD_TYPE_SD1:
      cout << F("SD1\n");
      break;

    case SD_CARD_TYPE_SD2:
      cout << F("SD2\n");
      break;

    case SD_CARD_TYPE_SDHC:
      if (sdCardCapacity(&m_csd) < 70000000) {
        cout << F("SDHC\n");
      } else {
        cout << F("SDXC\n");
      }
      break;

    default:
      cout << F("Unknown\n");
  }
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
  if (DISABLE_CS_PIN < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CS_PIN to disable an SPI device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CS_PIN) << endl;
    pinMode(DISABLE_CS_PIN, OUTPUT);
    digitalWrite(DISABLE_CS_PIN, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
  cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
  (void)config;
  cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }
  cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
  printConfig(SD_CONFIG);

}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  clearSerialInput();

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
  uint32_t t = millis();
  if (!sd.cardBegin(SD_CONFIG)) {
    cout << F(
           "\nSD initialization failed.\n"
           "Do not reformat the card!\n"
           "Is the card correctly inserted?\n"
           "Is there a wiring/soldering problem?\n");
    if (isSpi(SD_CONFIG)) {
      cout << F(
           "Is SD_CS_PIN set to the correct value?\n"
           "Does another SPI device need to be disabled?\n"
           );
    }
    errorPrint();
    return;
  }
  t = millis() - t;
  cout << F("init time: ") << t << " ms" << endl;

  if (!sd.card()->readCID(&m_cid) ||
      !sd.card()->readCSD(&m_csd) ||
      !sd.card()->readOCR(&m_ocr)) {
    cout << F("readInfo failed\n");
    errorPrint();
    return;
  }
  printCardType();
  cidDmp();
  csdDmp();
  cout << F("\nOCR: ") << uppercase << showbase;
  cout << hex << m_ocr << dec << endl;
  if (!mbrDmp()) {
    return;
  }
  if (!sd.volumeBegin()) {
    cout << F("\nvolumeBegin failed. Is the card formatted?\n");
    errorPrint();
    return;
  }
  for(uint8_t i = 0; i <4; i++){
    cout << F("\nPartion ") << (int) i+1 << F("\n");
[COLOR="#FF0000"]    if(i == 3) {
		ExPart[i].init(sd.card(), (int) i+1);
		dmpExVol(i);
	} else {
		Part[i].init(sd.card(), (int) i+1);
		dmpVol(i);
	}[/COLOR]
    cout << F("------------------------------- \n ");
  }
}

Shows this for partition 4:
Code:
Partion 4

Scanning FAT, please wait.

Volume is exFAT
sectorsPerCluster: 64
clusterCount:      222722
freeClusterCount:  4294967295
fatStartSector:    46835840
-------------------------------
:
 
Last edited:
@wwatson
Thanks for the changes will play more with it tomorrow. May try to do a list files but intent really was to see if and how to get access via sdfat. But the use of sd.card was the key
 
@wwatson
Thanks for the changes will play more with it tomorrow. May try to do a list files but intent really was to see if and how to get access via sdfat. But the use of sd.card was the key

You are welcome. I want to do the same with MSC and UbFat.During the week I do not have much time to play with this but with taxes being done next weekend is MINE:)
 
Taxes - yep - already did mine.

Anyway get the volume directory was relative easy.
Code:
SdFat version: 2.0.5-beta.1
Assuming an SDIO interface.

type any character to start
init time: 22 ms

Card type: SDXC

Manufacturer ID: 0X3
OEM ID: SD
Product: SN128
Version: 8.0
Serial number: 0X17DCCFC4
Manufacturing date: 7/2014

cardSize: 127865.45 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true

OCR: 0XC0FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X80,0X20,0X21,0X0,0XC,0XC2,0X22,0X20,2048,524288
2,0X0,0XC2,0X23,0X20,0XC,0XFE,0XFF,0XFF,526336,65536000
3,0X0,0XFE,0XFF,0XFF,0XC,0XFE,0XFF,0XFF,66062336,65536000
4,0X0,0XFE,0XFF,0XFF,0XF,0XFE,0XFF,0XFF,131598336,118138880
swampy.pdf
The-Design-and-Implementation-of-a-Robust-AHRS-for-Implementation-on-a-Quadrotor.pdf

Partion 1

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 4
clusterCount:      129024
freeClusterCount:  124192
fatStartSector:    8222
dataStartSector:   10240

Volume Directory:      
swampy.pdf
The-Design-and-Implementation-of-a-Robust-AHRS-for-Implementation-on-a-Quadrotor.pdf
------------------------------- 
 
Partion 2

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 32
clusterCount:      2046976
freeClusterCount:  2046882
fatStartSector:    527118
dataStartSector:   559104

Volume Directory:      
Visio-driver.pdf
------------------------------- 
 
Partion 3

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 32
clusterCount:      2046976
freeClusterCount:  2046622
fatStartSector:    66063118
dataStartSector:   66095104

Volume Directory:      
VSLAM_and_Navigation_System_of_Unmanned_Ground_Vehicle_Based_on_RGB-D_Camera.pdf
------------------------------- 
 
Partion 4

Scanning exFAT, please wait.

Volume is FAT0
sectorsPerCluster: 1
clusterCount:      0
freeClusterCount:  4294967290
fatStartSector:    0

Volume Directory:      
------------------------------- 
 
type any character to start
Still having problems with that exFat directory.

Code:
/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include "SdFat.h"
#include "sdios.h"
/*
  Set DISABLE_CS_PIN to disable a second SPI device.
  For example, with the Ethernet shield, set DISABLE_CS_PIN
  to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
  Change the value of SD_CS_PIN if you are using SPI
  and your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif  // HAS_SDIO_CLASS

//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);

FatPartition Part[4];
ExFatPartition ExPart[4];
[COLOR="#FF0000"]FatVolume partVol;
ExFatVolume expartVol;[/COLOR]

//------------------------------------------------------------------------------
bool cidDmp() {
  cout << F("\nManufacturer ID: ");
  cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
  cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << m_cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(m_cid.mdt_month) << '/';
  cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
bool csdDmp() {
  bool eraseSingleBlock;
  if (m_csd.v1.csd_ver == 0) {
    eraseSingleBlock = m_csd.v1.erase_blk_en;
    m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
  } else if (m_csd.v2.csd_ver == 1) {
    eraseSingleBlock = m_csd.v2.erase_blk_en;
    m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
  } else {
    cout << F("m_csd version error\n");
    return false;
  }
  m_eraseSize++;
  cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
  if (sd.sdErrorCode()) {
    cout << F("SD errorCode: ") << hex << showbase;
    printSdErrorSymbol(&Serial, sd.sdErrorCode());
    cout << F(" = ") << int(sd.sdErrorCode()) << endl;
    cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
  }
}
//------------------------------------------------------------------------------
bool mbrDmp() {
  MbrSector_t mbr;
  bool valid = true;
  if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
    cout << F("\nread MBR failed.\n");
    errorPrint();
    return false;
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    MbrPart_t *pt = &mbr.part[ip - 1];
    if ((pt->boot != 0 && pt->boot != 0X80) ||
        getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
      valid = false;
    }
    cout << int(ip) << ',' << uppercase << showbase << hex;
    cout << int(pt->boot) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->beginCHS[i]) << ',';
    }
    cout << int(pt->type) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->endCHS[i]) << ',';
    }
    cout << dec << getLe32(pt->relativeSectors) << ',';
    cout << getLe32(pt->totalSectors) << endl;
  }
  if (!valid) {
    cout << F("\nMBR not valid, assuming Super Floppy format.\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void dmpVol(uint8_t i) {
  cout << F("\nScanning FAT, please wait.\n");
  uint32_t freeClusterCount = Part[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(Part[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(Part[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << Part[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << Part[i].fatStartSector() << endl;
  cout << F("dataStartSector:   ") << Part[i].dataStartSector() << endl;
  if (Part[i].dataStartSector() % m_eraseSize) {
    cout << F("Data area is not aligned on flash erase boundary!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }

[COLOR="#FF0000"]  cout << F("\nVolume Directory:      ") <<endl;
  partVol.begin(sd.card(), true, i+1);
  partVol.chvol();
  partVol.ls("/", LS_R);[/COLOR]
  
  
}
//------------------------------------------------------------------------------
void dmpExVol(uint8_t i) {
  cout << F("\nScanning exFAT, please wait.\n");
  uint32_t freeClusterCount = ExPart[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(ExPart[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(ExPart[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << ExPart[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << ExPart[i].fatStartSector() << endl;
//  cout << F("dataStartSector:   ") << ExPart[i].dataStartSector() << endl;
//  if (ExPart[i+1].dataStartSector() % m_eraseSize) {
//    cout << F("Data area is not aligned on flash erase boundary!\n");
//    cout << F("Download and use formatter from www.sdcard.org!\n");
//  }
[COLOR="#B22222"]  cout << F("\nVolume Directory:      ") <<endl;
  expartVol.begin(sd.card(), true, i+1);
  expartVol.chvol();
  expartVol.ls("/", LS_R);[/COLOR]

}
//------------------------------------------------------------------------------
void printCardType() {

  cout << F("\nCard type: ");

  switch (sd.card()->type()) {
    case SD_CARD_TYPE_SD1:
      cout << F("SD1\n");
      break;

    case SD_CARD_TYPE_SD2:
      cout << F("SD2\n");
      break;

    case SD_CARD_TYPE_SDHC:
      if (sdCardCapacity(&m_csd) < 70000000) {
        cout << F("SDHC\n");
      } else {
        cout << F("SDXC\n");
      }
      break;

    default:
      cout << F("Unknown\n");
  }
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
  if (DISABLE_CS_PIN < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CS_PIN to disable an SPI device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CS_PIN) << endl;
    pinMode(DISABLE_CS_PIN, OUTPUT);
    digitalWrite(DISABLE_CS_PIN, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
  cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
  (void)config;
  cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }
  cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
  printConfig(SD_CONFIG);

}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  clearSerialInput();

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
  uint32_t t = millis();
  if (!sd.cardBegin(SD_CONFIG)) {
    cout << F(
           "\nSD initialization failed.\n"
           "Do not reformat the card!\n"
           "Is the card correctly inserted?\n"
           "Is there a wiring/soldering problem?\n");
    if (isSpi(SD_CONFIG)) {
      cout << F(
           "Is SD_CS_PIN set to the correct value?\n"
           "Does another SPI device need to be disabled?\n"
           );
    }
    errorPrint();
    return;
  }
  t = millis() - t;
  cout << F("init time: ") << t << " ms" << endl;

  if (!sd.card()->readCID(&m_cid) ||
      !sd.card()->readCSD(&m_csd) ||
      !sd.card()->readOCR(&m_ocr)) {
    cout << F("readInfo failed\n");
    errorPrint();
    return;
  }
  printCardType();
  cidDmp();
  csdDmp();
  cout << F("\nOCR: ") << uppercase << showbase;
  cout << hex << m_ocr << dec << endl;
  if (!mbrDmp()) {
    return;
  }
  if (!sd.volumeBegin()) {
    cout << F("\nvolumeBegin failed. Is the card formatted?\n");
    errorPrint();
    return;
  }
  sd.ls("/", LS_R);
  
  for(uint8_t i = 0; i <4; i++){
    cout << F("\nPartion ") << (int) i+1 << F("\n");
    if(i == 3) {
    ExPart[i].init(sd.card(), (int) i+1);
    dmpExVol(i);
  } else {
    Part[i].init(sd.card(), (int) i+1);
    dmpVol(i);
  }
    cout << F("------------------------------- \n ");
  }
}
 
Last edited:
@mjs513 @wwatson - looks like you are having some fun. Now to figure out how to integrate this with MTP :D I was happy yesterday to be able to plug in USB drive and it shows up and unplug it and it goes away...
Now probably need to figure out how volumes fit in.
 
@...

@mjs513 - tried you sketch above with a few cards. And it looks like it dumps lots of interesting info...

Tried reformat 32gb SD to exFat. As you mentioned not able to read that data (yet)...

Side question, wondering how hard it is to get the Volume Label? Will play around some.

If we can get it also wondering if we should pass that on through to MTP... Currently is is always passing null string:
writestring(""); // volume identifier

Now back to more playing!
 
For the fun of it, I thought I would see if I could get it to read an ExFat one...

I think this one sort of works for it. Probably a real hack, but...

When you are dumping out the top partition table, I keep the type values:
Code:
uint8_t partition_types[4];
...
    cout << int(pt->type) << ',';
    ////////////////////////////
    partition_types[ip-1] = pt->type;

And then when you decide to dump each partition I do:
Code:
  for (uint8_t i = 0; i < 4; i++) {
    cout << F("\nPartion ") << (int) i + 1 << F("\n");
    ////////////////////////////
    if (partition_types[i] == 7) {
      ExPart[i].init(sd.card(), (int) i + 1);
      dmpExVol(i);
    } else {
      Part[i].init(sd.card(), (int) i + 1);
      dmpVol(i);
    }
    cout << F("------------------------------- \n ");
  }
As I believe Fat types are like:
Code:
6=Fat16
7=ExFat
C=Fat32
Probably others, I think B is an old Fat32...
Edit: Some of this data from: https://www.win.tue.nl/~aeb/partitions/partition_types-1.html

Here is a ExFat card I setup:
Code:
init time: 8 ms

Card type: SDHC

Manufacturer ID: 0X1B
OEM ID: SM
Product: GB2MW
Version: 3.0
Serial number: 0X275361AC
Manufacturing date: 7/2011

cardSize: 32026.66 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true

OCR: 0XC0FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X0,0X82,0X3,0X0,0X7,0XFE,0XFF,0XFF,8192,62543872
2,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
3,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
2021-02-22 06:44        32768 System Volume Information/
  2021-02-22 06:44           12 WPSettings.dat
  2021-02-22 06:44           76 IndexerVolumeGuid
2021-01-24 06:23       393481 T4.1-Cardlike.jpg
2021-01-13 17:56       340510 T4-Cardlike.jpg
2010-03-22 07:11      3373255 DSC03355.JPG
                           21 test1.txt
                            0 mtpindex.dat

Partion 1

Scanning exFAT, please wait.

Volume is FAT64
sectorsPerCluster: 64
clusterCount:      977088
freeClusterCount:  976950
fatStartSector:    10240

Volume Directory:      
2021-02-22 06:44        32768 System Volume Information/
  2021-02-22 06:44           12 WPSettings.dat
  2021-02-22 06:44           76 IndexerVolumeGuid
2021-01-24 06:23       393481 T4.1-Cardlike.jpg
2021-01-13 17:56       340510 T4-Cardlike.jpg
2010-03-22 07:11      3373255 DSC03355.JPG
                           21 test1.txt
                            0 mtpindex.dat
------------------------------- 
 
Partion 2

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0

Volume Directory:      
------------------------------- 
 
Partion 3

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0

Volume Directory:      
------------------------------- 
 
Partion 4

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0

Volume Directory:      
------------------------------- 
 
type any character to start

and a simple Fat16...
Code:
init time: 61 ms

Card type: SD2

Manufacturer ID: 0X3
OEM ID: SD
Product: SU01G
Version: 8.0
Serial number: 0X750B2400
Manufacturing date: 1/2007

cardSize: 1015.81 MB (MB = 1,000,000 bytes)
flashEraseSize: 32 blocks
eraseSingleBlock: true

OCR: 0X80FF8000

SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X0,0X3,0X3D,0X0,0X6,0X4,0XC4,0XD8,249,1983751
2,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
3,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
2021-02-21 11:37          0 System Volume Information/
  2021-02-21 11:37         12 WPSettings.dat
  2021-02-21 11:37         76 IndexerVolumeGuid
2021-01-24 06:23     393481 T4.1-Cardlike.jpg
                         21 test1.txt
                          0 mtpindex.dat

Partion 1

Scanning FAT, please wait.

Volume is FAT16
sectorsPerCluster: 32
clusterCount:      61976
freeClusterCount:  61945
fatStartSector:    250
dataStartSector:   768

Volume Directory:      
2021-02-21 11:37          0 System Volume Information/
  2021-02-21 11:37         12 WPSettings.dat
  2021-02-21 11:37         76 IndexerVolumeGuid
2021-01-24 06:23     393481 T4.1-Cardlike.jpg
                         21 test1.txt
                          0 mtpindex.dat
------------------------------- 
 
Partion 2

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0

Volume Directory:      
------------------------------- 
 
Partion 3

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0

Volume Directory:      
------------------------------- 
 
Partion 4

Scanning FAT, please wait.

Volume is FAT0
sectorsPerCluster: 0
clusterCount:      4294967295
freeClusterCount:  4294967295
fatStartSector:    0
dataStartSector:   0

Volume Directory:      
------------------------------- 
 
type any character to start


Code:
/*
   This program attempts to initialize an SD card and analyze its structure.
*/
#include "SdFat.h"
#include "sdios.h"
/*
  Set DISABLE_CS_PIN to disable a second SPI device.
  For example, with the Ethernet shield, set DISABLE_CS_PIN
  to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
  Change the value of SD_CS_PIN if you are using SPI
  and your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16))
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(16))
#endif  // HAS_SDIO_CLASS

//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);
uint8_t partition_types[4];
FatPartition Part[4];
ExFatPartition ExPart[4];
FatVolume partVol;
ExFatVolume expartVol;

//------------------------------------------------------------------------------
bool cidDmp() {
  cout << F("\nManufacturer ID: ");
  cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
  cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << m_cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(m_cid.mdt_month) << '/';
  cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
bool csdDmp() {
  bool eraseSingleBlock;
  if (m_csd.v1.csd_ver == 0) {
    eraseSingleBlock = m_csd.v1.erase_blk_en;
    m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
  } else if (m_csd.v2.csd_ver == 1) {
    eraseSingleBlock = m_csd.v2.erase_blk_en;
    m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
  } else {
    cout << F("m_csd version error\n");
    return false;
  }
  m_eraseSize++;
  cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
  if (sd.sdErrorCode()) {
    cout << F("SD errorCode: ") << hex << showbase;
    printSdErrorSymbol(&Serial, sd.sdErrorCode());
    cout << F(" = ") << int(sd.sdErrorCode()) << endl;
    cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
  }
}
//------------------------------------------------------------------------------
bool mbrDmp() {
  MbrSector_t mbr;
  bool valid = true;
  if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
    cout << F("\nread MBR failed.\n");
    errorPrint();
    return false;
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    MbrPart_t *pt = &mbr.part[ip - 1];
    if ((pt->boot != 0 && pt->boot != 0X80) ||
        getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
      valid = false;
    }
    cout << int(ip) << ',' << uppercase << showbase << hex;
    cout << int(pt->boot) << ',';
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->beginCHS[i]) << ',';
    }
    cout << int(pt->type) << ',';
    ////////////////////////////
    partition_types[ip-1] = pt->type;
    for (int i = 0; i < 3; i++ ) {
      cout << int(pt->endCHS[i]) << ',';
    }
    cout << dec << getLe32(pt->relativeSectors) << ',';
    cout << getLe32(pt->totalSectors) << endl;
  }
  if (!valid) {
    cout << F("\nMBR not valid, assuming Super Floppy format.\n");
  }
  return true;
}
//------------------------------------------------------------------------------
void dmpVol(uint8_t i) {
  cout << F("\nScanning FAT, please wait.\n");
  uint32_t freeClusterCount = Part[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(Part[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(Part[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << Part[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << Part[i].fatStartSector() << endl;
  cout << F("dataStartSector:   ") << Part[i].dataStartSector() << endl;
  if (Part[i].dataStartSector() % m_eraseSize) {
    cout << F("Data area is not aligned on flash erase boundary!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }

  cout << F("\nVolume Directory:      ") << endl;
  partVol.begin(sd.card(), true, i + 1);
  partVol.chvol();
  partVol.ls("/", LS_R | LS_DATE | LS_SIZE | LS_A);


}
//------------------------------------------------------------------------------
void dmpExVol(uint8_t i) {
  cout << F("\nScanning exFAT, please wait.\n");
  uint32_t freeClusterCount = ExPart[i].freeClusterCount();
  if (Part[i].fatType() <= 32) {
    cout << F("\nVolume is FAT") << int(ExPart[i].fatType()) << endl;
  } else {
    cout << F("\nVolume is exFAT\n");
  }
  cout << F("sectorsPerCluster: ") << int(ExPart[i].sectorsPerCluster()) << endl;
  cout << F("clusterCount:      ") << ExPart[i].clusterCount() << endl;
  cout << F("freeClusterCount:  ") << freeClusterCount << endl;
  cout << F("fatStartSector:    ") << ExPart[i].fatStartSector() << endl;
  //  cout << F("dataStartSector:   ") << ExPart[i].dataStartSector() << endl;
  //  if (ExPart[i+1].dataStartSector() % m_eraseSize) {
  //    cout << F("Data area is not aligned on flash erase boundary!\n");
  //    cout << F("Download and use formatter from www.sdcard.org!\n");
  //  }
  cout << F("\nVolume Directory:      ") << endl;
  expartVol.begin(sd.card(), true, i + 1);
  expartVol.chvol();
  expartVol.ls("/", LS_R | LS_DATE | LS_SIZE | LS_A);

}
//------------------------------------------------------------------------------
void printCardType() {

  cout << F("\nCard type: ");

  switch (sd.card()->type()) {
    case SD_CARD_TYPE_SD1:
      cout << F("SD1\n");
      break;

    case SD_CARD_TYPE_SD2:
      cout << F("SD2\n");
      break;

    case SD_CARD_TYPE_SDHC:
      if (sdCardCapacity(&m_csd) < 70000000) {
        cout << F("SDHC\n");
      } else {
        cout << F("SDXC\n");
      }
      break;

    default:
      cout << F("Unknown\n");
  }
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
  if (DISABLE_CS_PIN < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CS_PIN to disable an SPI device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CS_PIN) << endl;
    pinMode(DISABLE_CS_PIN, OUTPUT);
    digitalWrite(DISABLE_CS_PIN, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
  cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
  (void)config;
  cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }
  cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
  printConfig(SD_CONFIG);

}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  clearSerialInput();

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
  uint32_t t = millis();
  if (!sd.cardBegin(SD_CONFIG)) {
    cout << F(
           "\nSD initialization failed.\n"
           "Do not reformat the card!\n"
           "Is the card correctly inserted?\n"
           "Is there a wiring/soldering problem?\n");
    if (isSpi(SD_CONFIG)) {
      cout << F(
             "Is SD_CS_PIN set to the correct value?\n"
             "Does another SPI device need to be disabled?\n"
           );
    }
    errorPrint();
    return;
  }
  t = millis() - t;
  cout << F("init time: ") << t << " ms" << endl;

  if (!sd.card()->readCID(&m_cid) ||
      !sd.card()->readCSD(&m_csd) ||
      !sd.card()->readOCR(&m_ocr)) {
    cout << F("readInfo failed\n");
    errorPrint();
    return;
  }
  printCardType();
  cidDmp();
  csdDmp();
  cout << F("\nOCR: ") << uppercase << showbase;
  cout << hex << m_ocr << dec << endl;
  if (!mbrDmp()) {
    return;
  }
  if (!sd.volumeBegin()) {
    cout << F("\nvolumeBegin failed. Is the card formatted?\n");
    errorPrint();
    return;
  }
  sd.ls("/", LS_R | LS_DATE | LS_SIZE | LS_A);

  for (uint8_t i = 0; i < 4; i++) {
    cout << F("\nPartion ") << (int) i + 1 << F("\n");
    ////////////////////////////
    if (partition_types[i] == 7) {
      ExPart[i].init(sd.card(), (int) i + 1);
      dmpExVol(i);
    } else {
      Part[i].init(sd.card(), (int) i + 1);
      dmpVol(i);
    }
    cout << F("------------------------------- \n ");
  }
}

Again I know a real hack!
 
Last edited:
@KurtE
Sorry for the delay in responding. Was busy playing and watching more snow fall :(

Any tried to modify formatter but haven't broken the code on that one and wound up messing up my partitions on the sd card :(

Anyway did try the Buffered print example but modified to write on either fat or extFAT. Can confirm that it can be done - will post that one shortly

But I do see you used @wwatson's modified version to get to exfat. Going to try and play with that a bit more as well. Not a real hack - but only way to do it since SD cards really weren't meant to have partitions :)
 
@KurtE - @wwatson
Decided to play around with the BufferedPrint example to see what it takes to write and read files from the partitions. Did manage to create 3 partitions that I can test with;
Code:
SD Partition Table
part,boot,bgnCHS[3],type,endCHS[3],start,length
1,0X80,0X0,0X1,0X10,0XC,0X3,0XE0,0XFF,2048,524288
2,0X0,0XC2,0X23,0X20,0XC,0XFE,0XFF,0XFF,526336,16564224
3,0X0,0XFE,0XFF,0XFF,0X7,0XFE,0XFF,0XFF,17092608,232642560
4,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0X0,0,0
Partition 1: Is a FAT32 (actually name is system-boot)
Partition 2: Another FAT32
Partition 3: exFAT

Interesting thing to note is that when you start the sd.card() you have to make sure you start it with whatever the first volume is formatted as otherwise it mess with the partitions that aren;t the same. In my case I had to set it up so SDFat sd was specified as part the extended fat defines:
Code:
// Test and benchmark of the fast bufferedPrint class.
//
// Mainly for AVR but may improve print performance with other CPUs.
#include "SdFat.h"
#include "BufferedPrint.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
[COLOR="#FF0000"]#define SD_FAT_TYPE 2[/COLOR]  // I tested with 1 and 2

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else  // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif  // HAS_SDIO_CLASS

#if SD_FAT_TYPE == 0
SdFat sd;
typedef File file_t;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
typedef File32 file_t;
[COLOR="#FF0000"]FatVolume partVol;
[/COLOR]#elif SD_FAT_TYPE == 2
[COLOR="#FF0000"]//SdExFat sd;
SdFat sd;  //if 1st partition is Fat32 have to start the SD card as FAT32 then use exVol to write to extended volume[/COLOR]
typedef ExFile file_t;
[COLOR="#FF0000"]ExFatVolume partVol;
[/COLOR]#elif SD_FAT_TYPE == 3
SdFs sd;
typedef FsFile file_t;
[COLOR="#FF0000"]FatVolume partVol;
[/COLOR]#else  // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE

// number of lines to print
const uint16_t N_PRINT = 20000;
//------------------------------------------------------------------------------
void benchmark() {
  file_t file;
  BufferedPrint<file_t, 64> bp;
  // do write test
  Serial.println();
  for (int test = 0; test < 6; test++) {
    char fileName[13] = "bench0.txt";
    fileName[5] = '0' + test;
    // open or create file - truncate existing file.
    if (!file.open(fileName, O_RDWR | O_CREAT | O_TRUNC)) {
      sd.errorHalt(&Serial, F("open failed"));
    }
    if (test & 1) {
      bp.begin(&file);
    }
    uint32_t t = millis();
    switch(test) {
    case 0:
      Serial.println(F("Test of println(uint16_t)"));
      for (uint16_t i = 0; i < N_PRINT; i++) {
        file.println(i);
      }
      break;

    case 1:
      Serial.println(F("Test of printField(uint16_t, char)"));
      for (uint16_t i = 0; i < N_PRINT; i++) {
        bp.printField(i, '\n');
      }
      break;

    case 2:
      Serial.println(F("Test of println(uint32_t)"));
      for (uint16_t i = 0; i < N_PRINT; i++) {
        file.println(12345678UL + i);
      }
      break;

    case 3:
      Serial.println(F("Test of printField(uint32_t, char)"));
      for (uint16_t i = 0; i < N_PRINT; i++) {
        bp.printField(12345678UL + i, '\n');
      }
      break;

    case 4:
      Serial.println(F("Test of println(double)"));
      for (uint16_t i = 0; i < N_PRINT; i++) {
        file.println((double)0.01*i);
      }
      break;

    case 5:
      Serial.println(F("Test of printField(double, char)"));
      for (uint16_t i = 0; i < N_PRINT; i++) {
        bp.printField((double)0.01*i, '\n');
      }
      break;

    }
    if (test & 1) {
      bp.sync();
    }
    if (file.getWriteError()) {
      sd.errorHalt(&Serial, F("write failed"));
    }
    double s = file.fileSize();
    file.close();
    t = millis() - t;
    Serial.print(F("Time "));
    Serial.print(0.001*t, 3);
    Serial.println(F(" sec"));
    Serial.print(F("File size "));
    Serial.print(0.001*s);
    Serial.println(F(" KB"));
    Serial.print(F("Write "));
    Serial.print(s/t);
    Serial.println(F(" KB/sec"));
    Serial.println();
  }
}
//------------------------------------------------------------------------------
void testMemberFunctions() {
  BufferedPrint<Print, 32> bp(&Serial);
  char c = 'c';    // char
//#define BASIC_TYPES
#ifdef BASIC_TYPES
  signed char sc = -1;   // signed 8-bit
  unsigned char uc = 1;  // unsiged 8-bit
  signed short ss = -2;  // signed 16-bit
  unsigned short us = 2; // unsigned 16-bit
  signed long sl = -4;   // signed 32-bit
  unsigned long ul = 4;  // unsigned 32-bit
#else  // BASIC_TYPES
  int8_t sc = -1;  // signed 8-bit
  uint8_t uc = 1;  // unsiged 8-bit
  int16_t ss = -2; // signed 16-bit
  uint16_t us = 2; // unsigned 16-bit
  int32_t sl = -4; // signed 32-bit
  uint32_t ul = 4; // unsigned 32-bit
#endif  // BASIC_TYPES
  float f = -1.234;
  double d = -5.678;
  bp.println();
  bp.println("Test print()");
  bp.print(c);
  bp.println();
  bp.print("string");
  bp.println();
  bp.print(F("flash"));
  bp.println();
  bp.print(sc);
  bp.println();
  bp.print(uc);
  bp.println();
  bp.print(ss);
  bp.println();
  bp.print(us);
  bp.println();
  bp.print(sl);
  bp.println();
  bp.print(ul);
  bp.println();
  bp.print(f);
  bp.println();
  bp.print(d);
  bp.println();
  bp.println();

  bp.println("Test println()");
  bp.println(c);
  bp.println("string");
  bp.println(F("flash"));
  bp.println(sc);
  bp.println(uc);
  bp.println(ss);
  bp.println(us);
  bp.println(sl);
  bp.println(ul);
  bp.println(f);
  bp.println(d);
  bp.println();

  bp.println("Test printField()");
  bp.printField(c, ',');
  bp.printField("string", ',');
  bp.printField(F("flash"), ',');
  bp.printField(sc, ',');
  bp.printField(uc, ',');
  bp.printField(ss, ',');
  bp.printField(us, ',');
  bp.printField(sl, ',');
  bp.printField(ul, ',');
  bp.printField(f, ',');
  bp.printField(d, '\n');

  bp.sync();
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println("Type any character to begin.");
  while(!Serial.available()) {}
  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
  }
  
  Serial.println("\nVolume Directory:      ");
  
[COLOR="#FF0000"]  if(!partVol.begin(sd.card(), true, 3)){   // for me part 1 and 2 are FAT32 and 3 is extFAT 
    sd.errorHalt("Volume did not start");//change part accordingly
  }
  partVol.chvol();
  partVol.ls("/", LS_SIZE);[/COLOR]
  
  Serial.println();
  Serial.println(F("Test member funcions:"));
  testMemberFunctions();
  Serial.println();
  Serial.println(F("Benchmark performance for uint16_t, uint32_t, and double:"));
  benchmark();

[COLOR="#FF0000"]    partVol.ls("/", LS_SIZE);[/COLOR]

  Serial.println("Done");
}
//------------------------------------------------------------------------------
void loop() {
}
I think I got all the changes hightlighted in red. If I then do the sdinfo modified to do volumes, it looks like it worked (checked the 3 volumes in explorer)
Code:
Partion 1

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 1
clusterCount:      516190
freeClusterCount:  514313
fatStartSector:    2080
dataStartSector:   10146
Data area is not aligned on flash erase boundary!
Download and use formatter from www.sdcard.org!

Volume Directory:      
    128890 bench0.txt
    128890 bench1.txt
    200000 bench2.txt
    200000 bench3.txt
    149000 bench4.txt
    149000 bench5.txt
------------------------------- 
 
Partion 2

Scanning FAT, please wait.

Volume is FAT32
sectorsPerCluster: 8
clusterCount:      2066432
freeClusterCount:  2066192
fatStartSector:    526814
dataStartSector:   559104

Volume Directory:      
    128890 bench0.txt
    128890 bench1.txt
    200000 bench2.txt
    200000 bench3.txt
    149000 bench4.txt
    149000 bench5.txt
------------------------------- 
 
Partion 3

Scanning exFAT, please wait.

Volume is FAT64
sectorsPerCluster: 256
clusterCount:      908720
freeClusterCount:  908704
fatStartSector:    17094656

Volume Directory:      
bench0.txt
bench1.txt
bench2.txt
bench3.txt
bench4.txt
bench5.txt
-------------------------------
How to get this info incorporated into FS and MTP and MSC do not know. But at least we now know that it can be done.
 
@mjs513 - Not a problem... Hope not too much snow! Here it is raining and upper 40s...

Will play more, but may want to switch gears to see about partitions on USB disks, which is probably more interesting.

Also sort of question to myself and ... Would be nice to get the volume labels... Especially toward MTP,

wondering if there is a method... SO far I have not seen one with SDFat stuff. I have seen mention of hacks.
There appear to be to ways maybe Volume name is stored: As part of the structure:
Code:
const uint8_t EXTENDED_BOOT_SIGNATURE = 0X29;
typedef struct biosParameterBlockFat16 {
  uint8_t  bytesPerSector[2];
  uint8_t  sectorsPerCluster;
  uint8_t  reservedSectorCount[2];
  uint8_t  fatCount;
  uint8_t  rootDirEntryCount[2];
  uint8_t  totalSectors16[2];
  uint8_t  mediaType;
  uint8_t  sectorsPerFat16[2];
  uint8_t  sectorsPerTrtack[2];
  uint8_t  headCount[2];
  uint8_t  hidddenSectors[4];
  uint8_t  totalSectors32[4];

  uint8_t  physicalDriveNumber;
  uint8_t  extReserved;
  uint8_t  extSignature;
  uint8_t  volumeSerialNumber[4];
  uint8_t  volumeLabel[11];
  uint8_t  volumeType[8];
} BpbFat16_t;
Note: there are other structures for fat32 ... and I don't see any code that uses this structure anywhere in the code...

Or the Root directory probably first directory entry may contain volume id... But we don't see it as: the nextfile like code calls:
Code:
static inline bool isFileOrSubdir(const DirFat_t* dir) {
  return (dir->attributes & FAT_ATTRIB_LABEL) == 0;
}
And it specifically does not allow the label to come through...
Might be nice to have a new method that allows this?

Or maybe add a special flag to the call: openNextFile
which says sure return that one...

But now back to playing
 
@KurtE
Been searching the code and the help system as well but to no avail. Nothing I have found seems to return the volume name. Think @wwatson mentioned in an earlier post that he was doing something to get the vol name.

As you said what would be more interesting is getting partitions working for USBdrives, thumb or SSD or HDD, which was really the final state for this stuff.
 
Back
Top