Mass Storage Device Solution

Overview

The USB Mass Storage Class (MSC) protocol defines the standard interface and transmission specifications for USB mass storage devices (such as U disks and SD card readers).

Based on the official MSC protocol standard released by USB-IF, Ameba implements complete USB storage device functionality. It supports interaction with the host via the SCSI (Small Computer System Interface) command set, providing efficient capabilities for reading, writing, erasing, and querying the status of storage media.

Ameba USB MSC Device

Features

  • Supports Bulk-Only Transport (BOT) protocol

  • Supports Svarious storage medium

    • RAM

    • SD Card (SD Mode: using SDIO interface)

    • SD Card (SPI Mode: using SPI interface)

    • External Flash

  • Supports USB hot-plug

  • Supports fully customizable descriptors

  • Supports configuring parameters such as speed mode

Application Scenarios

As a USB storage device, Ameba supports flexible access and management of various storage media. It can be combined with wireless connection technologies, such as Wi-Fi and Bluetooth, to implement diverse data storage and interaction solutions. For example,

  • Personal Storage and Wireless Expansion: Ameba can function as a standard U disk or SD/TF card reader for file transfer, system boot disk creation, and in-car media playback. When combined with Wi-Fi or Bluetooth, it upgrades to a “Wireless USB Drive,” allowing mobile phones or PCs to access storage content via a wireless network, breaking the physical limitations of traditional wired connections.

  • Multimedia Device Data Bridging: In applications such as digital cameras, dashcams, or digital multimedia players (MP3/MP4), Ameba emulates internal storage or expansion cards as a generic USB drive. When connected to a PC, users can manage photos, videos, and music files directly via drag-and-drop.

  • Convenient Firmware Upgrade: When connected to a PC, the device is recognized as a storage drive. Users simply need to drag the new firmware file (e.g., in .bin or .uf2 format) into the drive. The device automatically verifies the file and completes the system update, significantly lowering the maintenance barrier for end-users.

  • Smart Industrial Data Logger: Addressing data acquisition needs in industrial, agricultural, or scientific research fields, Bluetooth is used for low-power parameter configuration (e.g., modifying sampling frequency or file naming rules). When processing massive amounts of historical data, the device connects to a PC via the USB interface for high-speed export, balancing configuration flexibility with transmission efficiency.

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

Descriptor Implementation

This section presents the MSC class descriptor structures defined at the driver layer. These structures correspond to the standard descriptor definitions in the USB protocol specification.

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)

Full customization of device descriptors is supported. Refer to Device Descriptor Customization .

Endpoint Configurations

Endpoint

Count

Description

Control IN/OUT Endpoint

1

Handles control requests sent by the USB host.

Bulk IN Endpoint

1

Sends data to the USB host.

Bulk OUT Endpoint

1

Receives data from the USB host.

Implementation of Class-Specific Requests

The driver implements two Class-Specific Requests for MSC.

MSC Class-Specific Request

Description

Bulk-Only Mass Storage Reset

Resets the BOT transmission state and prepares to receive the next CSW.

Get Max LUN

The driver currently supports only one Logical Unit.

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.

SCSI Command

Description

INQUIRY

Returns constant MSC device information.

REQUEST_SENSE

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

TEST_UNIT_READY

Indicates if the device is ready to receive the next command.

READ_CAPACITY(10)

Returns the capacity of the storage medium.

READ(10)

Reads from the storage medium.

WRITE(10)

Writes data to the storage medium.

MODE_SENSE(6)

Returns constant MSC device parameters.

ALLOW_MEDIUM_REMOVAL

The MSC driver does not support medium removal and returns success directly.

START_STOP_UNIT

The MSC driver does not support loading/ejecting media; the medium is usable once initialized.

VERIFY(10)

Checks if the specified block address is within a reasonable range.

READ_FORMAT_CAPACITIES

Provides more detailed capacity and format information than READ_CAPACITY.

MODE_SENSE(10)

Returns more constant MSC device parameters than MODE_SENSE(6).

MODE_SELECT(6)

Does not allow the host to modify internal parameters; the driver returns success directly.

MODE_SELECT(10)

Same implementation as MODE_SELECT(6).

READ(12)

Same implementation as READ(10).

WRITE(12)

Same implementation as WRITE(10).

API Reference

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

Application Example

Application Design

This section outlines the complete usageflow of the MSC driver, covering core stages such as initialization and hot-plug management.

Driver Initialization

Define the configuration structure and callback functions, then call the initialization interface to initialize the underlying storage, the USB device core and the MSC class driver.

static usbd_config_t usbd_msc_cfg = {
    .speed = CONFIG_USBD_MSC_SPEED,
    .isr_priority = INT_PRI_MIDDLE,
};

static usbd_msc_cb_t usbd_msc_cb = {
    .status_changed = usbd_msc_cb_status_changed  /* USB status change callback. */
};

int ret = 0;
ret = usbd_msc_disk_init();    /* Initializes the underlying storage disk. */
if (ret != HAL_OK) {
    return;
}

ret = usbd_init(&usbd_msc_cfg);     /* Initialize USB device core driver with configuration. */
if (ret != HAL_OK) {
    usbd_msc_disk_deinit();
    return;
}

ret = usbd_msc_init(&usbd_msc_cb);  /* Initializes the MSC device class. */
if (ret != HAL_OK) {
    usbd_msc_disk_deinit();
    usbd_deinit();
    return;
}

USB Hot-plug Event Handling

Monitor USB connection status changes (connected/disconnected) by registering the status_changed callback function.

Refer to Device Connection Status Detection for more details.

Note

It is recommended to use a semaphore to notify a dedicated task thread for processing, avoiding time-consuming operations within the interrupt context.

static u8 msc_usb_attach_status;
static rtos_sema_t msc_usb_status_changed_sema;

static usbd_msc_cb_t usbd_msc_cb = {
    .status_changed = usbd_msc_cb_status_changed   /* USB status change callback. */
};

/* Callback executed in ISR context */
static void usbd_msc_cb_status_changed(u8 old_status, u8 status)
{
  RTK_LOGS(TAG, RTK_LOG_INFO, "USB status change: %d -> %d\n", old_status, status);
  msc_usb_attach_status = status;
  rtos_sema_give(msc_usb_status_changed_sema);
}

/* Thread handling the state machine */
static void msc_usb_hotplug_thread(void *param)
{
  int ret = 0;

  UNUSED(param);

  for (;;) {
    if (rtos_sema_take(msc_usb_status_changed_sema, RTOS_SEMA_MAX_COUNT) == RTK_SUCCESS) {
      if (msc_usb_attach_status == USBD_ATTACH_STATUS_DETACHED) {
        RTK_LOGS(TAG, RTK_LOG_INFO, "DETACHED\n");
        /* Clean up resources */
        usbd_msc_deinit();
        ret = usbd_deinit();
        if (ret != 0) {
          break;
        }
        usbd_msc_disk_deinit();
        RTK_LOGS(TAG, RTK_LOG_INFO, "Free heap: 0x%x\n", rtos_mem_get_free_heap_size());

        /* Re-initialize for next connection */
        usbd_msc_disk_init();
        ret = usbd_init(&msc_cfg);
        if (ret != 0) {
          break;
        }
        ret = usbd_msc_init(&msc_cb);
        if (ret != 0) {
          usbd_deinit();
          break;
        }
      } else if (msc_usb_attach_status == USBD_ATTACH_STATUS_ATTACHED) {
        RTK_LOGS(TAG, RTK_LOG_INFO, "ATTACHED\n");
      } else {
        RTK_LOGS(TAG, RTK_LOG_INFO, "INIT\n");
      }
    }
  }
  RTK_LOGS(TAG, RTK_LOG_ERROR, "Hotplug thread fail\n");
  rtos_task_delete(NULL);
}

Driver Deinitialization

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

/* De-initializes the underlying storage disk. */
usbd_msc_disk_deinit();
/* Deinitialize MSC device class driver. */
usbd_msc_deinit();
/* Deinitialize USB device core driver. */
usbd_deinit();

Operation method

This section introduces a complete USB Mass Storage Class (MSC) application example, demonstrating how to configure the Ameba development board as a USB storage device using the MSC protocol stack.

When the development board is connected to a USB host (e.g., a PC), the system recognizes it as a removable disk. The host can directly read from and write to the storage media (e.g., SD card) on the board via the USB interface, supporting USB hot-plugging.

The example code path is: {SDK}/example/usb/usbd_msc. It provides a complete design reference for developers designing custom USB storage products.

Note

Use the SD card hot-swap function with caution. Hot-swapping during data transmission carries the risk of file system corruption and data loss.

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 usbd_msc -p
    
  • Confirmation of Menuconfig configuration

    If compilation fails, please execute ameba.py menuconfig and confirm that USBD MSC and storage medium have been selected.

    - Choose `CONFIG USB --->`:
    
      [*] Enable USB
          USB Mode (Device)  --->
      [*] MSC
          Select storage media (RAM)  --->
    

Verification

  • Device Startup

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

    [MSC-I] USBD MSC demo start
    
  • Connect to Host

    Connect the development board to a PC (or other host devices supporting USB MSC) using a USB cable.

  • System Recognition

    A new removable disk drive should automatically appear in the PC’s file manager. Users can double-click to open the drive and perform read/write operations on files to verify that data transmission is working correctly.

    Note

    When using RAM as the storage medium, it must be formatted before it can be used normally.