ESP32S3 Adafruit TinyUSB access Internal Flash

Hello folks,

I have an Adafruit ESP32S3 TFT Reverse. I used it to build a data logger.
I initially developed the data logger in the Arduino IDE. I use this for a quick proof of work.

I would now like to move this data logger to an ESP32S3 dev board. Because it has more internal memory (16MB) and I don’t need the display.

My data logger worked with the Adafruit board.
I can’t get it to work with the dev board and I have no idea why.

I have broken down my code (which comes from the Adafruit example) to the essentials.

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

// Debug with FTDI (Serial0) or USBCDC (Serial)
#define DBG_SERIAL Serial

// ESP32 use same flash device that store code.
// Therefore there is no need to specify the SPI and SS
Adafruit_FlashTransport_ESP32 flashTransport;
Adafruit_SPIFlash flash(&flashTransport);

// file system object from SdFat
FatVolume fatfs;

// USB Mass Storage object
Adafruit_USBD_MSC usb_msc;

bool fs_formatted;  // Check if flash is formatted
bool fs_changed;    // Set to true when browser write to flash

//--------------------------------------------------------------------+
// Setup
//--------------------------------------------------------------------+

void setupMassStorage(void)
{
  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
  fs_changed = false;
  usb_msc.setReadyCallback(0, msc_ready_callback);

  usb_msc.begin();

  // Init file system on the flash
  fs_formatted = fatfs.begin(&flash);

  if ( !fs_formatted )
  {
    DBG_SERIAL.println("Failed to init files system, flash may not be formatted");
  }
}

void refreshMassStorage(void)
{
  fs_changed = true;
}

void setup()
{
#ifdef LED_BUILTIN
  pinMode(LED_BUILTIN, OUTPUT);
#endif

  DBG_SERIAL.begin(115200);

  setupMassStorage();

  //  while ( !DBG_SERIAL ) delay(10);   // wait for native usb
  DBG_SERIAL.println("TinyUSB Mass Storage with ESP32 File Browser example");
  DBG_SERIAL.print("JEDEC ID: 0x"); DBG_SERIAL.println(flash.getJEDECID(), HEX);
  DBG_SERIAL.print("Flash size: "); DBG_SERIAL.print(flash.size() / 1024); DBG_SERIAL.println(" KB");

}

//--------------------------------------------------------------------+
// Loop
//--------------------------------------------------------------------+

void loop()
{
  delay(2);//allow the cpu to switch to other tasks
}

// 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 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 msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
#ifdef LED_BUILTIN
  digitalWrite(LED_BUILTIN, HIGH);
#endif

  // 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 msc_flush_cb (void)
{
  // sync with flash
  flash.syncBlocks();

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

#ifdef LED_BUILTIN
  digitalWrite(LED_BUILTIN, LOW);
#endif
}

// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool msc_ready_callback(void)
{
  // if fs has changed, mark unit as not ready temporarily to force PC to flush cache
  bool ret = !fs_changed;
  fs_changed = false;
  return ret;
}

And here the ini File:

[env:esp32-s3-devkitm-1]
platform = espressif32
board = esp32-s3-devkitm-1
framework = arduino
board_build.partitions = ffat.csv
lib_deps = 
	adafruit/Adafruit TinyUSB Library@^3.1.3
	adafruit/Adafruit SPIFlash@^4.3.4
build_unflags = 
    -DARDUINO_USB_MODE = 1
build_flags =
    -DARDUINO_USB_CDC_ON_BOOT=1
    -DUSE_TINYUSB=true
    -DCDC_ENABLED=0
    -DCORE_DEBUG_LEVEL=5
    -DARDUINO_USB_MODE=0

; Serial Monitor options
monitor_speed = 115200

My attempts:

  1. Adafruit TFT Rev - Arduino IDE: Code works. Internal memory is accessible via USB.
  2. dev board - Arduino IDE: This is where the problems start. The memory is recognised correctly. The code tells me the size of the internal memory in the terminal. USB does not work.
  3. Dev Board - Platformio: Immediate kernel panic.

Does anyone have an idea what the problem could be?
I am surprised that the example in the Arduino IDE works with the Adafruit board, but not with the Dev Board.

Which ESP32-S3 module do you have exactly?

  • How much RAM / PSRAM does it have and how is it connected (quad / ocatal)

Please describe in detail what exactly is not working.

  • ESP is crashing
  • No serial output
  • Sketch not running as expected
  • something else …

Did you try a simple blink sketch?

Hey,
i have a ESP32-S3 WROOM-1-N16R8.

I have carried out further debugging and have now reached the following status:

in Platformio the ESP32S3 dev module recognises the flash correctly. No more Kernel Panic.

TinyUSB Mass Storage with ESP32 File Browser example
JEDEC ID: 0x5E4018
Flash size: 12160 KB

However, the ESP does not register as a mass storage device on the computer.

My actual platfomrio.ini:

[env:esp32-s3-devkitm-1]
platform = espressif32
board = esp32-s3-devkitm-1
board_upload.flash_size=16MB
framework = arduino
board_build.partitions = ffat.csv
lib_deps = 
	adafruit/Adafruit TinyUSB Library@^3.1.3
	adafruit/Adafruit SPIFlash@^4.3.4


build_unflags = 
    -DARDUINO_USB_MODE=1
build_flags =
    -DARDUINO_USB_CDC_ON_BOOT=1
    -DUSE_TINYUSB=true
    -DCDC_ENABLED=0
    -DCORE_DEBUG_LEVEL=5
    -DARDUINO_USB_MODE=0
	'-DCFG_TUSB_CONFIG_FILE="C:\Users\User\.platformio\packages\framework-arduinoespressif32\tools\sdk\esp32s3\include\arduino_tinyusb\include\tusb_config.h"'

; Serial Monitor options
monitor_speed = 115200
monitor_filters = esp32_exception_decoder

I take this as an answer to my unanswered questions. :wink:

You can use esp32-s3-devkitc1-n16r8.json from my boards repo.

I have no knowledge of using an ESP32-S3 board as a mass storage device. Perhaps someone else here has the relevant knowledge and can help you.

I am talking about the internal flash of the ESP32 module. Sorry if that was not clear.

I will take a look.

Take a look

I’ll give it a try and report my result.

1 Like