diy/아두이노

SD 메모리 포맷 전용기기 만들기(2)_소스코드

do121 2025. 10. 11. 20:16

전원 인가시 포맷 실행함.

eraseCard() 함수는 섹터를 '0'으로 채우는 기능인데 에러 발생함

formatCard() 함수로 실제 데이터 삭제없이 빠른 포맷 실행.

/*
 * This program will format SD/SDHC/SDXC cards.
 * Warning all data will be deleted!
 *
 * This program attempts to match the format
 * generated by SDFormatter available here:
 *
 * http://www.sdcard.org/consumers/formatter/
 *
 * For very small cards this program uses FAT16
 * and the above SDFormatter uses FAT12.
 */
#ifndef DISABLE_FS_H_WARNING
#define DISABLE_FS_H_WARNING  // Disable warning for type File not defined. 
#endif  // DISABLE_FS_H_WARNING 
#include "SdFat.h"
#include "sdios.h"
#include "U8glib.h"
#include <Wire.h> //for nano sda scl a4 a5

// OLED 설정
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

/*
  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
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif  // SDCARD_SS_PIN

// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
// #define SPI_CLOCK SD_SCK_MHZ(50)
// SPI_CLOCK 값을 낮춤
//#define SPI_CLOCK SD_SCK_MHZ(16)  // 50MHz → 16MHz로 낮춤
// 또는
#define SPI_CLOCK SD_SCK_MHZ(4)   // 더 낮춤

// Try to select the best SD card configuration.
#if defined(HAS_TEENSY_SDIO)
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif defined(HAS_BUILTIN_PIO_SDIO)
// See the Rp2040SdioSetup example for boards without a builtin SDIO socket.
#define SD_CONFIG SdioConfig(PIN_SD_CLK, PIN_SD_CMD_MOSI, PIN_SD_DAT0_MISO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else  // HAS_TEENSY_SDIO
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif  // HAS_TEENSY_SDIO
//==============================================================================
// Serial output stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
uint32_t cardSectorCount = 0;
uint8_t sectorBuffer[512] __attribute__ ((aligned (4)));
//------------------------------------------------------------------------------
// SdCardFactory constructs and initializes the appropriate card.
SdCardFactory cardFactory;
// Pointer to generic SD card.
SdCard* m_card = nullptr;
//------------------------------------------------------------------------------
#define sdError(msg)                        \
  {                                         \
    cout << F("error: ") << F(msg) << endl; \
    sdErrorHalt();                          \
  }
//-

//  -----------------------------------------------------------------------------
void sdErrorHalt() {
  if (!m_card) {
    cout << F("Invalid SD_CONFIG") << endl;
    dis_oled3( "","Error:", "Invalid SD_CONFIG", "Check wiring", "");
  } else if (m_card->errorCode()) {
    if (m_card->errorCode() == SD_CARD_ERROR_CMD0) {
      cout << F("No card, wrong chip select pin, or wiring error?") << endl;
      dis_oled3( "","Error:", "No SD Card", "or wiring error", "Check CS pin");
    }
    cout << F("SD errorCode: ") << hex << showbase;
    printSdErrorSymbol(&Serial, m_card->errorCode());
    cout << F(" = ") << int(m_card->errorCode()) << endl;
    cout << F("SD errorData = ") << int(m_card->errorData()) << endl;
    dis_oled3( "","SD Error:", String(m_card->errorCode()), String(m_card->errorData()), "");
  }
  while (true) {
    delay(1000);
  }
}


void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
// OLED 표시 함수
void dis_oled3(String msg1, String msg2, String msg3, String msg4, String msg5) {
  int idx[] = {10, 26, 39, 52, 65};
  String str[5];

  str[0] = msg1;
  str[1] = msg2;
  str[2] = msg3;
  str[3] = msg4;
  str[4] = msg5;

  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_unifont);
    for (int i = 0; i < 5; i++) {
      u8g.setPrintPos(0, idx[i]);
      u8g.print(str[i]);
    }
  } while (u8g.nextPage());
}
//------------------------------------------------------------------------------
// 진행 상태 표시 함수
void showProgress(String message, int progress = -1) {
  String progressBar = "---";
  if (progress >= 0) {
    progressBar = "";
    for (int i = 0; i < 3; i++) {
      if (i < progress % 4) {
        progressBar += "*";
      } else {
        progressBar += "-";
      }
    }
  }
  
  dis_oled3("","SD Formatter", message, progressBar, "");
}
//------------------------------------------------------------------------------
// flash erase all data
uint32_t const ERASE_SIZE = 262144L;
void eraseCard() {
  cout << endl << F("Erasing\n");
  showProgress("Erasing card", 0);
  
  uint32_t firstBlock = 0;
  uint32_t lastBlock;
  uint16_t n = 0;
  int progressCount = 0;

  do {
    lastBlock = firstBlock + ERASE_SIZE - 1;
    if (lastBlock >= cardSectorCount) {
      lastBlock = cardSectorCount - 1;
    }
    if (!m_card->erase(firstBlock, lastBlock)) {
      sdError("erase failed");
    }
    
    // 진행 상태 업데이트 (3초마다)
    if (millis() % 3000 < 100) {
      showProgress("Erasing card", progressCount % 4);
      progressCount++;
    }
    
    firstBlock += ERASE_SIZE;
  } while (firstBlock < cardSectorCount);
  
  cout << endl;

  if (!m_card->readSector(0, sectorBuffer)) {
    sdError("readBlock");
  }
  
  cout << hex << showbase << setfill('0') << internal;
  cout << F("All data set to ") << setw(4) << int(sectorBuffer[0]) << endl;
  cout << dec << noshowbase << setfill(' ') << right;
  cout << F("Erase done\n");
  
  showProgress("Erase complete", 3);
  delay(1000);
}
//------------------------------------------------------------------------------
void formatCard() {
  showProgress("Formatting", 0);
  
  ExFatFormatter exFatFormatter;
  FatFormatter fatFormatter;

  // Format exFAT if larger than 32GB.
  bool rtn = cardSectorCount > 67108864
                 ? exFatFormatter.format(m_card, sectorBuffer, &Serial)
                 : fatFormatter.format(m_card, sectorBuffer, &Serial);

  if (!rtn) {
    sdErrorHalt();
  }
  
  showProgress("Format complete", 3);
  cout << F("Format completed successfully!") << endl;
  delay(1000);
}
//------------------------------------------------------------------------------
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() {
  // OLED 초기화
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_unifont);
    u8g.setPrintPos(0, 10);
    u8g.print("Initializing...");
  } while (u8g.nextPage());

  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    yield();
  }
  
  showProgress("Initializing", 0);
  delay(1000);
// 카드 초기화 후 지연 시간 추가
  m_card = cardFactory.newCard(SD_CONFIG);
  if (!m_card || m_card->errorCode()) {
    sdError("card init failed.");
    return;
  }
  
  // 추가: 초기화 후 안정화를 위한 대기 시간
  delay(100);
  
  // 추가: 카드가 idle 상태에서 벗어났는지 확인
  uint32_t start = millis();
  while (m_card->errorCode() && millis() - start < 5000) {
    delay(10);
  }
  // 자동으로 포맷 시작
  showProgress("Starting format", 1);
  delay(1000);

  // Select and initialize proper card driver.
  showProgress("Detecting SD card", 2);
  m_card = cardFactory.newCard(SD_CONFIG);
  if (!m_card || m_card->errorCode()) {
    sdError("card init failed.");
    return;
  }

  cardSectorCount = m_card->sectorCount();
  if (!cardSectorCount) {
    sdError("Get sector count failed.");
    return;
  }

  // 카드 정보 표시
  showProgress("Card detected", 3);
  delay(1000);
  
  cout << F("\nCard size: ") << cardSectorCount * 5.12e-7;
  cout << F(" GB (GB = 1E9 bytes)\n");
  cout << F("Card size: ") << cardSectorCount / 2097152.0;
  cout << F(" GiB (GiB = 2^30 bytes)\n");

  cout << F("Card will be formated ");
  if (cardSectorCount > 67108864) {
    cout << F("exFAT\n");
    showProgress("Format: exFAT", 0);
  } else if (cardSectorCount > 4194304) {
    cout << F("FAT32\n");
    showProgress("Format: FAT32", 0);
  } else {
    cout << F("FAT16\n");
    showProgress("Format: FAT16", 0);
  }
  delay(1000);

  // 자동으로 지우기 + 포맷 수행 (F 옵션)
  // showProgress("Starting erase", 1);
  // eraseCard();
  
  showProgress("Starting format", 2);
  formatCard();
  
  // 완료 메시지
  showProgress("COMPLETE!", 3);
  dis_oled3("","SD Erase", "COMPLETE!", "Card is ready", "Remove card");
  cout << F("Format completed successfully!") << endl;
}

void loop() {
  // 완료 후 아무 작업도 하지 않음
  delay(1000);
}