概要
- 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`にセクタ数定義する。<br>今回、`#define STORAGE_BLK_NBR 0x81000`としたので、<br>=> 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`)へ飛ばして、うまくデータを詰める
## 実際のコード
- もともとのコードの変更箇所
```c: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とか。<br>(てきとうなUSBフラッシュメモリで、パーティション切って、フォーマットして、ダンプして、必要なとこを入力)
```c:
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 *)§MBR, 512); break; case SECTOR_PBR: memcpy(buf, (const void *)§BPB, 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なので。<br>で、256MBくらいのパーティションで、FAT16フォーマットすると、4KB/clusterになる。<br>(ファイルシステムのクラスタサイズと、フラッシュメモリの物理セクタサイズがちがうと、管理が大変だよね...`;_;`)
- EEPROMにファイル情報(ROOTDIRに入るような情報=>FATチェーン生成)、FLASHにデータのみ、という感じで使用しようかと。
---
### STM32L1xx firmware V1.8.0にて
(2018-01-01追記)
```c:memo-usbd_storage_if.cのうまいとこにこぴぺする
#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
/*
mkfs.vfat -v /dev/loop0p1 -s 1 -S 512 -r 512 -f 2 -n COURTMATICS
mkfs.fat 4.1 (2017-01-24)
/dev/loop0p1 has 64 heads and 32 sectors per track,
hidden sectors 0x0000;
logical sector size is 512,
using 0xf8 media descriptor, with 65535 sectors;
drive number 0x80;
filesystem has 2 16-bit FATs and 1 sector per cluster.
FAT size is 254 sectors, and provides 64994 clusters.
There is 1 reserved sector.
Root directory contains 512 slots and uses 32 sectors.
Volume ID is 935c69b7, volume label COURTMATICS.
*/
#define SECTOR_MBR (0x0000)
#define SECTOR_PBR (0x0001)
#define SECTOR_FAT1 (0x0002)
#define SECTOR_FAT2 (0x0100)
#define SECTOR_ROOT (0x01FE)
#define SECTOR_DATA (0x021E)
const unsigned char sectMBR[] = {
0xFA,0xB8,0x00,0x10,0x8E,0xD0,0xBC,0x00,0xB0,0xB8,0x00,0x00,0x8E,0xD8,0x8E,0xC0,
0xFB,0xBE,0x00,0x7C,0xBF,0x00,0x06,0xB9,0x00,0x02,0xF3,0xA4,0xEA,0x21,0x06,0x00,
0x00,0xBE,0xBE,0x07,0x38,0x04,0x75,0x0B,0x83,0xC6,0x10,0x81,0xFE,0xFE,0x07,0x75,
0xF3,0xEB,0x16,0xB4,0x02,0xB0,0x01,0xBB,0x00,0x7C,0xB2,0x80,0x8A,0x74,0x01,0x8B,
0x4C,0x02,0xCD,0x13,0xEA,0x00,0x7C,0x00,0x00,0xEB,0xFE,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB8,0x1A,0x6B,0x10,0x00,0x00,0x00,0x00,
0x02,0x00,0x0C,0x14,0x10,0x04,0x01,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA
};
const unsigned char sectBPB[] = {
0xEB,0x3C,0x90,0x6D,0x6B,0x66,0x73,0x2E,0x66,0x61,0x74,0x00,0x02,0x01,0x01,0x00,
0x02,0x00,0x02,0xFF,0xFF,0xF8,0xFE,0x00,0x20,0x00,0x40,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xB7,0x69,0x5C,0x93,0x43,0x4F,0x55,0x52,0x54,
0x4D,0x41,0x54,0x49,0x43,0x53,0x46,0x41,0x54,0x31,0x36,0x20,0x20,0x20,0x0E,0x1F,
0xBE,0x5B,0x7C,0xAC,0x22,0xC0,0x74,0x0B,0x56,0xB4,0x0E,0xBB,0x07,0x00,0xCD,0x10,
0x5E,0xEB,0xF0,0x32,0xE4,0xCD,0x16,0xCD,0x19,0xEB,0xFE,0x54,0x68,0x69,0x73,0x20,
0x69,0x73,0x20,0x6E,0x6F,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C,
0x65,0x20,0x64,0x69,0x73,0x6B,0x2E,0x20,0x20,0x50,0x6C,0x65,0x61,0x73,0x65,0x20,
0x69,0x6E,0x73,0x65,0x72,0x74,0x20,0x61,0x20,0x62,0x6F,0x6F,0x74,0x61,0x62,0x6C,
0x65,0x20,0x66,0x6C,0x6F,0x70,0x70,0x79,0x20,0x61,0x6E,0x64,0x0D,0x0A,0x70,0x72,
0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x74,
0x72,0x79,0x20,0x61,0x67,0x61,0x69,0x6E,0x20,0x2E,0x2E,0x2E,0x20,0x0D,0x0A,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA
};
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 *)§MBR, 512);
break;
case SECTOR_PBR:
memcpy(buf, (const void *)§BPB, 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;
}
chkdsk
C:\Users\user>chkdsk E:
The type of the file system is FAT.
Volume Serial Number is 935C-69B7
Windows is verifying files and folders...
File and folder verification is complete.
Windows has scanned the file system and found no problems.
No further action is required.
33,276,928 bytes total disk space.
512 bytes in 1 files.
33,276,416 bytes available on disk.
512 bytes in each allocation unit.
64,994 total allocation units on disk.
64,993 allocation units available on disk.
C:\Users\User>