原文地址http://qiita.com/mt08/items/fcc925fa47726bfc6c74

概要

  • STM32CubeMXを使って、USB MassStorageを使ってみる。
  • USBを使うときは、外付けのOscillator/Xtalが必要。(48MHzを作るのに、内部のやつは精度がでない?)
  • usbd_storage_if.cだけ変更. 今回は、ReadOnly.

環境

  • STM32L1系
  • ビルド環境
    • Windows7 64bit
    • MDK-ARM Lite v5.20
    • STM32CubeMX v4.18.0
      • ボードが動くくらいの設定(クロックとか、GPIOとか)
      • FreeRTOS : [v] Enabled (Lチカにつかった程度)
      • USB_DEVICE : Class for FS IP Mass Storage Class
      • USB : [v] Device (FS)
        => コード生成
    • Firmware Package for Family STM32L1 v1.6.0

大体の説明

  • コールバック
    ホストに接続すると、コールバックが呼ばれるので、うまく応答すればよい。

    usbd_storage_if.c
    ...
    USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
    {
    STORAGE_Init_FS,
    STORAGE_GetCapacity_FS,
    STORAGE_IsReady_FS,
    STORAGE_IsWriteProtected_FS,
    STORAGE_Read_FS,
    STORAGE_Write_FS,
    STORAGE_GetMaxLun_FS,
    (int8_t *)STORAGE_Inquirydata_FS,
    };
    ...
  • ディスクの容量は、STORAGE_BLK_NBRにセクタ数定義する。
    今回、#define STORAGE_BLK_NBR 0x81000としたので、
    => 0x81000 * 512bytes/sector = 258MBくらいのディスク

  • コールバックは、だいたい、STORAGE_Read_FSで、セクタのデータを要求してくるので、そいつをかえせばいい。

    • ↓の実装では、_ReadSector()に飛ばしている。
    • _ReadSector()で、要求されたセクタ番号で、MBR, PBR, FAT, ROOT_DIR, DATAの領域で、処理を分けている。
      • MBR,PBRは、固定値を用意して、memcpy
      • FAT, ROOTDIR, DATAは、Offsetを引いて、処理関数(handleFatClusterChain,handleRoot,handleData)へ飛ばして、うまくデータを詰める

実際のコード

  • もともとのコードの変更箇所

    usbd_storage_if.c
    ...
    #define STORAGE_LUN_NBR 1
    #define STORAGE_BLK_NBR 0x81000 //##mt08
    #define STORAGE_BLK_SIZ ... int8_t STORAGE_IsWriteProtected_FS (uint8_t lun)
    {
    /* USER CODE BEGIN 5 */
    return (USBD_FAIL); //##mt08: Read Only
    /* USER CODE END 5 */
    } ...
    int8_t STORAGE_Read_FS (uint8_t lun,
    uint8_t *buf,
    uint32_t blk_addr,
    uint16_t blk_len)
    {
    /* USER CODE BEGIN 6 */
    _ReadSector(buf, blk_addr, blk_len); //##mt08
    return (USBD_OK);
    /* USER CODE END 6 */
    }

追加コード

  • 型宣言

    #include <stdint.h>
    typedef uint8_t Byte;
    typedef struct MasterBootRecord {
    Byte checkRoutionOnx86[446];
    struct {
    Byte bootDescriptor; /* 0x80: bootable device, 0x00: non-bootable */
    Byte firstPartitionSector[3]; /* 1st sector number */
    Byte fileSystemDescriptor; /* 1:FAT12, 4:FAT16(less than 32MB), 5:Extended-DOS Partition,
    6:FAT16(more 32MB), 0xb:FAT32(more 2GB),
    0xc:FAT32 Int32h, 0xe:FAT16 Int32h,
    0xf:5:Extended-DOS Partition Int32h */
    Byte lastPartitionSector[3];
    Byte firstSectorNumbers[4]; /* first sector number (link to BPB sector) */
    Byte numberOfSectors[4];
    } partitionTable[4];
    Byte sig[2]; /* 0x55, 0xaa */
    } MBRecord; typedef struct FAT16BPB_t {
    /* FAT16 or FAT12 BPB */
    Byte jmpOpeCode[3]; /* 0xeb ?? 0x90 */
    Byte OEMName[8];
    /* FAT16 */
    Byte bytesPerSector[2]; /* bytes/sector */
    Byte sectorsPerCluster; /* sectors/cluster */
    Byte reservedSectors[2]; /* reserved sector, beginning with sector 0 */
    Byte numberOfFATs; /* file allocation table */
    Byte rootEntries[2]; /* root entry (512) */
    Byte totalSectors[2]; /* partion total secter */
    Byte mediaDescriptor; /* 0xf8: Hard Disk */
    Byte sectorsPerFAT[2]; /* sector/FAT (FAT32 always zero: see bigSectorsPerFAT) */
    Byte sectorsPerTrack[2]; /* sector/track (not use) */
    Byte heads[2]; /* heads number (not use) */
    Byte hiddenSectors[4]; /* hidden sector number */
    Byte bigTotalSectors[4]; /* total sector number */
    /* info */
    Byte driveNumber;
    Byte unused;
    Byte extBootSignature;
    Byte serialNumber[4];
    Byte volumeLabel[11];
    Byte fileSystemType[8]; /* "FAT16 " */
    Byte loadProgramCode[448];
    Byte sig[2]; /* 0x55, 0xaa */
    } BPBlock; // BIOS Parameter Block typedef struct DirEntry_t {
    Byte name[8]; /* file name */
    Byte extension[3]; /* file name extension */
    Byte attribute; /* file attribute
    bit 4 directory flag
    bit 3 volume flag
    bit 2 hidden flag
    bit 1 system flag
    bit 0 read only flag */
    Byte reserved; /* use NT or same OS */
    Byte createTimeMs; /* VFAT 10millsec (0   199) */
    Byte createTime[2]; /* VFAT */
    Byte createDate[2]; /* VFAT */
    Byte accessDate[2]; /* VFAT */
    Byte clusterHighWord[2]; /* FAT32 MSB 16 bits */
    Byte updateTime[2];
    Byte updateDate[2];
    Byte cluster[2]; /* start cluster number */
    Byte fileSize[4]; /* file size in bytes (directory is always zero) */
    } DirEntry; #pragma anon_unions
    typedef struct _DirEntTime {
    union {
    uint16_t W;
    struct {
    uint16_t second : 5;
    uint16_t minutes : 6;
    uint16_t hour : 5;
    } B;
    };
    } DirEntTime; typedef struct _DirEntDate {
    union {
    uint16_t W;
    struct {
    uint16_t day : 5;
    uint16_t month : 4;
    uint16_t year : 7;
    } B;
    };
    } DirEntDate;
    #pragma no_anon_unions
  • 固定値: MBRとか、PBSとか。
    (てきとうなUSBフラッシュメモリで、パーティション切って、フォーマットして、ダンプして、必要なとこを入力)

    const MBRecord sectMBR = {
    .checkRoutionOnx86 = { 0x00 },
    .partitionTable = {
    {
    .bootDescriptor = 0x00,
    .firstPartitionSector = { 0x02, 0x21, 0x00 },
    .fileSystemDescriptor = 0x06, //FAT16
    .lastPartitionSector = { 0xC2, 0x22, 0x20 },
    .firstSectorNumbers = { 0x00, 0x08, 0x00, 0x00 },
    .numberOfSectors = { 0x00, 0x00, 0x08, 0x00 },
    },//[0]
    { 0 },//[1]
    { 0 },//[2]
    { 0 },//[3]
    },
    .sig = { 0x55, 0xAA },
    };
    const BPBlock sectBPB = {
    .jmpOpeCode = { 0xEB, 0x00, 0x90 },
    .OEMName = { ' ',' ',' ',' ',' ',' ',' ',' ' },
    .bytesPerSector = { 0x00, 0x02 },
    .sectorsPerCluster = 0x08, // 4KB/sectors
    .reservedSectors = { 0x08, 0x00 },
    .numberOfFATs = 0x02,
    .rootEntries = { 0x00, 0x02 },
    .totalSectors = { 0x00, 0x00 },
    .mediaDescriptor = 0xF8, // HDD
    .sectorsPerFAT = { 0x00, 0x01 },
    .sectorsPerTrack = { 0x3F,0x00 },
    .heads = { 0xFF,0x00 },
    .hiddenSectors = { 0x00, 0x08, 0x00, 0x00 },
    .bigTotalSectors = { 0x00,0x00,0x08, 0x00 },
    .driveNumber = 0x80,
    .unused = 0,
    .extBootSignature = 0x29,
    .serialNumber = { 0x78,0x56,0x34,0x12 },
    .volumeLabel = { 'N','O',' ','N','A','M','E',' ',' ',' ',' ' },
    .fileSystemType = { 'F','A','T','1','6',' ',' ',' ' },
    .loadProgramCode = { 0 },
    .sig = { 0x55, 0xAA },
    }; #define SECTOR_MBR (0x0000)
    #define SECTOR_PBR (0x0800)
    #define SECTOR_FAT1 (0x0808)
    #define SECTOR_FAT2 (0x0908)
    #define SECTOR_ROOT (0x0A08)
    #define SECTOR_DATA (0x0A28)
  • セクタ読み出しで、それっぽいデータをわたすとこ。

    void _handleFatClusterChain(uint32_t sect_offset, uint8_t *buf)
{
uint16_t *bufW = (uint16_t *)&buf[0];
if (sect_offset == 0)
{
bufW[0] = 0xfff8;
bufW[1] = 0xffff;
bufW[2] = 0xffff; //最初のファイル. 1クラスタでおわり.
}
} void _handleRoot(uint32_t sect_offset, uint8_t *buf)
{
// 1 sector(512bytes) has 16 entries
DirEntry *pDir = (DirEntry *)buf;
if (sect_offset == 0)
{
memset(pDir, 0x00, sizeof(DirEntry));
sprintf((char *)pDir->name, "TEXT_123");
pDir->extension[0] = 'T';
pDir->extension[1] = 'X';
pDir->extension[2] = 'T';
pDir->attribute = 0x00;
{
DirEntTime *pT = (DirEntTime *)&pDir->updateTime[0];
DirEntDate *pD = (DirEntDate *)&pDir->updateDate[0];
pT->B.hour = 12;
pT->B.minutes = 34;
pT->B.second = 56 / 2;
pD->B.year = 2017 - 1980;
pD->B.month = 1;
pD->B.day = 12;
} *(uint16_t*)&pDir->cluster = 0x0002;
*(uint32_t*)&pDir->fileSize = 123;
}
} void _handleData(uint32_t sect_offset, uint8_t *buf)
{
memset(buf, 'A', 512);
sprintf((char *)buf, "Hello World!\r\n");
buf[14]='>';
} uint32_t _ReadSector(uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
switch (blk_addr)
{
case SECTOR_MBR:
memcpy(buf, (const void *)&sectMBR, 512);
break;
case SECTOR_PBR:
memcpy(buf, (const void *)&sectBPB, 512);
break;
default:
memset(buf, 0x00, 512);
//FAT cluster chain
if ((SECTOR_FAT1 <= blk_addr) && (blk_addr < SECTOR_ROOT))
{
if (blk_addr >= SECTOR_FAT2) { blk_addr -= (SECTOR_FAT2 - SECTOR_FAT1); }
_handleFatClusterChain(blk_addr - SECTOR_FAT1, buf); }
else if ((SECTOR_ROOT <= blk_addr) && (blk_addr < SECTOR_DATA))
{
_handleRoot(blk_addr - SECTOR_ROOT, buf); }
else if (SECTOR_DATA <= blk_addr)
{
_handleData(blk_addr - SECTOR_DATA, buf); }
break;
}
return 0;
}

その他

    • 4KB/clusterにしてるのは、STM32の内蔵FLASHが4KB/sectorなので。
      で、256MBくらいのパーティションで、FAT16フォーマットすると、4KB/clusterになる。
      (ファイルシステムのクラスタサイズと、フラッシュメモリの物理セクタサイズがちがうと、管理が大変だよね...;_;)
    • EEPROMにファイル情報(ROOTDIRに入るような情報=>FATチェーン生成)、FLASHにデータのみ、という感じで使用しようかと。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

好了现在我们动手吧。现在只要修改usbd_storage_if.C文件

/**
******************************************************************************
* @file : usbd_storage_if.c
* @brief : Memory management layer
******************************************************************************
* This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/ /* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"
/* USER CODE BEGIN INCLUDE */
/* USER CODE END INCLUDE */ /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/ /** @defgroup USBD_STORAGE
* @brief usbd core module
* @{
*/ /** @defgroup USBD_STORAGE_Private_TypesDefinitions
* @{
*/
/* USER CODE BEGIN PRIVATE_TYPES */
/* USER CODE END PRIVATE_TYPES */
/**
* @}
*/ /** @defgroup USBD_STORAGE_Private_Defines
* @{
*/
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x81000
#define STORAGE_BLK_SIZ 0x200 /* USER CODE BEGIN PRIVATE_DEFINES */
/* USER CODE END PRIVATE_DEFINES */ /**
* @}
*/ /** @defgroup USBD_STORAGE_Private_Macros
* @{
*/
/* USER CODE BEGIN PRIVATE_MACRO */
/* USER CODE END PRIVATE_MACRO */ /**
* @}
*/ /** @defgroup USBD_STORAGE_IF_Private_Variables
* @{
*/
/* USER CODE BEGIN INQUIRY_DATA_FS */
/* USB Mass storage Standard Inquiry Data */
const int8_t STORAGE_Inquirydata_FS[] = /* 36 */
{ /* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - ),
0x00,
0x00,
0x00,
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'', '.', '' ,'', /* Version : 4 Bytes */
};
/* USER CODE END INQUIRY_DATA_FS */ /* USER CODE BEGIN PRIVATE_VARIABLES */
/* USER CODE END PRIVATE_VARIABLES */ /**
* @}
*/ /** @defgroup USBD_STORAGE_IF_Exported_Variables
* @{
*/
extern USBD_HandleTypeDef hUsbDeviceFS;
/* USER CODE BEGIN EXPORTED_VARIABLES */
/* USER CODE END EXPORTED_VARIABLES */ /**
* @}
*/ /** @defgroup USBD_STORAGE_Private_FunctionPrototypes
* @{
*/
static int8_t STORAGE_Init_FS (uint8_t lun);
static int8_t STORAGE_GetCapacity_FS (uint8_t lun,
uint32_t *block_num,
uint16_t *block_size);
static int8_t STORAGE_IsReady_FS (uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS (uint8_t lun);
static int8_t STORAGE_Read_FS (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len);
static int8_t STORAGE_Write_FS (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS (void); /* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
#include <stdint.h>
typedef uint8_t Byte;
typedef struct MasterBootRecord
{
Byte checkRoutionOnx86[];
struct
{
Byte bootDescriptor; /* 0x80: bootable device, 0x00: non-bootable */
Byte firstPartitionSector[]; /* 1st sector number */
Byte fileSystemDescriptor; /* 1:FAT12, 4:FAT16(less than 32MB), 5:Extended-DOS Partition,
6:FAT16(more 32MB), 0xb:FAT32(more 2GB),
0xc:FAT32 Int32h, 0xe:FAT16 Int32h,
0xf:5:Extended-DOS Partition Int32h */
Byte lastPartitionSector[];
Byte firstSectorNumbers[]; /* first sector number (link to BPB sector) */
Byte numberOfSectors[];
} partitionTable[];
Byte sig[]; /* 0x55, 0xaa */
} MBRecord; typedef struct FAT16BPB_t
{
/* FAT16 or FAT12 BPB */
Byte jmpOpeCode[]; /* 0xeb ?? 0x90 */
Byte OEMName[];
/* FAT16 */
Byte bytesPerSector[]; /* bytes/sector */
Byte sectorsPerCluster; /* sectors/cluster */
Byte reservedSectors[]; /* reserved sector, beginning with sector 0 */
Byte numberOfFATs; /* file allocation table */
Byte rootEntries[]; /* root entry (512) */
Byte totalSectors[]; /* partion total secter */
Byte mediaDescriptor; /* 0xf8: Hard Disk */
Byte sectorsPerFAT[]; /* sector/FAT (FAT32 always zero: see bigSectorsPerFAT) */
Byte sectorsPerTrack[]; /* sector/track (not use) */
Byte heads[]; /* heads number (not use) */
Byte hiddenSectors[]; /* hidden sector number */
Byte bigTotalSectors[]; /* total sector number */
/* info */
Byte driveNumber;
Byte unused;
Byte extBootSignature;
Byte serialNumber[];
Byte volumeLabel[];
Byte fileSystemType[]; /* "FAT16 " */
Byte loadProgramCode[];
Byte sig[]; /* 0x55, 0xaa */
} BPBlock; // BIOS Parameter Block typedef struct DirEntry_t
{
Byte name[]; /* file name */
Byte extension[]; /* file name extension */
Byte attribute; /* file attribute
bit 4 directory flag
bit 3 volume flag
bit 2 hidden flag
bit 1 system flag
bit 0 read only flag */
Byte reserved; /* use NT or same OS */
Byte createTimeMs; /* VFAT 10millsec (0 199) */
Byte createTime[]; /* VFAT */
Byte createDate[]; /* VFAT */
Byte accessDate[]; /* VFAT */
Byte clusterHighWord[]; /* FAT32 MSB 16 bits */
Byte updateTime[];
Byte updateDate[];
Byte cluster[]; /* start cluster number */
Byte fileSize[]; /* file size in bytes (directory is always zero) */
} DirEntry; #pragma anon_unions
typedef struct _DirEntTime
{
union
{
uint16_t W;
struct
{
uint16_t second : ;
uint16_t minutes : ;
uint16_t hour : ;
} B;
};
} DirEntTime; typedef struct _DirEntDate
{
union
{
uint16_t W;
struct
{
uint16_t day : ;
uint16_t month : ;
uint16_t year : ;
} B;
};
} DirEntDate;
#pragma no_anon_unions const MBRecord sectMBR =
{
.checkRoutionOnx86 = { 0x00 },
.partitionTable = {
{
.bootDescriptor = 0x00,
.firstPartitionSector = { 0x02, 0x21, 0x00 },
.fileSystemDescriptor = 0x06, //FAT16
.lastPartitionSector = { 0xC2, 0x22, 0x20 },
.firstSectorNumbers = { 0x00, 0x08, 0x00, 0x00 },
.numberOfSectors = { 0x00, 0x00, 0x08, 0x00 },
},//[0]
{ },//[1]
{ },//[2]
{ },//[3]
},
.sig = { 0x55, 0xAA },
};
const BPBlock sectBPB =
{
.jmpOpeCode = { 0xEB, 0x00, 0x90 },
.OEMName = { ' ',' ',' ',' ',' ',' ',' ',' ' },
.bytesPerSector = { 0x00, 0x02 },
.sectorsPerCluster = 0x08, // 4KB/sectors
.reservedSectors = { 0x08, 0x00 },
.numberOfFATs = 0x02,
.rootEntries = { 0x00, 0x02 },
.totalSectors = { 0x00, 0x00 },
.mediaDescriptor = 0xF8, // HDD
.sectorsPerFAT = { 0x00, 0x01 },
.sectorsPerTrack = { 0x3F,0x00 },
.heads = { 0xFF,0x00 },
.hiddenSectors = { 0x00, 0x08, 0x00, 0x00 },
.bigTotalSectors = { 0x00,0x00,0x08, 0x00 },
.driveNumber = 0x80,
.unused = ,
.extBootSignature = 0x29,
.serialNumber = { 0x78,0x56,0x34,0x12 },
.volumeLabel = { 'N','O',' ','N','A','M','E',' ',' ',' ',' ' },
.fileSystemType = { 'F','A','T','','',' ',' ',' ' },
.loadProgramCode = { },
.sig = { 0x55, 0xAA },
}; #define SECTOR_MBR (0x0000)
#define SECTOR_PBR (0x0800)
#define SECTOR_FAT1 (0x0808)
#define SECTOR_FAT2 (0x0908)
#define SECTOR_ROOT (0x0A08)
#define SECTOR_DATA (0x0A28) void _handleFatClusterChain(uint32_t sect_offset, uint8_t *buf)
{
uint16_t *bufW = (uint16_t *)&buf[];
if (sect_offset == )
{
bufW[] = 0xfff8;
bufW[] = 0xffff;
bufW[] = 0xffff; //结束第一个文件。1簇。
}
} void _handleRoot(uint32_t sect_offset, uint8_t *buf)
{
// 1 sector(512bytes) has 16 entries
DirEntry *pDir = (DirEntry *)buf;
if (sect_offset == )
{
memset(pDir, 0x00, sizeof(DirEntry));
sprintf((char *)pDir->name, "TEXT_123");
pDir->extension[] = 'T';
pDir->extension[] = 'X';
pDir->extension[] = 'T';
pDir->attribute = 0x00;
{
DirEntTime *pT = (DirEntTime *)&pDir->updateTime[];
DirEntDate *pD = (DirEntDate *)&pDir->updateDate[];
pT->B.hour = ;
pT->B.minutes = ;
pT->B.second = / ;
pD->B.year = - ;
pD->B.month = ;
pD->B.day = ;
} *(uint16_t*)&pDir->cluster = 0x0002;
*(uint32_t*)&pDir->fileSize = ;
}
} void _handleData(uint32_t sect_offset, uint8_t *buf)
{
memset(buf, 'A', );
sprintf((char *)buf, "Hello World!\r\n");
buf[]='>';
} uint32_t _ReadSector(uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
switch (blk_addr)
{
case SECTOR_MBR:
memcpy(buf, (const void *)&sectMBR, );
break;
case SECTOR_PBR:
memcpy(buf, (const void *)&sectBPB, );
break;
default:
memset(buf, 0x00, );
//FAT cluster chain
if ((SECTOR_FAT1 <= blk_addr) && (blk_addr < SECTOR_ROOT))
{
if (blk_addr >= SECTOR_FAT2)
{
blk_addr -= (SECTOR_FAT2 - SECTOR_FAT1);
}
_handleFatClusterChain(blk_addr - SECTOR_FAT1, buf); }
else if ((SECTOR_ROOT <= blk_addr) && (blk_addr < SECTOR_DATA))
{
_handleRoot(blk_addr - SECTOR_ROOT, buf); }
else if (SECTOR_DATA <= blk_addr)
{
_handleData(blk_addr - SECTOR_DATA, buf); }
break;
}
return ;
}
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */ /**
* @}
*/ USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
{
STORAGE_Init_FS,
STORAGE_GetCapacity_FS,
STORAGE_IsReady_FS,
STORAGE_IsWriteProtected_FS,
STORAGE_Read_FS,
STORAGE_Write_FS,
STORAGE_GetMaxLun_FS,
(int8_t *)STORAGE_Inquirydata_FS,
}; /* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : STORAGE_Init_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_Init_FS (uint8_t lun)
{
/* USER CODE BEGIN 2 */
return (USBD_OK);
/* USER CODE END 2 */
} /*******************************************************************************
* Function Name : STORAGE_GetCapacity_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_GetCapacity_FS (uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
/* USER CODE BEGIN 3 */
*block_num = STORAGE_BLK_NBR;
*block_size = STORAGE_BLK_SIZ;
return (USBD_OK);
/* USER CODE END 3 */
} /*******************************************************************************
* Function Name : STORAGE_IsReady_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_IsReady_FS (uint8_t lun)
{
/* USER CODE BEGIN 4 */
return (USBD_OK);
/* USER CODE END 4 */
} /*******************************************************************************
* Function Name : STORAGE_IsWriteProtected_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_IsWriteProtected_FS (uint8_t lun)
{
/* USER CODE BEGIN 5 */
return (USBD_OK);
/* USER CODE END 5 */
} /*******************************************************************************
* Function Name : STORAGE_Read_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_Read_FS (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
_ReadSector(buf, blk_addr, blk_len);
return (USBD_OK);
/* USER CODE END 6 */
} /*******************************************************************************
* Function Name : STORAGE_Write_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_Write_FS (uint8_t lun,
uint8_t *buf,
uint32_t blk_addr,
uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
return (USBD_OK);
/* USER CODE END 7 */
} /*******************************************************************************
* Function Name : STORAGE_GetMaxLun_FS
* Description :
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int8_t STORAGE_GetMaxLun_FS (void)
{
/* USER CODE BEGIN 8 */
return (STORAGE_LUN_NBR - );
/* USER CODE END 8 */
} /* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ /**
* @}
*/ /**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

[转]使用STM32CubeMX:USB大容量存储设备的更多相关文章

  1. 控制器没有足够的带宽可利用为USB大容量存储设备的解决方法

    伴随网盘时代的没落,最近刚入手了一个移动硬盘.现在的移动硬盘都是USB3.0,传输速度比USB2.0要快很多.但是链接笔记本电脑后发现传输速度在20MB/s左右,跟USB2.0速度差不多,并不能达到传 ...

  2. 弹出USB大容量存储设备时出问题的解决方法

    我的计算机->管理->系统工具->事件查看器->自定义视图->Kernel-Pnp->详情->进程ID 然后在任务管理器里找到该进程(任务管理器->查看 ...

  3. win10突然不能使用usb大容量存储设备(移动硬盘)的解决方法

    昨天开始使用usb硬盘,发现一块无法识别,一块识别好了以后不能打开. 可能是之前一次系统更新有bug,但是一直也没有用移动硬盘,所以没有发现. 开始尝试各种方案,已经尝试过并且无效的有以下几个: 1, ...

  4. [未完] Linux 4.4 USB —— spiflash模拟usb大容量存储设备 调试记录 Gadget Mass Stroage

    linux 4.4 USB Gadget Mass Stroage 硬件平台: licheepi nano衍生 调试记录 驱动信息 │ This driver is a replacement for ...

  5. 【转】弹出USB大容量存储设备时出问题的解决方法

    原文链接 如下图所示,这个问题,相信很多人都有遇到过,而且经常难以解决,试了很多方法都无效.到最后,只能抱着侥幸的心理直接拔出,如果运气好,可能没有事,如果运气不好,你的U盘或者移动硬盘就要从此报废了 ...

  6. 教你开启红米的USB大容量存储选项,全网首发哦

    教你开启红米的USB大容量存储选项,全网首发哦 http://bbs.7to.cn/thread-10732-1-1.html 发表于 2014-4-29 110643 红米note入手也有两天了.各 ...

  7. 如何查找Mac上的USB存储设备使用痕迹

    最近刚好有个案子的证物主机是MBP, OS X版本为El Capitan,案况与营业秘密外泄有关,当中要找有关USB存储设备的使用痕迹. 要提醒大家的是,不同版本的OS X,各种迹证的存放文件名称及路 ...

  8. C# 访问USB(HID)设备

    原文:C# 访问USB(HID)设备 二话不说,直接给代码,如果您真想做这方面的东西,还是稍微研究下,没有现成的好类用,就需要自己了解其原理 //引用空间 using System; using Sy ...

  9. android usb Host模式下与usb Hid 设备的通信

    做android 与USB HID设备的通信有段时间了,总结一下遇到的问题和解决方法: 1,第一次遇到的问题:android 版本低不支持usb hid, 被要求做相关项目的时候,就从mUsbMana ...

随机推荐

  1. ALGO-9_蓝桥杯_算法训练_摆动序列(DP)

    问题描述 如果一个序列满足下面的性质,我们就将它称为摆动序列: . 序列中的所有数都是不大于k的正整数: . 序列中至少有两个数. . 序列中的数两两不相等: . 如果第i – 1个数比第i – 2个 ...

  2. IKAnalyzer 源码走读

    首先摘抄一段关于IK的特性介绍: 采用了特有的“正向迭代最细粒度切分算法”,具有60万字/秒的高速处理能力. 采用了多子处理器分析模式,支持:英文字母(IP地址.Email.URL).数字(日期,常用 ...

  3. PAT 乙级 1017 A除以B (20) C++版

    1017. A除以B (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 本题要求计算A/B,其中A是不超过 ...

  4. 廖雪峰Java1-4数组操作-4多维数组

    二维数组 二维数组就是元素为数组的数组 二维数组每个数组的长度不要求一样.比如 int[][] = { { 1, 2 }, { 3, 4, 5 }, { 6, 7, 8, 9 } } int[][] ...

  5. 在CentOS-6.9里安装openvswitch-2.5.4

    第一步:安装依赖 yum install rpm-build openssl-devel gcc wgetyum install python-devel kernel-devel kernel-de ...

  6. 聊天,发朋友圈可以不打字,但是表情怎么能少呢?那么如何用win10自带的微软拼音输入法打出表情呢?

    Step1:将光标定位到你要输入的地方 Step2:将输入法切换为中文,win10是[Win+空格] Step3:打出想要的表情类型,例如开心,(切记输完后不要选择文字,就保持拼音状态),保持下图的样 ...

  7. lamda匿名函数(与sorted(),filter(),map() 一起用), 递归函数, 二分查找

    一. 匿名函数 为了解决一些简单的需求而设计的一句话函数.  lambda表示的是匿名函数. 不需要用def来声明, 一句话就可以声明出一个函数 语法:    函数名 = lambda 参数: 返回值 ...

  8. 【架构师之路】集群/分布式环境下5种session处理策略

    [架构师之路]集群/分布式环境下5种session处理策略   转自:http://www.cnblogs.com/jhli/p/6557929.html 在搭建完集群环境后,不得不考虑的一个问题就是 ...

  9. 运维人员word优化

  10. [SQL]SQL Prompt5的工具栏按钮介绍

    这是SQL Prompt5的工具栏按钮 Refresh Suggestions 刷新提示(数据库更改表结构后,需要刷新一下) Format SQL 格式化代码(Pro版本才能启用,可定制,所有前边带红 ...