ESP32 SD card info

User avatar
Segmentation Fault
Posts: 22
Joined: Sat Apr 04, 2020 1:49 am

ESP32 SD card info

Postby Segmentation Fault » Sat Apr 04, 2020 2:01 am

I've been making a project with my ESP8266 with an additional SD card module using Arduino IDE.
My project required an upgrade, so I purchased and ESP32-WROVER-KIT and am trying to get the SD card information, but I cannot find something similar with the ESP8266 SdFat.h for the ESP32.

Is there a way to get in ESP32 the card info (type, size, manufacturer, partitions etc) like the cardInfo example of ESP8266?

User avatar
Segmentation Fault
Posts: 22
Joined: Sat Apr 04, 2020 1:49 am

Re: ESP32 SD card info

Postby Segmentation Fault » Sun Apr 05, 2020 9:42 pm

To answer for other people might needing this; the ESP32 library for Arduino IDE does not seem to include the required files, but they can be downloaded from here: https://github.com/greiman/SdFat

It seems to be almost the same as with ESP8266, except that "using namespace sdfat;" will cause a compilation error. I also added #define FS_NO_GLOBALS to avoid another compilation error and now the code compiles fine for ESP-WROVER.

I have not uploaded and tested it yet. I will post an update as soon as I do.

User avatar
Segmentation Fault
Posts: 22
Joined: Sat Apr 04, 2020 1:49 am

Re: ESP32 SD card info

Postby Segmentation Fault » Mon Apr 13, 2020 9:29 pm

I cannot initialize the sdfat.
SD_INFO gives:

Code: Select all

error: File System initialization failed.
SD errorCode: 0X50,0X0
PARTITION_INFO:

Code: Select all

gives error: read MBR failed
SD errorCode: 0X50,0X0
VOLUME_INFO gives:

Code: Select all

error: cardBegin failed
SD errorCode: 0X20,0XFF
This is my code:

Code: Select all

#include <SdFat.h>
#include <sdios.h>
#include <My_Receive_serial_lib.h>
#include <SPI.h>
#include <SD.h>

static bool hasSD = false;
fs::File uploadFile;

#define USE_SDIO 0
#if USE_SDIO
  	// Use faster SdioCardEX
  	SdFatSdioEX sd;
#else // USE_SDIO
	SdFat sd;
#endif  // USE_SDIO

#define SD_CS 13
  
void setup()
{
	Serial.begin(SERIAL_BAUD_RATE);
	SPI.begin(14, 2, 15, 13); // The bultin SD card SPI for WROVER  
}

void loop()
{
	if (Serial.available() > 0)
	 {
		String IncomingData = Recieve_serial();
		if (IncomingData == "SD_INFO" )
    		{
      			cidDmp();
    		}
		else if (IncomingData == "PARTITION_INFO" )
		{
      			partDmp();
   		}
    		else if (IncomingData == "VOLUME_INFO" )
    		{
      			volDmp();
    		}
    	}
}


uint8_t cidDmp()
{
  Serial.println("-----------------");
  Serial.println("Initialising card:");
  uint32_t t = millis();
#if USE_SDIO
  if (!sd.cardBegin(SD_CS))
  {
    Serial.print("cardBegin failed in #if USE_SDIO");
    sdErrorMsg("\ncardBegin failed");
    return 0;
  }
#else  // USE_SDIO
  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.cardBegin(SD_CS, SD_SCK_MHZ(50)))
  {
    Serial.print("cardBegin failed in #else (of #if USE_SDIO)");
    sdErrorMsg("cardBegin failed");
    return 0;
  }
  else
  {
    if (!sd.fsBegin())
    {
      sdErrorMsg("\nFile System initialization failed.\n");
      return 0;
    }
  }
#endif  // USE_SDIO 
  t = millis() - t;

  float cardSize2;
  float freeSpace;

  cardSize = sd.card()->cardSize();
  if (cardSize == 0)
  {
    sdErrorMsg("cardSize failed");
    return 0;
  }
  else
  {
    cardSize2 = 0.000512 * cardSize / 1024.0;
    freeSpace = 0.000512 * sd.vol()->blocksPerCluster() * (uint32_t)sd.vol()->freeClusterCount() / 1024.0;
  }

  Serial.print("init time: ");
  Serial.print(t); Serial.println("ms");
  Serial.print("Card type: ");
  switch (sd.card()->type())
  {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;

    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;

    case SD_CARD_TYPE_SDHC:
      if (cardSize < 70000000)
      {
        Serial.println("SDHC");
      }
      else
      {
        Serial.println("SDXC");
      }
      break;

    default:
      Serial.println("Unknown");
  }

  cid_t cid;
  if (!sd.card()->readCID(&cid))
  {
    sdErrorMsg("readCID failed");
    return 0;
  }
  else
  {
    Serial.println("SD card initialised successfully.");
  }


  //Serial.println("-----------------");
  Serial.println("Card INFO:");
  Serial.print("Card size: "); Serial.print(cardSize2); Serial.println(" GB");
  Serial.print("Free space: "); Serial.print(freeSpace); Serial.println(" GB");
  Serial.print("Card clusters: "); Serial.println(cardSize);
  Serial.print("Manufacturer ID: ");  Serial.print("0x"); Serial.println(cid.mid, HEX);
  Serial.print("OEM ID: "); Serial.println(cid.oid[0] << cid.oid[1]);
  Serial.print("Product: ");
  for (uint8_t i = 0; i < 5; i++)
  {
    Serial.print(cid.pnm[i]);
  } Serial.println();
  Serial.print("nVersion: "); Serial.print(cid.prv_n); Serial.print("."); Serial.println(cid.prv_m);
  Serial.print("Serial number: "); Serial.println(cid.psn, HEX);
  Serial.print("Manufacturing date: "); Serial.print(cid.mdt_month); Serial.print("/"); Serial.println(2000 + cid.mdt_year_low + 10 * cid.mdt_year_high);

  uint32_t ocr;
  if (!sd.card()->readOCR(&ocr))
  {
    sdErrorMsg("\nreadOCR failed");
    return 0;
  }
  Serial.print("OCR: "); Serial.print("0x"); Serial.println(ocr, HEX);
}

uint8_t csdDmp()
{
  csd_t csd;
  uint8_t eraseSingleBlock;
  if (!sd.card()->readCSD(&csd))
  {
    sdErrorMsg("readCSD failed");
    return false;
  }
  if (csd.v1.csd_ver == 0)
  {
    eraseSingleBlock = csd.v1.erase_blk_en;
    eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
  }
  else if (csd.v2.csd_ver == 1)
  {
    eraseSingleBlock = csd.v2.erase_blk_en;
    eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
  }
  else
  {
    Serial.println("csd version error");
    return false;
  }

  eraseSize++;
  Serial.print("flashEraseSize: "); Serial.print(eraseSize); Serial.println(" blocks");
  Serial.print("eraseSingleBlock: ");
  if (eraseSingleBlock)
  {
    Serial.println("true");
  }
  else
  {
    Serial.println("false");
  }
}

uint8_t partDmp()
{
#if USE_SDIO
  if (!sd.cardBegin()) {
    sdErrorMsg("\ncardBegin failed");
    return 0;
  }
#else  // USE_SDIO
  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.cardBegin(SD_CS, SD_SCK_MHZ(50))) {
    sdErrorMsg("cardBegin failed");
    return 0;
  }
#endif  // USE_SDIO 

  cardSize = sd.card()->cardSize();


  mbr_t mbr;
  if (!sd.card()->readBlock(0, (uint8_t*)&mbr))
  {
    sdErrorMsg("read MBR failed");
    return false;
  }
  Serial.println("-----------------");
  Serial.println("Part INFO:");
  for (uint8_t ip = 1; ip < 5; ip++)
  {
    part_t *pt = &mbr.part[ip - 1];
    if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize)
    {
      Serial.println("No MBR. Assuming Super Floppy format.");
      return true;
    }
  }
  Serial.println("SD Partition Table");
  Serial.println("part,boot,type,start,length");
  for (uint8_t ip = 1; ip < 5; ip++)
  {
    part_t *pt = &mbr.part[ip - 1];
    Serial.print(ip); Serial.print(",0x"); Serial.print(pt->boot, HEX); Serial.print(","); Serial.print(pt->type);
    Serial.print(","); Serial.print(pt->firstSector); Serial.print(",");  Serial.print(pt->totalSectors);  Serial.println();
  }
  return true;
}

void volDmp()
{
  #if defined (ARDUINO_ESP8266_NODEMCU)
    #if USE_SDIO
      if (!sd.cardBegin())
      {
        sdErrorMsg("\ncardBegin failed");
        return;
      }
    #else  // USE_SDIO
      // Initialize at the highest speed supported by the board that is
      // not over 50 MHz. Try a lower speed if SPI errors occur.
      if (!sd.cardBegin(SD_CS, SD_SCK_MHZ(50))) {
        sdErrorMsg("cardBegin failed");
        return;
      }
    #endif  // USE_SDIO 
  #elif defined (ARDUINO_ARCH_ESP32)
      if (!sd.cardBegin()) {
        sdErrorMsg("\ncardBegin failed");
        return;
      }
  #endif

  cardSize = sd.card()->cardSize();
  
  if (!sd.fsBegin())
  {
    sdErrorMsg("\nFile System initialization failed.\n");
    return;
  }
  if (!sd.cardBegin())
  {
    Serial.println("cardBegin failed");
    sdErrorMsg("\ncardBegin failed");
    return;
  }

  Serial.println("-----------------");
  Serial.println("Volume INFO:");
  //  float cardSize2 = float((0.000512*cardSize) >> 10); Does not work because of float and bit shifting
  //  float freeSpace = float((0.000512*sd.vol()->blocksPerCluster()*(uint32_t)sd.vol()->freeClusterCount())>>10); Does not work because of float and bit shifting
  float cardSize2 = 0.000512 * cardSize / 1024.0;
  float freeSpace = 0.000512 * sd.vol()->blocksPerCluster() * (uint32_t)sd.vol()->freeClusterCount() / 1024.0;
  uint32_t volFree2 = sd.vol()->freeClusterCount();
  Serial.print("Volume is FAT"); Serial.println(sd.vol()->fatType());

    
  Serial.print("Card size: "); Serial.print(cardSize2); Serial.println(" GB");
  Serial.print("Free space: "); Serial.print(freeSpace); Serial.println(" GB");
  Serial.print("blocksPerCluster: "); Serial.println(sd.vol()->blocksPerCluster());
  Serial.print("totalClusters: "); Serial.println(cardSize);
  Serial.print("clusterCount: "); Serial.println(sd.vol()->clusterCount());
  Serial.print("freeClusters: "); Serial.println(volFree2);
  //  float fs = 0.000512/1024.0*volFree*sd.vol()->blocksPerCluster();
  //  Serial.print("freeSpace: "); Serial.print(fs); Serial.println(" GB");
  Serial.flush();
  Serial.print("fatStartBlock: "); Serial.println(sd.vol()->fatStartBlock());
  Serial.print("fatCount: "); Serial.println(sd.vol()->fatCount());
  Serial.print("blocksPerFat: "); Serial.println(sd.vol()->blocksPerFat());
  Serial.print("rootDirStart: "); Serial.println(sd.vol()->rootDirStart());
  Serial.print("dataStartBlock: "); Serial.println(sd.vol()->dataStartBlock());
  delay(100);
  if (sd.vol()->dataStartBlock() > 0 % eraseSize)
  {
    Serial.println("Data area is not aligned on flash erase boundaries!");
    //Serial.println("Download and use formatter from www.sdcard.org!");
  }

  csdDmp();
}
I am suspecting I should define the SD SPI bus of the WROVER in the SdFat class as well, but I cannot find how to define the SPI GPIO pins there.
Any help would be really appreciated,
Last edited by Segmentation Fault on Mon Apr 13, 2020 10:30 pm, edited 2 times in total.

pipi61
Posts: 34
Joined: Fri Dec 23, 2016 10:58 pm

Re: ESP32 SD card info

Postby pipi61 » Mon Apr 13, 2020 10:11 pm

The pinout change in your source:
SPI.begin( 14, 2, 15, 13); // The bultin SD card SPI for WROVER
void begin (int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1);// this SPI.begin defined in spi.h

User avatar
Segmentation Fault
Posts: 22
Joined: Sat Apr 04, 2020 1:49 am

Re: ESP32 SD card info

Postby Segmentation Fault » Mon Apr 13, 2020 10:21 pm

Hi pipi61,

The SD class works properly after the pinout change SPI.begin( 14, 2, 15, 13);

The SdFat class though creates these errors.


I do not understand your reply. :(

pipi61
Posts: 34
Joined: Fri Dec 23, 2016 10:58 pm

Re: ESP32 SD card info

Postby pipi61 » Mon Apr 13, 2020 11:30 pm

sorry, i view sd, don"t sdfat.
Connect this pinout
CLK18, Miso19, Mosi23, CS15
and remove SPI.begin....

User avatar
Segmentation Fault
Posts: 22
Joined: Sat Apr 04, 2020 1:49 am

Re: ESP32 SD card info

Postby Segmentation Fault » Tue Apr 14, 2020 12:30 am

I cannot really do that. The SD card module is built in on the WROVER board and connected with the specific pinout.

truufseir
Posts: 3
Joined: Mon Apr 13, 2020 9:39 pm

Re: ESP32 SD card info

Postby truufseir » Tue Apr 14, 2020 1:04 pm

Yes sdfat will work fine as he said.

User avatar
Segmentation Fault
Posts: 22
Joined: Sat Apr 04, 2020 1:49 am

Re: ESP32 SD card info

Postby Segmentation Fault » Tue Apr 14, 2020 10:23 pm

It seems that it is a speed problem, not related with the WROVER pinout but with esp32.

Solution here:
https://github.com/greiman/SdFat/issues ... -396235386

Who is online

Users browsing this forum: No registered users and 11 guests