Here's the code:
Code: Select all
// MIT License header skipped for forum post
#include "SPI.h"
#include "SdFat.h"
#include "Adafruit_SPIFlash.h"
#include "Adafruit_TinyUSB.h"
Adafruit_FlashTransport_RP2040 flashTransport;
Adafruit_SPIFlash flash(&flashTransport);
// file system object from SdFat
FatVolume fatfs;
FatFile root;
FatFile file;
// USB Mass Storage object
Adafruit_USBD_MSC usb_msc;
// Check if flash is formatted
bool fs_formatted;
// Set to true when PC write to flash
bool fs_changed;
// the setup function runs once when you press reset or power the board
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
flash.begin();
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
usb_msc.setID("Adafruit", "External Flash", "1.0");
// Set callback
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
// Set disk size, block size should be 512 regardless of spi flash page size
usb_msc.setCapacity(flash.size() / 512, 512);
// MSC is ready for read/write
usb_msc.setUnitReady(true);
usb_msc.begin();
// Init file system on the flash
fs_formatted = fatfs.begin(&flash);
Serial.begin(115200);
while ( !Serial ) delay(10); // wait for native usb
if ( !fs_formatted )
{
Serial.println("Failed to init files system, flash may not be formatted");
}
Serial.println("Adafruit TinyUSB Mass Storage External Flash example");
Serial.print("JEDEC ID: 0x"); Serial.println(flash.getJEDECID(), HEX);
Serial.print("Flash size: "); Serial.print(flash.size() / 1024); Serial.println(" KB");
fs_changed = true; // to print contents initially
}
void loop()
{
if ( fs_changed )
{
fs_changed = false;
// delay(1000);
// check if host formatted disk
if (!fs_formatted)
{
fs_formatted = fatfs.begin(&flash);
}
// skip if still not formatted
if (!fs_formatted) return;
File32 readFile = fatfs.open("test.hex", FILE_READ);
if (!readFile) {
Serial.println("Error, failed to open test.hex for reading!");
// while (1) yield();
}
else {
Serial.print("Entire contents of test.hex, ");
Serial.print(readFile.available(), DEC);
Serial.println(" bytes");
while (readFile.available()) {
// delay(1);
char c = readFile.read();
if (c < 255) {
Serial.print(c);
}
else {
Serial.println(" ERROR"); // don't print non-ASCII chars
break;
}
}
}
readFile.close();
}
delay (5000); // don't refresh all the time
}
// callbacks copied verbatim from msc_external_flash example
// 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 msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
{
// Note: SPIFLash Block 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 msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
digitalWrite(LED_BUILTIN, HIGH);
// Note: SPIFLash Block 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 msc_flush_cb (void)
{
// sync with flash
flash.syncBlocks();
// clear file system's cache to force refresh
fatfs.cacheClear();
fs_changed = true;
digitalWrite(LED_BUILTIN, LOW);
}
Code: Select all
Entire contents of test.hex, 1448 bytes
:4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0
:400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080
:400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040
:4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
:4001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BF
:40014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007F
:40018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F
:4001C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF
:020200000000FC
:4008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B8
:020840000000B6
:321000004A29A514000000000000000000000000000000000000000000000000FF7F000000000000A08CE001E0016009C0030000C40630
:0A180000FFFF10A4200010D4B6036F
:00000001FF
If I instead copy the file to the drive while the program is running, I get this:
Code: Select all
Entire contents of test.hex, 1448 bytes
:4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0
:400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080
:400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040
:4000C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ERROR
Frustratingly, sometimes this all actually works, and I get all 1488 bytes read. Sometimes I only get 512 bytes read. But the file always copies correctly, if I read it back it's identical to the source. And if I restart the Pico with the file already in flash, the results are correct. Both good and bad results are showing me 1488 bytes in the file, but the bad reads only get part of the result before it chokes and gives me an error.
What am I doing wrong here? The file is copying correctly, all the MSC stuff seems to be working fine. I think the issue might be with the SDFatLib, but this is my first time using it and so I'm not sure where to start looking to debug this.
Thanks!