Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mass Storage Controller microSD on Metro RP2040 #455

Open
mikeysklar opened this issue Sep 6, 2024 · 0 comments
Open

Mass Storage Controller microSD on Metro RP2040 #455

mikeysklar opened this issue Sep 6, 2024 · 0 comments
Labels
Bug Something isn't working

Comments

@mikeysklar
Copy link

mikeysklar commented Sep 6, 2024

Operating System

Linux

Arduino IDE version

2.3.2

Board

Adafruit Metro RP2040

ArduinoCore version

earlephilhower 4.0.1

TinyUSB Library version

3.3.3

Sketch as ATTACHED TXT

stock example msc_external_flash_sdcard.ino with a single line pin change from 10 --> 23 for SDCARD_CS.

/*********************************************************************
 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 Copyright (c) 2019 Ha Thach for Adafruit Industries
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

/* This example exposes both external flash and SD card as mass storage (dual LUNs)
 * Following library is required
 *   - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash
 *   - SdFat https://github.com/adafruit/SdFat
 *
 * Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT
 * in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original
 * SdFat library and manually change those macros
 *
 * Note2: If your flash is not formatted as FAT12 previously, you could format it using
 * follow sketch https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format
 */

#include "SPI.h"
#include "SdFat.h"
#include "Adafruit_SPIFlash.h"
#include "Adafruit_TinyUSB.h"

//--------------------------------------------------------------------+
// External Flash Config
//--------------------------------------------------------------------+

// for flashTransport definition
#include "flash_config.h"

Adafruit_SPIFlash flash(&flashTransport);

// External Flash File system
FatVolume fatfs;

//--------------------------------------------------------------------+
// SDCard Config
//--------------------------------------------------------------------+

#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
  // PyPortal has on-board card reader
  #define SDCARD_CS       32
  #define SDCARD_DETECT   33
#else
  #define SDCARD_CS       23
  // no detect
#endif

// SDCard File system
SdFat sd;

// USB Mass Storage object
Adafruit_USBD_MSC usb_msc;

// Set to true when PC write to flash
bool sd_changed = false;
bool sd_inited = false;

bool flash_formatted = false;
bool flash_changed = false;

// the setup function runs once when you press reset or power the board
void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);

  // MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
  usb_msc.setMaxLun(2);

  usb_msc.setID(0, "Adafruit", "External Flash", "1.0");
  usb_msc.setID(1, "Adafruit", "SD Card", "1.0");

  // Since initialize both external flash and SD card can take time.
  // If it takes too long, our board could be enumerated as CDC device only
  // i.e without Mass Storage. To prevent this, we call Mass Storage begin first
  // LUN readiness will always be set later on
  usb_msc.begin();

  //------------- Lun 0 for external flash -------------//
  flash.begin();
  flash_formatted = fatfs.begin(&flash);

  usb_msc.setCapacity(0, flash.size()/512, 512);
  usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
  usb_msc.setUnitReady(0, true);

  flash_changed = true; // to print contents initially

  //------------- Lun 1 for SD card -------------//
#ifdef SDCARD_DETECT
  // DETECT pin is available, detect card present on the fly with test unit ready
  pinMode(SDCARD_DETECT, INPUT);
  usb_msc.setReadyCallback(1, sdcard_ready_callback);
#else
  // no DETECT pin, card must be inserted when powered on
  init_sdcard();
  sd_inited = true;
  usb_msc.setUnitReady(1, true);
#endif

//  while ( !Serial ) delay(10);   // wait for native usb
  Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
  delay(1000);
}

bool init_sdcard(void)
{
  Serial.print("Init SDCard ... ");

  if ( !sd.begin(SDCARD_CS, SD_SCK_MHZ(50)) )
  {
    Serial.print("Failed ");
    sd.errorPrint("sd.begin() failed");

    return false;
  }

  uint32_t block_count;

#if SD_FAT_VERSION >= 20000
  block_count = sd.card()->sectorCount();
#else
  block_count = sd.card()->cardSize();
#endif


  usb_msc.setCapacity(1, block_count, 512);
  usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);

  sd_changed = true; // to print contents initially

  Serial.print("OK, Card size = ");
  Serial.print((block_count / (1024*1024)) * 512);
  Serial.println(" MB");

  return true;
}

void print_rootdir(File32* rdir)
{
  File32 file;

  // Open next file in root.
  // Warning, openNext starts at the current directory position
  // so a rewind of the directory may be required.
  while ( file.openNext(rdir, O_RDONLY) )
  {
    file.printFileSize(&Serial);
    Serial.write(' ');
    file.printName(&Serial);
    if ( file.isDir() )
    {
      // Indicate a directory.
      Serial.write('/');
    }
    Serial.println();
    file.close();
  }
}

void loop()
{
  if ( flash_changed )
  {
    if (!flash_formatted)
    {
      flash_formatted = fatfs.begin(&flash);
    }

    // skip if still not formatted
    if (flash_formatted)
    {
      File32 root;
      root = fatfs.open("/");

      Serial.println("Flash contents:");
      print_rootdir(&root);
      Serial.println();

      root.close();
    }

    flash_changed = false;
  }

  if ( sd_changed )
  {
    File32 root;
    root = sd.open("/");

    Serial.println("SD contents:");
    print_rootdir(&root);
    Serial.println();

    root.close();

    sd_changed = false;
  }

  delay(1000); // refresh every 1 second
}


//--------------------------------------------------------------------+
// SD Card callbacks
//--------------------------------------------------------------------+

int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
  bool rc;

#if SD_FAT_VERSION >= 20000
  rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
#else
  rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
#endif

  return rc ? bufsize : -1;
}

// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and 
// return number of written bytes (must be multiple of block size)
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
  bool rc;

  digitalWrite(LED_BUILTIN, HIGH);

#if SD_FAT_VERSION >= 20000
  rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
#else
  rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
#endif

  return rc ? bufsize : -1;
}

// Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache.
void sdcard_flush_cb (void)
{
#if SD_FAT_VERSION >= 20000
  sd.card()->syncDevice();
#else
  sd.card()->syncBlocks();
#endif

  // clear file system's cache to force refresh
  sd.cacheClear();

  sd_changed = true;

  digitalWrite(LED_BUILTIN, LOW);
}

#ifdef SDCARD_DETECT
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool sdcard_ready_callback(void)
{
  // Card is inserted
  if ( digitalRead(SDCARD_DETECT) == HIGH )
  {
    // init SD card if not already
    if ( !sd_inited )
    {
      sd_inited = init_sdcard();
    }
  }else
  {
    sd_inited = false;
    usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
  }

  Serial.println(sd_inited);

  return sd_inited;
}
#endif

//--------------------------------------------------------------------+
// External Flash callbacks
//--------------------------------------------------------------------+

// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size)
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
  return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
}

// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size)
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
  digitalWrite(LED_BUILTIN, HIGH);

  // Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
  // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
  return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
}

// Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache.
void external_flash_flush_cb (void)
{
  flash.syncBlocks();

  // clear file system's cache to force refresh
  fatfs.cacheClear();

  flash_changed = true;

  digitalWrite(LED_BUILTIN, LOW);
}

Compiled Log as ATTACHED TXT

Using library SPI at version 1.0 in folder: /Users/sklarm/Library/Arduino15/packages/adafruit/hardware/nrf52/1.6.1/libraries/SPI
Using library SdFat - Adafruit Fork at version 2.2.3 in folder: /Users/sklarm/Documents/Arduino/libraries/SdFat_-_Adafruit_Fork
Using library Adafruit SPIFlash at version 4.3.4 in folder: /Users/sklarm/Documents/Arduino/libraries/Adafruit_SPIFlash
Using library Adafruit TinyUSB Library at version 3.3.3 in folder: /Users/sklarm/Documents/Arduino/libraries/Adafruit_TinyUSB_Library
/Users/sklarm/Library/Arduino15/packages/adafruit/tools/arm-none-eabi-gcc/9-2019q4/bin/arm-none-eabi-size -A /private/var/folders/m2/l1rzb2nj4rb0w1sdtcd5_bsh0000gn/T/arduino/sketches/9A7875B9A39C03197040352FDE2DEEC7/msc_external_flash_sdcard.ino.elf
Sketch uses 72212 bytes (8%) of program storage space. Maximum is 815104 bytes.
Global variables use 10424 bytes (4%) of dynamic memory, leaving 227144 bytes for local variables. Maximum is 237568 bytes.

What happened ?

This problem originated in the Adafruit Forums. Reported on an Adafruit Feather RP2040 Adalogger and reproduced behavior on an Adafruit Metro RP2040. Both have built-in SD card holders.

The SD card mounts as is visible from the OS.

/dev/disk5s1 32G 2.1M 32G 1% 0 0 100% /Volumes/SDCARD

Usability is the issue. I can list the files on the card initially. I've not been successful copying the files off.

`
sklarm@grazie ~ % time echo /Volumes/SDCARD/*
/Volumes/SDCARD/adabot.wav /Volumes/SDCARD/hello.wav /Volumes/SDCARD/interesting.wav /Volumes/SDCARD/uhoh.wav /Volumes/SDCARD/whhaatt.wav
sklarm@grazie ~ % time ls /Volumes/SDCARD/*
/Volumes/SDCARD/adabot.wav /Volumes/SDCARD/uhoh.wav
/Volumes/SDCARD/hello.wav /Volumes/SDCARD/whhaatt.wav
/Volumes/SDCARD/interesting.wav
ls --color=auto /Volumes/SDCARD/* 0.00s user 0.01s system 58% cpu 0.012 total
sklarm@grazie ~ % cp /Volumes/SDCARD/* /var/tmp
cp: /Volumes/SDCARD/adabot.wav: Resource busy
cp: /Volumes/SDCARD/hello.wav: Resource busy
cp: /Volumes/SDCARD/interesting.wav: Resource busy
cp: /Volumes/SDCARD/uhoh.wav: Resource busy
cp: /Volumes/SDCARD/whhaatt.wav: Resource busy

`

How to reproduce ?

Modify msc_external_flash_sdcard.ino

  • modfify SDCARD_CS to pin 23

drive mounts, but is not usable.

/dev/disk5s1 32G 2.1M 32G 1% 0 0 100% /Volumes/SDCARD

Debug Log

No response

Screenshots

No response

@mikeysklar mikeysklar added the Bug Something isn't working label Sep 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant