Go Down

Topic: Don't Format SD cards with OS utilities! (Read 74024 times) previous topic - next topic

brazil


Flinkly

Thanks for this, and SdFat.  I'm still working on buffering (making sense of it, ME here...), but whenever I have a question about Arduino's and SDs, and ask the Google, you (in some flavor) come up and answer my question and more.

If only SDIO didn't seem so much more intimidating than SPI (which is so simple!).

Thanks!

Eimerkette

Thanks for the information about using "SDFormatter V4.0" to format SD card.

Because of having no success to get my "Arduino UNO" - "SD card" running, I searched for posts which describes the same problem. But I didn't found any solution/hint which will help. In the meantime I spend many hours/days...

Therefore I also tried to use "SDFormatter V4.0" to format my SD card, but I did not solve my problem.

My "Arduino UNO" - "SD card" is still not running. That's really frustrating and makes no fun.

The best result (using "CardInfo") was:

Code: [Select]

Initializing SD card...Wiring is correct and a card is present.

Card type: SDHC
Could not find FAT16/FAT32 partition.
Make sure you've formatted the card


but it is hard to reproduce this situation.

Any hints?

_pepe_

#33
Mar 12, 2017, 03:08 pm Last Edit: Mar 12, 2017, 03:17 pm by _pepe_
Hi,

It could be interesting to modify the SD library in order to know the reason why the volume's initialization fails.

For instance, you could add an "error" attribute in the SdVolume class (in file SD/src/utility/SdFat.h):

class SdVolume {
 public:
  uint8_t error;
...

and set it to particular values depending on the exit point of the SdVolume::init() method (in file SD/src/utility/SdVolume.cpp):

uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
  error = 0;
  uint32_t volumeStartBlock = 0;
  sdCard_ = dev;
  // if part == 0 assume super floppy with FAT boot sector in block zero
  // if part > 0 assume mbr volume with partition table
  if (part) {
    if (part > 4)return error=1,false;
    if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return error=2,false;
    part_t* p = &cacheBuffer_.mbr.part[part-1];
    if ((p->boot & 0X7F) !=0)
      // not a valid partition
      return error=3,false;
    if (p->totalSectors < 100)
      // not a valid partition
      return error=4,false;
    if (p->firstSector == 0)
      // not a valid partition
      return error=5,false;
    volumeStartBlock = p->firstSector;
  }
  if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return error=6,false;
  bpb_t* bpb = &cacheBuffer_.fbs.bpb;
  if (bpb->bytesPerSector != 512)
       // not valid FAT volume
      return error=7,false;
  if (bpb->fatCount == 0)
       // not valid FAT volume
      return error=8,false;
  if (bpb->reservedSectorCount == 0)
       // not valid FAT volume
      return error=9,false;
  if (bpb->sectorsPerCluster == 0)
       // not valid FAT volume
      return error=10,false;
  fatCount_ = bpb->fatCount;
  blocksPerCluster_ = bpb->sectorsPerCluster;

  // determine shift that is same as multiply by blocksPerCluster_
  clusterSizeShift_ = 0;
  while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
    // error if not power of 2
    if (clusterSizeShift_++ > 7) return error=11,false;
  }
  blocksPerFat_ = bpb->sectorsPerFat16 ?
                    bpb->sectorsPerFat16 : bpb->sectorsPerFat32;

  fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;

  // count for FAT16 zero for FAT32
  rootDirEntryCount_ = bpb->rootDirEntryCount;

  // directory start for FAT16 dataStart for FAT32
  rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;

  // data start for FAT16 and FAT32
  dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512);

  // total blocks for FAT16 or FAT32
  uint32_t totalBlocks = bpb->totalSectors16 ?
                           bpb->totalSectors16 : bpb->totalSectors32;
  // total data blocks
  clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);

  // divide by cluster size to get cluster count
  clusterCount_ >>= clusterSizeShift_;

  // FAT type is determined by cluster count
  if (clusterCount_ < 4085) {
    fatType_ = 12;
  } else if (clusterCount_ < 65525) {
    fatType_ = 16;
  } else {
    rootDirStart_ = bpb->fat32RootCluster;
    fatType_ = 32;
  }
  return true;
}
Then, you just have to read the "error" attribute in "CardInfo" when the error occurs:

  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    Serial.println(volume.error);
    return;
  }

Eimerkette

#34
Mar 12, 2017, 05:15 pm Last Edit: Mar 12, 2017, 06:12 pm by Eimerkette Reason: (Added link to new topic.)
Hi _pepe_,

thanks for this hint.

I'll do it and report the corresponding error codes in a new topic.

dlchambers

Unfortunately, this utility formats the SD as FAT32, but the Arduino SD lib wants FAT16. So the tool is useless.

C1913

Quote
So the tool is useless
So are cars, if I dont know how to drive them. Or foreign languages I don't speak. They are indeed useless, but to me, not in general.
Only cause you're frustrated is no reason to be rude. People here are there to help you, not to bother you with useless crap   ;)
If google was a country, I'd move there.

fat16lib

Quote
Unfortunately, this utility formats the SD as FAT32, but the Arduino SD lib wants FAT16. So the tool is useless.
SD cards are designed to be formatted with a layout that matches the card's flash chips.  SDFormatter produces the optimal layout by inserting hidden sectors to adjust the layout to chip boundaries.  SDFormatter chooses an appropriate cluster size.  There are no options for the standard format.

SDFormatter uses FAT12 for very small cards.  FAT16 is used for cards <= 2GB, FAT32 for cards <= 32 GB, and exFAT for cards larger than 32GB.

The SD library supports FAT16/FAT32 and is optimized for the layout SDFormatter produces.

Go Up