[转]使用STM32CubeMX:USB大容量存储设备

原文地址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 - 5),
    0x00,
    0x00,
    0x00,
    ‘S‘, ‘T‘, ‘M‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, /* Manufacturer : 8 bytes */
    ‘P‘, ‘r‘, ‘o‘, ‘d‘, ‘u‘, ‘c‘, ‘t‘, ‘ ‘, /* Product      : 16 Bytes */
    ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘,
    ‘0‘, ‘.‘, ‘0‘ ,‘1‘,                     /* 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[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

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;
}
/* 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 - 1);
    /* USER CODE END 8 */
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/**
  * @}
  */

/**
  * @}
  */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
时间: 2024-08-28 23:36:55

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

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

伴随网盘时代的没落,最近刚入手了一个移动硬盘.现在的移动硬盘都是USB3.0,传输速度比USB2.0要快很多.但是链接笔记本电脑后发现传输速度在20MB/s左右,跟USB2.0速度差不多,并不能达到传说中70-80MB/s.而且刚插入电脑的时候会弹出提示“控制器没有足够的带宽可利用为USB大容量存储设备”. 其实这样可以看出,硬件是支持USB3.0的,那么问题肯定是在软件方面,所以自然而然就想到了驱动的问题,网上百度的USB3.0万能驱动貌似没有效果,后来使用了笔记本官网的USB3.0驱动就ok

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

昨天开始使用usb硬盘,发现一块无法识别,一块识别好了以后不能打开. 可能是之前一次系统更新有bug,但是一直也没有用移动硬盘,所以没有发现. 开始尝试各种方案,已经尝试过并且无效的有以下几个: 1,卸载usb驱动,重启后系统自动安装,没有用: 2,驱动精灵,没有用: 3,驱动人生,没有用: 4,驱动禁用启用,没有用: 最后走头无路,就开始系统更新一下(之前关闭了系统自动更新),然后就好了--

Android USB大容量存储时SD卡状态监听(转)

对SD卡状态监听,到现在为止我知道的有两种方式: 1.注册StorageEventListener来监听sd卡状态 StorageEventListener中有onStorageStateChanged()方法,当sd卡状态改变时,此方法会调用,对各状态的判断一般会用到Environment类,此类中包含的有关sd卡状态的常量有: MEDIA_BAD_REMOVAL:表明SDCard 被卸载前己被移除 MEDIA_CHECKING:表明对象正在磁盘检查 MEDIA_MOUNTED:表明sd对象是

树莓派-USB存储设备自动挂载

简单介绍实现命令行下USB存储设备自动挂载的方法,Linux gnome/kde窗口环境下有移动存储的管理程序,可以实现自动挂载移动存储设备,但是在命令行下 通常需要用mount命令手动挂载USB存储设备. 通过给linux下的设备管理服务udev添加规则配置文件,可以实现命令行下USB存储设备自动挂载. 输入命令: sudo vim /etc/udev/rules.d/10-usbstorage.rules 写入如下脚本到编辑窗口 KERNEL!="sd*", GOTO="

stm32 USB hid设备与PC进行双向数据传输时PC不识别USB设备

stm32 USB hid设备与PC进行双向数据传输时PC不识别USB设备,或者开始时识别,拔出后再插入就没有反应了,就连鼠标U盘也没有反应. 我的问题是,我安装了VMware虚拟机,并进行USB设备的分配,使得虚拟机系统也识别USB设备. 所以,解决问题的办法如下: 在<属性>中选择禁用. 然后把下面的VMware Workstation Server 也禁用了.重启电脑就OK了.

USB组合设备 Interface Association Descriptor (IAD)

Communication Device Class,简称CDCUSB Compound Device,USB复合设备USB Composite Device,USB组合设备 摘要USB复合设备 Compound Device内嵌Hub和多个Function,每个Function都相当于一个独立的USB外设,有自己的PID/VID.USB组合设备Composite Device内只有一个Function,只有一套PID/VID,通过将不同的interface定义为不同的类来实现多个功能的组合.

分析USB平台设备模型框架(1)

start_kernel rest_init(); kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); do_basic_setup(); driver_init(); void __init driver_init(void) void __init driver_init(void) { /* These are the core pieces */ devices_init(); 表示在/sys/devices /sys/

Windows与自定义USB HID设备通信说明.

1 .   所使用的典型 Windows API CreateFile ReadFile WriteFile 以下函数是 DDK 的内容: HidD_SetFeature HidD_GetFeature HidD_SetOutputReport HidD_GetInputReport 其中, CreateFile 用于打开设备: ReadFile . HidD_GetFeature . HidD_GetInputReport 用于设备到主机方向的数据通信: WriteFile . HidD_Se

Raspberry Pi 自动挂载USB存储设备

简单介绍实现命令行下USB存储设备自动挂载的方法,Linux gnome/kde窗口环境下有移动存储的管理程序,可以实现自动挂载移动存储设备,但是在命令行下 通常需要用mount命令手动挂载USB存储设备. 通过给linux下的设备管理服务udev添加规则配置文件,可以实现命令行下USB存储设备自动挂载 创建10-usbstorage.rules sudo vim /etc/udev/rules.d/10-usbstorage.rules 复制粘贴以下代码 KERNEL!="sd*",