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


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

    概要

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

    Qiita-STM32_USBMS04.png

    環境

    • 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!
    ");
            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!
    ");
        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****/
  • 相关阅读:
    激活win10系统的方法(亲测)
    java使用jxl,自动导出数据excle,quartz自动发送邮件
    java对接网银支付案例
    将数字转换成Excel表头格式的字母序号
    mysql date_add日期函数的使用
    itext A4纸张横向创建PDF
    Spring 定时器 定时访问数据库并发送邮件
    mvc路由报错
    eval()和$.parseJSON()注意事项
    跨域学习笔记
  • 原文地址:https://www.cnblogs.com/libra13179/p/7156363.html
Copyright © 2020-2023  润新知