Skip to content

Commit b0a7ab1

Browse files
authored
Merge pull request #131 from espressif/fix/msc_device_performance
fix(tusb_msc): Cache sector metrics, enable storage buffering
2 parents 535e258 + c30af29 commit b0a7ab1

File tree

1 file changed

+105
-39
lines changed

1 file changed

+105
-39
lines changed

device/esp_tinyusb/tusb_msc_storage.c

Lines changed: 105 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,41 +13,69 @@
1313
#include "diskio_wl.h"
1414
#include "wear_levelling.h"
1515
#include "esp_partition.h"
16+
#include "esp_memory_utils.h"
17+
#include "sdkconfig.h"
1618
#include "vfs_fat_internal.h"
1719
#include "tinyusb.h"
20+
#include "device/usbd_pvt.h"
1821
#include "class/msc/msc_device.h"
1922
#include "tusb_msc_storage.h"
20-
#include "esp_vfs_fat.h"
2123
#if SOC_SDMMC_HOST_SUPPORTED
2224
#include "diskio_sdmmc.h"
2325
#endif
2426

2527
static const char *TAG = "tinyusb_msc_storage";
2628

29+
#define MSC_STORAGE_MEM_ALIGN 4
30+
#define MSC_STORAGE_BUFFER_SIZE CONFIG_TINYUSB_MSC_BUFSIZE /*!< Size of the buffer, configured via menuconfig (MSC FIFO size) */
31+
32+
#if ((MSC_STORAGE_BUFFER_SIZE) % MSC_STORAGE_MEM_ALIGN != 0)
33+
#error "CONFIG_TINYUSB_MSC_BUFSIZE must be divisible by MSC_STORAGE_MEM_ALIGN. Adjust your configuration (MSC FIFO size) in menuconfig."
34+
#endif
35+
2736
// CONFIG_TINYUSB_MSC_BUFSIZE must be bigger, or equal to the CONFIG_WL_SECTOR_SIZE
2837
#if (CONFIG_TINYUSB_MSC_BUFSIZE < CONFIG_WL_SECTOR_SIZE)
2938
#error "CONFIG_TINYUSB_MSC_BUFSIZE must be at least at the size of CONFIG_WL_SECTOR_SIZE"
3039
#endif
3140

41+
/**
42+
* @brief Structure representing a single write buffer for MSC operations.
43+
*/
3244
typedef struct {
33-
bool is_fat_mounted;
34-
const char *base_path;
45+
uint8_t data_buffer[MSC_STORAGE_BUFFER_SIZE]; /*!< Buffer to store write data. The size is defined by MSC_STORAGE_BUFFER_SIZE. */
46+
uint32_t lba; /*!< Logical Block Address for the current WRITE10 operation. */
47+
uint32_t offset; /*!< Offset within the specified LBA for the current write operation. */
48+
uint32_t bufsize; /*!< Number of bytes to be written in this operation. */
49+
} msc_storage_buffer_t;
50+
51+
/**
52+
* @brief Handle for TinyUSB MSC storage interface.
53+
*
54+
* This structure holds metadata and function pointers required to
55+
* manage the underlying storage medium (SPI flash, SDMMC).
56+
*/
57+
typedef struct {
58+
msc_storage_buffer_t storage_buffer;
59+
bool is_fat_mounted; /*!< Indicates if the FAT filesystem is currently mounted. */
60+
const char *base_path; /*!< Base path where the filesystem is mounted. */
3561
union {
36-
wl_handle_t wl_handle;
62+
wl_handle_t wl_handle; /*!< Handle for wear leveling on SPI flash. */
3763
#if SOC_SDMMC_HOST_SUPPORTED
38-
sdmmc_card_t *card;
64+
sdmmc_card_t *card; /*!< Handle for SDMMC card. */
3965
#endif
4066
};
41-
esp_err_t (*mount)(BYTE pdrv);
42-
esp_err_t (*unmount)(void);
43-
uint32_t (*sector_count)(void);
44-
uint32_t (*sector_size)(void);
45-
esp_err_t (*read)(size_t sector_size, uint32_t lba, uint32_t offset, size_t size, void *dest);
46-
esp_err_t (*write)(size_t sector_size, size_t addr, uint32_t lba, uint32_t offset, size_t size, const void *src);
47-
tusb_msc_callback_t callback_mount_changed;
48-
tusb_msc_callback_t callback_premount_changed;
49-
int max_files;
50-
} tinyusb_msc_storage_handle_s; /*!< MSC object */
67+
esp_err_t (*mount)(BYTE pdrv); /*!< Pointer to the mount function. */
68+
esp_err_t (*unmount)(void); /*!< Pointer to the unmount function. */
69+
uint32_t sector_count; /*!< Total number of sectors in the storage medium. */
70+
uint32_t sector_size; /*!< Size of a single sector in bytes. */
71+
esp_err_t (*read)(size_t sector_size, /*!< Function pointer for reading data. */
72+
uint32_t lba, uint32_t offset, size_t size, void *dest);
73+
esp_err_t (*write)(size_t sector_size, /*!< Function pointer for writing data. */
74+
size_t addr, uint32_t lba, uint32_t offset, size_t size, const void *src);
75+
tusb_msc_callback_t callback_mount_changed; /*!< Callback for mount state change. */
76+
tusb_msc_callback_t callback_premount_changed; /*!< Callback for pre-mount state change. */
77+
int max_files; /*!< Maximum number of files that can be open simultaneously. */
78+
} tinyusb_msc_storage_handle_s;
5179

5280
/* handle of tinyusb driver connected to application */
5381
static tinyusb_msc_storage_handle_s *s_storage_handle;
@@ -175,7 +203,7 @@ static esp_err_t _write_sector_sdmmc(size_t sector_size,
175203
}
176204
#endif
177205

178-
static esp_err_t msc_storage_read_sector(uint32_t lba,
206+
static esp_err_t _msc_storage_read_sector(uint32_t lba,
179207
uint32_t offset,
180208
size_t size,
181209
void *dest)
@@ -185,7 +213,7 @@ static esp_err_t msc_storage_read_sector(uint32_t lba,
185213
return (s_storage_handle->read)(sector_size, lba, offset, size, dest);
186214
}
187215

188-
static esp_err_t msc_storage_write_sector(uint32_t lba,
216+
static esp_err_t _msc_storage_write_sector(uint32_t lba,
189217
uint32_t offset,
190218
size_t size,
191219
const void *src)
@@ -254,6 +282,29 @@ static esp_err_t _mount(char *drv, FATFS *fs)
254282
return ret;
255283
}
256284

285+
/**
286+
* @brief Handles deferred USB MSC write operations.
287+
*
288+
* This function is invoked via TinyUSB's deferred execution mechanism to perform
289+
* write operations to the underlying storage. It writes data from the
290+
* `storage_buffer` stored within the `s_storage_handle`.
291+
*
292+
* @param param Unused. Present for compatibility with deferred function signature.
293+
*/
294+
static void _write_func(void *param)
295+
{
296+
// Process the data in storage_buffer
297+
esp_err_t err = _msc_storage_write_sector(
298+
s_storage_handle->storage_buffer.lba,
299+
s_storage_handle->storage_buffer.offset,
300+
s_storage_handle->storage_buffer.bufsize,
301+
(const void *)s_storage_handle->storage_buffer.data_buffer
302+
);
303+
if (err != ESP_OK) {
304+
ESP_LOGE(TAG, "Write failed, error=0x%x", err);
305+
}
306+
}
307+
257308
esp_err_t tinyusb_msc_storage_mount(const char *base_path)
258309
{
259310
esp_err_t ret = ESP_OK;
@@ -369,29 +420,29 @@ esp_err_t tinyusb_msc_storage_unmount(void)
369420
uint32_t tinyusb_msc_storage_get_sector_count(void)
370421
{
371422
assert(s_storage_handle);
372-
return (s_storage_handle->sector_count)();
423+
return (s_storage_handle->sector_count);
373424
}
374425

375426
uint32_t tinyusb_msc_storage_get_sector_size(void)
376427
{
377428
assert(s_storage_handle);
378-
return (s_storage_handle->sector_size)();
429+
return (s_storage_handle->sector_size);
379430
}
380431

381432
esp_err_t tinyusb_msc_storage_init_spiflash(const tinyusb_msc_spiflash_config_t *config)
382433
{
383434
assert(!s_storage_handle);
384-
s_storage_handle = (tinyusb_msc_storage_handle_s *)malloc(sizeof(tinyusb_msc_storage_handle_s));
385-
ESP_RETURN_ON_FALSE(s_storage_handle, ESP_ERR_NO_MEM, TAG, "could not allocate new handle for storage");
435+
s_storage_handle = (tinyusb_msc_storage_handle_s *)heap_caps_aligned_alloc(MSC_STORAGE_MEM_ALIGN, sizeof(tinyusb_msc_storage_handle_s), MALLOC_CAP_DMA);
436+
ESP_RETURN_ON_FALSE(s_storage_handle, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory for storage handle");
386437
s_storage_handle->mount = &_mount_spiflash;
387438
s_storage_handle->unmount = &_unmount_spiflash;
388-
s_storage_handle->sector_count = &_get_sector_count_spiflash;
389-
s_storage_handle->sector_size = &_get_sector_size_spiflash;
439+
s_storage_handle->wl_handle = config->wl_handle;
440+
s_storage_handle->sector_count = _get_sector_count_spiflash();
441+
s_storage_handle->sector_size = _get_sector_size_spiflash();
390442
s_storage_handle->read = &_read_sector_spiflash;
391443
s_storage_handle->write = &_write_sector_spiflash;
392444
s_storage_handle->is_fat_mounted = false;
393445
s_storage_handle->base_path = NULL;
394-
s_storage_handle->wl_handle = config->wl_handle;
395446
// In case the user does not set mount_config.max_files
396447
// and for backward compatibility with versions <1.4.2
397448
// max_files is set to 2
@@ -410,24 +461,28 @@ esp_err_t tinyusb_msc_storage_init_spiflash(const tinyusb_msc_spiflash_config_t
410461
tinyusb_msc_unregister_callback(TINYUSB_MSC_EVENT_PREMOUNT_CHANGED);
411462
}
412463

464+
if (!esp_ptr_dma_capable((const void *)s_storage_handle->storage_buffer.data_buffer)) {
465+
ESP_LOGW(TAG, "storage buffer is not DMA capable");
466+
}
467+
413468
return ESP_OK;
414469
}
415470

416471
#if SOC_SDMMC_HOST_SUPPORTED
417472
esp_err_t tinyusb_msc_storage_init_sdmmc(const tinyusb_msc_sdmmc_config_t *config)
418473
{
419474
assert(!s_storage_handle);
420-
s_storage_handle = (tinyusb_msc_storage_handle_s *)malloc(sizeof(tinyusb_msc_storage_handle_s));
421-
ESP_RETURN_ON_FALSE(s_storage_handle, ESP_ERR_NO_MEM, TAG, "could not allocate new handle for storage");
475+
s_storage_handle = (tinyusb_msc_storage_handle_s *)heap_caps_aligned_alloc(MSC_STORAGE_MEM_ALIGN, sizeof(tinyusb_msc_storage_handle_s), MALLOC_CAP_DMA);
476+
ESP_RETURN_ON_FALSE(s_storage_handle, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory for storage handle");
422477
s_storage_handle->mount = &_mount_sdmmc;
423478
s_storage_handle->unmount = &_unmount_sdmmc;
424-
s_storage_handle->sector_count = &_get_sector_count_sdmmc;
425-
s_storage_handle->sector_size = &_get_sector_size_sdmmc;
479+
s_storage_handle->card = config->card;
480+
s_storage_handle->sector_count = _get_sector_count_sdmmc();
481+
s_storage_handle->sector_size = _get_sector_size_sdmmc();
426482
s_storage_handle->read = &_read_sector_sdmmc;
427483
s_storage_handle->write = &_write_sector_sdmmc;
428484
s_storage_handle->is_fat_mounted = false;
429485
s_storage_handle->base_path = NULL;
430-
s_storage_handle->card = config->card;
431486
// In case the user does not set mount_config.max_files
432487
// and for backward compatibility with versions <1.4.2
433488
// max_files is set to 2
@@ -446,15 +501,20 @@ esp_err_t tinyusb_msc_storage_init_sdmmc(const tinyusb_msc_sdmmc_config_t *confi
446501
tinyusb_msc_unregister_callback(TINYUSB_MSC_EVENT_PREMOUNT_CHANGED);
447502
}
448503

504+
if (!esp_ptr_dma_capable((const void *)s_storage_handle->storage_buffer.data_buffer)) {
505+
ESP_LOGW(TAG, "storage buffer is not DMA capable");
506+
}
507+
449508
return ESP_OK;
450509
}
451510
#endif
452511

453512
void tinyusb_msc_storage_deinit(void)
454513
{
455-
assert(s_storage_handle);
456-
free(s_storage_handle);
457-
s_storage_handle = NULL;
514+
if (s_storage_handle) {
515+
heap_caps_free(s_storage_handle);
516+
s_storage_handle = NULL;
517+
}
458518
}
459519

460520
esp_err_t tinyusb_msc_register_callback(tinyusb_msc_event_type_t event_type,
@@ -513,7 +573,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
513573
(void) lun;
514574
const char vid[] = "TinyUSB";
515575
const char pid[] = "Flash Storage";
516-
const char rev[] = "0.1";
576+
const char rev[] = "0.2";
517577

518578
memcpy(vendor_id, vid, strlen(vid));
519579
memcpy(product_id, pid, strlen(pid));
@@ -572,7 +632,7 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
572632
// - Application fill the buffer (up to bufsize) with address contents and return number of read byte.
573633
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize)
574634
{
575-
esp_err_t err = msc_storage_read_sector(lba, offset, bufsize, buffer);
635+
esp_err_t err = _msc_storage_read_sector(lba, offset, bufsize, buffer);
576636
if (err != ESP_OK) {
577637
ESP_LOGE(TAG, "msc_storage_read_sector failed: 0x%x", err);
578638
return 0;
@@ -585,11 +645,17 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
585645
// - Application write data from buffer to address contents (up to bufsize) and return number of written byte.
586646
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize)
587647
{
588-
esp_err_t err = msc_storage_write_sector(lba, offset, bufsize, buffer);
589-
if (err != ESP_OK) {
590-
ESP_LOGE(TAG, "msc_storage_write_sector failed: 0x%x", err);
591-
return 0;
592-
}
648+
assert(bufsize <= MSC_STORAGE_BUFFER_SIZE);
649+
// Copy data to the buffer
650+
memcpy((void *)s_storage_handle->storage_buffer.data_buffer, buffer, bufsize);
651+
s_storage_handle->storage_buffer.lba = lba;
652+
s_storage_handle->storage_buffer.offset = offset;
653+
s_storage_handle->storage_buffer.bufsize = bufsize;
654+
655+
// Defer execution of the write to the TinyUSB task
656+
usbd_defer_func(_write_func, NULL, false);
657+
658+
// Return the number of bytes accepted
593659
return bufsize;
594660
}
595661

0 commit comments

Comments
 (0)