zoukankan      html  css  js  c++  java
  • [转]使用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****/
  • 相关阅读:
    LOJ 6089 小Y的背包计数问题 —— 前缀和优化DP
    洛谷 P1969 积木大赛 —— 水题
    洛谷 P1965 转圈游戏 —— 快速幂
    洛谷 P1970 花匠 —— DP
    洛谷 P1966 火柴排队 —— 思路
    51Nod 1450 闯关游戏 —— 期望DP
    洛谷 P2312 & bzoj 3751 解方程 —— 取模
    洛谷 P1351 联合权值 —— 树形DP
    NOIP2007 树网的核
    平面最近点对(加强版)
  • 原文地址:https://www.cnblogs.com/libra13179/p/7156363.html
Copyright © 2011-2022 走看看