USB Component  Version 5.1
MDK-Professional Middleware for USB Device and Host
 All Data Structures Functions Variables Enumerations Enumerator Groups Pages
MSC: Mass Storage Class Functions

Implement application specific behaviour of a Mass Storage Class (MSC) Device. More...

Functions

void USBD_MSCn_Initialize (void)
 Called during USBD_Initialize to initialize the USB MSC class Device.
 
void USBD_MSCn_Uninitialize (void)
 Called during USBD_Uninitialize to un-initialize the USB MSC class Device.
 
bool USBD_MSCn_Read (uint32_t lba, uint16_t cnt, uint8_t *buf)
 Read data from media.
 
bool USBD_MSCn_Write (uint32_t lba, uint16_t cnt, const uint8_t *buf)
 Write data to media.
 

Description

Implement application specific behaviour of a Mass Storage Class (MSC) Device.

The MSC class in the USB Component is used for data storage.

Refer to:

The USB Component allows multiple instances of the MSC class. Each MSC class instance has a separate files and interface functions:

This documentation uses n as a placeholder for the instance number 0 - 3. Most applications only require one instance of a MSC class. For the first MSC class instance the instance number is 0:

To create an USB Device with a MSC class:

Configuration File USBD_Config_MSC_n.h

The configuration file USBD_Config_MSC_n.h defines:

These settings are used to create the Interface Descriptor and Endpoint Descriptor of the related USB Device Class. It is important that the settings match the application specific behaviour in the related C source file USBD_User_MSC_n.c.

Software Structure

The handling for the MSC class endpoint events is implemented in USBD_MSC_Thread which is started by USBD_Initialize. Each instance of a MSC class runs an instance of USBD_MSC_Thread which calls the data functions USBD_MSCn_Read and USBD_MSCn_Write.

msc_inline_mscgraph_3

Code Example

The following source code is part of the user code template file. The application specific behaviour may be implemented using this code template.

#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "rl_usbd.h"
// If the USE_FILE_SYSTEM is defined then File System is used and media can
// be accessed from application code or can be accessed by USB Mass Storage
// requests, default media in that case is SD Card or NAND Flash.
// If the USE_FILE_SYSTEM is not defined (commented out) then File System is
// not used and media can only be accessed by USB Mass Storage requests,
// default media in that case is RAM memory containing dummy disk image.
#define USE_FILE_SYSTEM // Use File System for Memory Storage
static usbd_msc_data_t *msc_data_ptr; // Pointer to the MSC run-time settings
// in RAM
extern const usbd_msc_t *usbd_msc_ptr[];// Pointer to the MSC configuration in
// code memory
#ifdef USE_FILE_SYSTEM
#include "rl_fs.h"
static int32_t DrvId; // FAT drive id
static fsMediaInfo Media; // Media Information
#else
static uint8_t memory [8192]; // Memory in RAM for dummy disk image
static uint8_t block_buf [512]; // Buffer for block read/write to media
extern
const uint8_t memory_disk_image[4096]; // Dummy Memory Disk Image
#endif
// Called during USBD_Initialize to initialize the USB Device class.
void USBD_MSCn_Initialize (void) {
#ifdef USE_FILE_SYSTEM
fsIOC_Cache cache_info;
// Get pointer to the MSC run-time
// settings in RAM, so it can be altered
msc_data_ptr = usbd_msc_ptr[n]->data_ptr;
DrvId = fs_ioc_get_id (NULL); // Get ID of File System drive
if (DrvId < 0) return; // If ID is invalid initialization
// failed
if (fs_ioc_lock (DrvId) == 0) { // Lock the media for usage by USB
fs_ioc_read_info(DrvId, &Media); // Read media info of actual media
fs_ioc_get_cache(DrvId, &cache_info); // Get cache settings of File System
msc_data_ptr->block_size = 512; // Block size of Mass Storage
// Cache buffer from File System is
// used for media read/write
msc_data_ptr->block_buf = cache_info.buffer;
// Number of blocks that can fit to cache
msc_data_ptr->block_group = cache_info.size / 512;
// Total number of blocks on media
msc_data_ptr->block_count = Media.block_cnt * (Media.read_blen / 512);
// Total size of media
msc_data_ptr->memory_size = msc_data_ptr->block_count * Media.read_blen;
}
#else
// Get pointer to the MSC run-time
// settings in RAM, so it can be altered
msc_data_ptr = usbd_msc_ptr[n]->data_ptr;
msc_data_ptr->memory_size = 8192; // Total size of dummy image
msc_data_ptr->block_size = 512; // Block size of Mass Storage
msc_data_ptr->block_group = 1; // Number of blocks buffered
// Total number of blocks that dummy
// image contains
msc_data_ptr->block_count = msc_data_ptr->memory_size / msc_data_ptr->block_size;
// Cache buffer from File System is
// used for data buffer
msc_data_ptr->block_buf = block_buf;// Buffer used for media read/write
// Copy the dummy image from code to RAM
memcpy(memory, memory_disk_image, sizeof(memory_disk_image));
#endif
msc_data_ptr->media_ready = true; // Media is ready now
}
// Called during USBD_Uninitialize to de-initialize the USB Device class.
// ToDo: add code for de-initialization
}
// Read data from media.
// \param[in] lba logical address of first block to read.
// \param[in] cnt number of contiguous blocks to read from media.
// \param[out] buf data buffer for data read from media.
// \return true read succeeded.
// \return false read failed.
bool USBD_MSCn_Read (uint32_t lba, uint16_t cnt, uint8_t *buf) {
if (msc_data_ptr->media_ready) {
#ifdef USE_FILE_SYSTEM
// Read data directly from media
if (fs_ioc_read_sector(DrvId, lba, buf, cnt) == fsOK)
return true;
#else
// Read data from dummy image in RAM
memcpy(buf, &memory[lba * msc_data_ptr->block_size], cnt * msc_data_ptr->block_size);
return true;
#endif
}
return false;
}
// \brief Write data to media.
// \param[in] lba logical address of first block to write.
// \param[in] cnt number of contiguous blocks to write to media.
// \param[out] buf data buffer containing data to write to media.
// \return true write succeeded.
// \return false write failed.
bool USBD_MSCn_Write (uint32_t lba, uint16_t cnt, const uint8_t *buf) {
if (msc_data_ptr->media_ready) { // Write to media only if media is ready
#ifdef USE_FILE_SYSTEM
// Write data directly to media
if (fs_ioc_write_sector(DrvId, lba, buf, cnt) == fsOK)
return true;
#else
// Write data to image in RAM
memcpy(&memory[lba * msc_data_ptr->block_size], buf, cnt * msc_data_ptr->block_size);
return true;
#endif
}
return false;
}

Function Documentation

void USBD_MSCn_Initialize ( void  )

Called during USBD_Initialize to initialize the USB MSC class Device.

Returns
none.

The function USBD_MSCn_Initialize is called automatically upon initialization of a Mass Storage Class Device and needs no invocation in the user code. Modify this function to the application's needs to allocate resources and initialize additional peripherals.

Code Example

#include "rl_usbd.h"
void USBD_MSC0_Initialize (void) {
#ifdef USE_FILE_SYSTEM
IOC_CACHE cache_info;
msc_data_ptr = usbd_msc_ptr[0]->data_ptr;
DrvId = ioc_get_id (NULL);
if (DrvId < 0) return;
if (ioc_lock (DrvId) == 0) {
ioc_read_info(&Media, DrvId);
ioc_get_cache(&cache_info, DrvId);
msc_data_ptr->block_size = 512;
msc_data_ptr->block_buf = cache_info.Buffer; /* Cache buffer from FileSystem */
msc_data_ptr->block_group = cache_info.Size / 512;
msc_data_ptr->block_count = Media.block_cnt * (Media.read_blen / 512);
msc_data_ptr->memory_size = msc_data_ptr->block_count * Media.read_blen;
}
#else
msc_data_ptr = usbd_msc_ptr[0]->data_ptr;
msc_data_ptr->memory_size = 8192;
msc_data_ptr->block_size = 512;
msc_data_ptr->block_group = 1;
msc_data_ptr->block_count = msc_data_ptr->memory_size / msc_data_ptr->block_size;
msc_data_ptr->block_buf = block_buf;
memcpy(memory, memory_disk_image, sizeof(memory_disk_image));
#endif
msc_data_ptr->media_ready = true;
}
bool USBD_MSCn_Read ( uint32_t  lba,
uint16_t  cnt,
uint8_t *  buf 
)

Read data from media.

Parameters
[in]lbalogical address of first block to read.
[in]cntnumber of contiguous blocks to read from media.
[out]bufdata buffer for data read from media.
Returns
true read succeeded.
false read failed.

The function USBD_MSCn_Read reads the data that should be returned to the USB Host that requested it. Modify this function to the application's needs.

The argument lba specifies the logical address of the first block that is to be read.

The argument cnt specifies the number of contiguous blocks to be read from the media.

The argument buf is pointing to the buffer where the read data should be stored.

Code Example

#include rl_usbd.h
bool USBD_MSC0_Read (uint32_t lba, uint16_t cnt, uint8_t *buf) {
if (msc_data_ptr->media_ready) {
#ifdef USE_FILE_SYSTEM
ioc_read_sect(lba, buf, cnt, DrvId);
#else
memcpy(buf, &memory[lba * msc_data_ptr->block_size], cnt * msc_data_ptr->block_size);
#endif
}
}
void USBD_MSCn_Uninitialize ( void  )

Called during USBD_Uninitialize to un-initialize the USB MSC class Device.

Returns
none.

The function USBD_MSCn_Uninitialize is called automatically upon un-initialization of a Mass Storage Class Device and needs no invocation in the user code. If USBD_MSCn_Initialize has been adapted to the application, USBD_MSCn_Uninitialize should release resources and should de-initialize peripherals.

Code Example

#include "rl_usb.h"
int main (void) {
..
USBD_Initialize (1); // USB Device 1 Initialization
...
USBD_Uninitialize (1); // USB Device 1 Un-Initialization
..
}
bool USBD_MSCn_Write ( uint32_t  lba,
uint16_t  cnt,
const uint8_t *  buf 
)

Write data to media.

Parameters
[in]lbalogical address of first block to write.
[in]cntnumber of contiguous blocks to write to media.
[out]bufdata buffer containing data to write to media.
Returns
true write succeeded.
false write failed.

The function USBD_MSCn_Write writes data received from the USB Host. Modify this function to the application's needs.

The argument lba specifies the logical address of the first block that is to be written.

The argument cnt specifies the number of contiguous blocks to be written to the media.

The argument buf is pointing to the buffer containing the data to be written.

Code Example

#include rl_usbd.h
bool USBD_MSC0_Write (uint32_t lba, uint16_t cnt, const uint8_t *buf) {
if (msc_data_ptr->media_ready) {
#ifdef USE_FILE_SYSTEM
ioc_write_sect(lba, buf, cnt, DrvId);
#else
memcpy(&memory[lba * msc_data_ptr->block_size], buf, cnt * msc_data_ptr->block_size);
#endif
}
}