Mass Storage Host Solution

Overview

The USB Mass Storage Class (MSC) protocol establishes a standard communication specification between a host and mass storage devices.

Ameba has implemented a complete USB MSC host protocol stack based on the official MSC protocol standards released by the USB-IF. It supports interaction with MSC devices via the SCSI (Small Computer System Interface) command set, enabling stable and high-speed file reading and writing.

Ameba USB MSC Host

Features

  • Supports standard MSC devices (such as U-disks, SD card readers, etc.)

  • The maximum supported storage capacity is 32GB

  • Supports read and write operations of the FAT32 file system

  • Supports USB hot-plug

  • Automatically parses descriptors and adapts to speed modes

  • Configurable parameters such as BULK transfer length

Application Scenarios

As a USB storage host, Ameba can mount external mass storage devices via the USB interface. By combining this with network technologies to implement various data interactive applications. For example,

  • Smart Network Storage / Private Cloud: Combines network technology to bridge local storage with cloud connectivity, supporting automatic bidirectional file synchronization and secure remote access based on DDNS/VPN, to build a lightweight home private cloud.

  • Industrial IoT Gateway: Caches sensor data or serial logs to USB storage devices in unstable network environments (e.g., mines, offshore), and automatically executes resume-from-break uploads to the cloud once connectivity is restored, ensuring the integrity and reliability of industrial data.

  • AI Media Library & Storage Expansion: Utilizes external storage to house massive media files or AI knowledge bases, overcoming internal Flash capacity limitations to enable local offline retrieval and low-cost functional expansion.

  • Hardware Security Token: During startup or privilege verification, the device scans a connected U disk for specific encrypted certificates or License files; upon successful validation, it activates advanced system privileges, acting as a physically isolated, low-cost hardware authorization lock.

Protocol Introduction

The MSC protocol defines the transmission and control functionalities required to implement storage devices under the USB specification. Common devices that adhere to this standard include USB flash drives, external hard drives, and card readers.

Descriptor Structure

In addition to complying with standard USB descriptor specifications (such as Device Descriptors, Configuration Descriptors, and Endpoint Descriptors), MSC devices are required to:

  • Declare the communication protocol used (e.g., SCSI) via the Interface Descriptor.

  • Encapsulate transmission commands and data through bulk endpoints.

The following section illustrates a standard USB MSC descriptor structure based on the Bulk-Only Transport (BOT) mode utilizing the SCSI command set:

Device Descriptor
└── Identifies basic device information

Configuration Descriptor
└── Contains total length of the entire configuration, power supply information, etc.
│
└── Interface Descriptor(Interface 0, Alternate Setting 0)
    ├── bInterfaceClass: 0x08 (Mass Storage)
    ├── bInterfaceSubClass: 0x06 (SCSI transparent command set)
    ├── bInterfaceProtocol: 0x50 (Bulk-Only Transport)
    └── bNumEndpoints: 2 (2 Endpoints)
        ├── Endpoint Descriptor(BULK IN)
        └── Endpoint Descriptor(BULK OUT)

Device Qualifier Descriptor
└── Device information while running in another speed mode

Other Speed Configuration Descriptor
├── Configuration information while running in another speed mode.
│
└── Interface Descriptor(Interface 0, Alternate Setting 0)
    ├── bInterfaceClass: 0x08 (Mass Storage)
    ├── bInterfaceSubClass: 0x06 (SCSI transparent command set)
    ├── bInterfaceProtocol: 0x50 (Bulk-Only Transport)
    └── bNumEndpoints: 2 (2 Endpoints)
        ├── Endpoint Descriptor(BULK IN)
        └── Endpoint Descriptor(BULK OUT)

Protocol document

The USB-IF has officially released the MSC-class basic protocol and specifications for the BOT transfer protocol. During the development process, please refer to the following core documents:

Software and Hardware Architecture

The figure below illustrates the software and hardware layers that commands and data traverse between the host and the device.

../../../_images/usb_msc_arch.svg

Taking a read operation as an example, when a user reads a file from a U disk, the process is as follows:

  • Host Side:

    • Application Request: The user initiates a file read request within an application (e.g., File Manager).

    • File System Conversion: The file system converts the filename and offset into a Logical Block Address (LBA) read request and generates a standard SCSI READ command.

    • Protocol Encapsulation: The host MSC class driver encapsulates the SCSI command into the command packet format defined by the MSC protocol.

    • Hardware Transmission: The USB host controller driver transmits the data packet to the bus via the physical USB port.

  • Device Side:

    • Hardware Reception: The USB device controller receives the data packet from the physical port.

    • Protocol Parsing: The MSC device class driver verifies the integrity of the packet and parses the encapsulated SCSI command.

    • Media Access: Based on the parsed command parameters (such as LBA address and length), data is read from the underlying storage medium (e.g., an SD card).

    • Data and Status Return: The read data is returned to the host, followed by the command execution status response.

BOT Transmission Flow

Once the MSC device is connected to the host and enumeration is complete, if it is identified as a Mass Storage device supporting BOT (Bulk-Only Transport) mode, all subsequent data communication occurs exclusively through bulk endpoints. Bulk transfers are not strictly time-critical, ensuring maximum data integrity.

According to the MSC BOT transmission protocol specification, all transfers follow a three-stage “Command -> Data -> Status” flow:

  • CBW (Command Block Wrapper): Sent from the host to the device. It encapsulates the specific SCSI command (e.g., READ, WRITE, INQUIRY).

  • Data (Data Stage): Transfers the actual file or control data. (The direction depends on the SCSI command type; for commands without data interaction, this stage is omitted).

  • CSW (Command Status Wrapper): Sent from the device to the host. It reports the execution result of the previous CBW command (Success, Failure, or Phase Error).

../../../_images/usb_msc_bot_flow.svg

The data transmission process is as follows:

  • Host Initiates Request: The host MSC class driver encapsulates the SCSI command into a CBW packet and sends it to the device via the Bulk OUT endpoint.

  • Device Parsing and Execution: The device receives the CBW packet, performs a validity check, and parses the SCSI command. If the CBW is valid, the device operates on the underlying physical storage medium according to the command:

    • Write Operation (e.g., WRITE): Receives the data stream sent by the host via the Bulk OUT endpoint and writes it to the storage medium.

    • Read Operation (e.g., READ): Reads data from the storage medium and transmits it back to the host via the Bulk IN endpoint.

    • No-Data Command (e.g., TEST UNIT READY): Skips the data stage and proceeds directly to the status stage.

  • Device Returns Status: After data transmission is complete (or if no data transmission is required), the device sends a CSW packet via the Bulk IN endpoint to report the command execution result to the host.

  • Host Confirms Completion: The host parses the received CSW packet and checks the bCSWStatus field to confirm whether the command was executed successfully, thereby concluding the operation.

Class-Specific Requests

Control requests for MSC devices are categorized into Standard Requests and Class-Specific Requests.

This section focuses on the Class-Specific Requests unique to the MSC BOT specification. These requests are used to implement specific storage functions. There are only two such requests:

MSC Class-Specific Request

Requirement

Description

Bulk-Only Mass Storage Reset

Mandatory

Resets the device interface and associated endpoints.

Get Max LUN

Mandatory

Queries the maximum number of Logical Units supported by the device.

SCSI Commands

The primary MSC BOT SCSI commands are listed below:

SCSI Command

Requirement

Description

INQUIRY

Mandatory

The first command sent by the host to query device information.

REQUEST_SENSE

Mandatory

Sent by the host to retrieve detailed error information whenever a command fails.

TEST_UNIT_READY

Mandatory

Checks if the device is ready.

READ_CAPACITY(10)

Mandatory

Queries the capacity of the storage medium.

READ(10)

Mandatory

The core command for reading data.

WRITE(10)

Mandatory

The core command for writing data.

MODE_SENSE(6)

Optional

Queries specific device parameters, such as caching policy or write- protection status.

ALLOW_MEDIUM_REMOVAL

Optional

Used to allow or prevent medium removal, implementing the “Safely Remove Hardware” feature.

START_STOP_UNIT

Optional

Used to load or eject the medium.

VERIFY(10)

Optional

Requests the device to verify that specified blocks are readable without transferring data.

READ_FORMAT_CAPACITIES

Optional

Provides more detailed capacity and format information than READ_CAPACITY.

Note

For detailed information on the SCSI standard, please refer to the official documentation.

Class Driver

The USB protocol stack provides a standard MSC host class driver based on the BOT (Bulk-Only Transport) protocol, utilizing the SCSI command set.

Pipe Configuration

Count

Description

2

Control IN/OUT Transfer

1

Bulk IN Transfer

1

Bulk OUT Transfer

Class-Specific Request Implementation

The driver implements two Class-Specific Requests for MSC.

MSC Class-Specific Request

Description

Bulk-Only Mass Storage Reset

The host requests a reset of the transfer when a BOT transfer error occurs.

Get Max LUN

After the device is connected, the host queries the number of Logical Units supported by the device.

SCSI Command Implementation

The SCSI commands implemented by the driver under the MSC BOT specification are listed below. Developers can refer to existing implementations to extend other commands.

  • INQUIRY

  • REQUEST_SENSE

  • TEST_UNIT_READY

  • READ_CAPACITY(10)

  • READ(10)

  • WRITE(10)

FatFS Disk Driver API

The class driver defines a FatFS disk driver USB_disk_Driver typed with ll_diskio_drv:

API

Description

disk_initialize

Initializes USB disk

disk_deinitialize

Deinitializes USB disk

disk_status

Returns disk status (RES_OK/RES_ERROR)

disk_read

Reads data from USB disk (sector-aligned)

disk_write

Writes data to USB disk (requires _USE_WRITE set in FatFS)

disk_ioctl

Implements FatFS IO control commands:

  • CTRL_SYNC: No-op (USB implements write-through)

  • GET_SECTOR_COUNT: Returns total sectors

  • GET_SECTOR_SIZE: Returns sector size

  • GET_BLOCK_SIZE: Returns erase block size

API Reference

For detailed function prototypes and usage, please refer to the Driver API

Application Example

Application Design

Driver Initialization

Use the following example code to define the configuration structure and callback functions, then invoke the initialization interface to initialize the USB host core and the MSC class driver.

static usbh_config_t usbh_cfg = {
  .speed = USB_SPEED_HIGH,
  .ext_intr_enable = USBH_SOF_INTR,
  .isr_priority = INT_PRI_MIDDLE,
  .main_task_priority = 3U,
  .tick_source = USBH_SOF_TICK,
  }

static usbh_msc_cb_t usbh_msc_usr_cb = {
  .attach = usbh_msc_cb_attach,                  /* USB device attach callback */
  .setup = usbh_msc_cb_setup,                    /* USB device setup done, indicate that device is ready for bulk transfer */
};

static usbh_user_cb_t usbh_usr_cb = {
  .process = usbh_msc_cb_process
};

int ret = 0;
ret = usbh_init(&usbh_cfg, &usbh_usr_cb);   /* Initialize USB host core driver with configuration and user callback. */
if (ret != HAL_OK) {
    return;
}

ret = usbh_msc_init(&usbh_msc_usr_cb);          /* Initializes the MSC host class with MSC class user callback. */
if (ret != HAL_OK) {
    usbd_msc_disk_deinit();
    return;
}

File Read And Write

Perform file read and write operations on the device after initialization.

static rtos_sema_t msc_attach_sema;
static __IO int msc_is_ready = 0;

static int usbh_msc_cb_attach(void)
{
  RTK_LOGS(TAG, RTK_LOG_INFO, "ATTACH\n");
  rtos_sema_give(msc_attach_sema);
  return HAL_OK;
}

static int usbh_msc_cb_setup(void)
{
  RTK_LOGS(TAG, RTK_LOG_INFO, "SETUP\n");
  msc_is_ready = 1;
  return HAL_OK;
}

static int usbh_msc_cb_process(usb_host_t *host, u8 msg)
{
  UNUSED(host);

  switch (msg) {
  case USBH_MSG_DISCONNECTED:
    msc_is_ready = 0;
    break;
  case USBH_MSG_CONNECTED:
    break;
  default:
    break;
  }

  return HAL_OK;
}

static u32 filenum = 0;
static u8 *msc_wt_buf;
static u8 *msc_rd_buf;
FATFS fs;
FIL f;
int drv_num = 0;
char logical_drv[4];
char path[64] = {'0'};
u32 br;
u32 bw;

rtos_sema_create(&msc_attach_sema, 0U, 1U);

msc_wt_buf = (u8 *)rtos_mem_zmalloc(USBH_MSC_TEST_BUF_SIZE);
if (msc_wt_buf == NULL) {
  RTK_LOGS(TAG, RTK_LOG_ERROR, "Fail to alloc test buf\n");
  goto exit_deinit;
}

msc_rd_buf = (u8 *)rtos_mem_zmalloc(USBH_MSC_TEST_BUF_SIZE);
if (msc_rd_buf == NULL) {
  RTK_LOGS(TAG, RTK_LOG_ERROR, "Fail to alloc test buf\n");
  goto exit_deinit;
}

/* Register USB disk driver to fatfs*/
drv_num = FATFS_RegisterDiskDriver(&USB_disk_Driver);
if (drv_num < 0) {
  RTK_LOGS(TAG, RTK_LOG_ERROR, "Fail to register\n");
  goto exit_deinit;
}

logical_drv[0] = drv_num + '0';
logical_drv[1] = ':';
logical_drv[2] = '/';
logical_drv[3] = 0;

while (1) {
  if (msc_is_ready) {
    rtos_time_delay_ms(10);  /* Wait for MSC device is ready for class-specific communication */
    break;
  }
}

/* Mount logical drive */
if (f_mount(&fs, logical_drv, 1) != FR_OK) {
  RTK_LOGS(TAG, RTK_LOG_ERROR, "Fail to mount logical drive\n");
  FATFS_UnRegisterDiskDriver(drv_num);
  goto exit_deinit;
}

while (1) {
  if (rtos_sema_take(msc_attach_sema, RTOS_SEMA_MAX_COUNT) != RTK_SUCCESS) {
    RTK_LOGS(TAG, RTK_LOG_ERROR, "Fail to take sema\n");
    continue;                /* Wait for MSC device attach*/
  }
}

/* Construct the device file path */
strcpy(path, logical_drv);
sprintf(&path[3], "TEST%ld.DAT", filenum);

/* Open test file */
f_open(&f, path, FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
/* Write the data from a buffer to an opened file */
f_write(&f, (void *)msc_wt_buf, USBH_MSC_TEST_BUF_SIZE, (UINT *)&bw);
/* Move the file pointer to the file head */
f_lseek(&f, 0);
/* Read data from an opened file to a buffer */
f_read(&f, (void *)msc_rd_buf, USBH_MSC_TEST_BUF_SIZE, (UINT *)&br);
/* Close source file */
f_close(&f);

exit_deinit:

  rtos_sema_delete(msc_attach_sema);

  if (msc_wt_buf) {
    rtos_mem_free(msc_wt_buf);
  }
  if (msc_rd_buf) {
    rtos_mem_free(msc_rd_buf);
  }

  usbh_msc_deinit();
  usbh_deinit();
  return;

Driver Deinitialization

When storage functionality is no longer needed or during system shutdown, release resources in the reverse order of initialization.

/* Deinitialize MSC host class driver. */
usbh_msc_deinit();
/* Deinitialize USB host core driver. */
usbh_deinit();

Operation method

This section introduces a complete USB Mass Storage (MSC) application example, which demonstrates how to configure the Ameba development board as a USB storage host through the MSC protocol stack.

When the development board is connected to a standard MSC device such as a U-disk supporting the FAT32 format, the host can recognize it and perform simple file read and write tests based on FatFS.

Example path: {SDK}/example/usb/usbh_msc. It provides a complete design reference for developers designing custom USB storage host products.

Configuration and Compilation

  • Compilation and Flashing

    Execute the following commands in the SDK root directory to configure the environment, select the target SoC, compile the project, and flash the generated Image file to the development board.

    # Initialize environment (required for every new terminal)
    source env.sh or env.bat(Windows system)
    
    # Select Target SoC (replace xxx with your specific SoCs)
    ameba.py soc xxx
    
    ameba.py build -a usbh_msc -p
    
  • Confirmation of Menuconfig configuration

    If compilation fails, please execute ameba.py menuconfig and confirm that USBH MSC has been selected.

    - Choose `CONFIG USB --->`:
    
      [*] Enable USB
          USB Mode (Host)  --->
      [*] MSC
    

Verification

  • Device Startup

    Reset the development board and observe the serial log; it should display the following startup message:

    [MSC-I] USBH MSC demo start
    [MSC-I] Register USB disk
    [MSC-I] FatFS USB W/R performance test start...
    
  • Connect to Device

    Connect a U-disk (formatted as FatFS) to the USB port of the development board using a OTG cable.

  • Recognition and Testing

    The Ameba development board will identify the MSC device and perform read/write performance tests.

    [USBH-A] Device attached,speed 0
    [USBH-A] PID: 0x6545
    [USBH-A] VID: 0x0930
    [USBH-A] Address 1 assigned
    [USBH-A] MFG: TOSHIBA
    [USBH-A] PROD: TransMemory
    [USBH-A] SN: C03FD5F7715FE3417000DE76
    [USBH-A] Enum done, total 1 cfg
    [USBH-A] Switch to itf: 0
    [USBH-A] Class: 0x08
    [USBH-A] SubClass: 0x06
    [USBH-A] Protocol: 0x50
    [MSC-I] ATTACH
    [MSC-I] Max lun 1
    [MSC-I] Lun 0
    [MSC-I] SETUP
    [MSC-I] Open file: 0:/TEST0.DAT
    [MSC-I] W test: size 512, round 20...
    [MSC-I] W rate 204.0 KB/s for 20 round @ 49 ms
    [MSC-I] R test: size = 512 round = 20...
    [MSC-I] R rate 476.1 KB/s for 20 round @ 21 ms
    [MSC-I] W test: size 1024, round 20...
    [MSC-I] W rate 540.5 KB/s for 20 round @ 37 ms
    [MSC-I] R test: size = 1024 round = 20...
    [MSC-I] R rate 800.0 KB/s for 20 round @ 25 ms
    [MSC-I] W test: size 2048, round 20...
    [MSC-I] W rate 655.7 KB/s for 20 round @ 61 ms
    [MSC-I] R test: size = 2048 round = 20...
    [MSC-I] R rate 1212.1 KB/s for 20 round @ 33 ms
    [MSC-I] W test: size 4096, round 20...
    [MSC-I] W rate 1095.8 KB/s for 20 round @ 73 ms
    [MSC-I] R test: size = 4096 round = 20...
    [MSC-I] R rate 1600.0 KB/s for 20 round @ 50 ms
    [MSC-I] FatFS USB W/R performance test done
    [MSC-I] File close OK