FAT 协议 (驱动器格式)
本文概述了存储硬件协议。 FAT16 或 FAT 协议 最多可以 格式 化 2 GB 的存储器。
FAT 协议
在 FAT 协议 中,数据只是进行了分类,通过读取硬盘的开头就可以知道数据的地址。
使用 FAT 协议格式化的驱动器的起始位置是“跳转指令”。
跳转指令为0xeb3c90。
识别出这三个字节后,你几乎可以确定你已经进入了驱动器。 接下来的 8 个字节指定格式化驱动器的系统。
接下来的两个字节:16位,每个扇区的字节数。
下一个字节:8位,每簇的扇区数(sectors per cluster)。
接下来的两个字节:16 位,预取(保留)段
下一个字节:8位,文件分配表(fats)的数量
接下来的两个字节:16 位,内核(根)条目总数
下一个字节:16位,逻辑部分之和
下一个字节:8位,存储设备信息
接下来的两个字节:16 位,每个 fat 的逻辑段数
从地址0xb到0x1fe与偏差和操作系统有关,该数据量是可变的。
数据0x1fe=0x55和0x1ff=0xaa,称为数据旋转(移位)以进行同步。
每个簇的节数*每个节的字节数=格式化驱动器时输入的数字(分配单元大小),因此发现与驱动器外部的关系。
这里很清楚,任何数字数据的原始版本都不能以任何方式区分其副本。
你可以复制任何类型的数字数据,除非芯片不允许这样做,所以要复制这些受保护的数据,必须在先进的实验室中分割芯片并操纵其门,这几乎是不可能的。
* 字节 / byte
| | 该部门 / sector
( ) 簇 / cluster
( |**…*| |**…*| |**…*| )
大 多 数 格 式 中 的 扇 区 为 512 字 节。 下 面 的 程 序 从 存 储 卡 中 读 取 FAT16 或 FAT 格 式 文 件 的 基 本 信 息:
bool cTxos::bFileInit()
{
if(!bSDMMCReceiveBlock(0x00000000))
{
strcpy(ucErrMsg,“File format 0“);
return 0;
}
if(ucFileBlockData[0] != 0xeb
|| ucFileBlockData[1] != 0x3c
|| ucFileBlockData[2] != 0x90)//Jump instruction
{
strcpy(ucErrMsg,“File format J“);
return 0;
}
usFileBPS = ucFileBlockData[11];
usFileBPS |= ucFileBlockData[12] << 8;
ucFileSPC = ucFileBlockData[13];
usFileFRS = ucFileBlockData[14];
usFileFRS |= ucFileBlockData[15] << 8;
ucFileFAT = ucFileBlockData[16];
usFileTRE = ucFileBlockData[17];
usFileTRE |= ucFileBlockData[18] << 8;
usFileSPF = ucFileBlockData[22];
usFileSPF |= ucFileBlockData[23] << 8;
if((ucFileSPC * usFileBPS) != 8192)//Block lengh
{
strcpy(ucErrMsg,“Block lengh is not 8192“);
return 0;
}
ucFileMaxBlocksOfCals = (ucFileSPC * usFileBPS)/512;
//root directory initialize
if(!bOpenDir(0))
{
strcpy(ucErrMsg,“File format-Root dir“);
return 0;
}
return 1;
}
bool cTxos::bOpenDir(unsigned short usCalusterNumber)
{
unsigned int uiRamAddr;
//root directory
uiRamAddr = (usFileFRS+(usFileSPF * ucFileFAT))*usFileBPS;
if(usCalusterNumber != 0)
uiRamAddr += ((usCalusterNumber-2)*ucFileSPC*usFileBPS)+(usFileTRE*32);
vDelayUS(10000);
if(!bSDMMCReceiveBlock(uiRamAddr))
return 0;
for(usCalusterNumber=0; usCalusterNumber<512; usCalusterNumber++)
ucFileDir[usCalusterNumber] = ucFileBlockData[usCalusterNumber];
usFileEntryOffset = 0x0000; //First entry
return 1;
}
在 下 面 的 程 序 中,读 取 一 个 无 限 大 小 的 文 件; 每 次 填 满 256 个 存 储 单 元 后,都 会 重 新 从存 储 卡 的 开 头 读 取 数 据。
void cTxos::vReadDir()
{
//File name 0x00
ucFileName[0] = ucFileDir[usFileEntryOffset+0];//0x00:empty - 0xE5:deleted
ucFileName[1] = ucFileDir[usFileEntryOffset+1];
ucFileName[2] = ucFileDir[usFileEntryOffset+2];
ucFileName[3] = ucFileDir[usFileEntryOffset+3];
ucFileName[4] = ucFileDir[usFileEntryOffset+4];
ucFileName[5] = ucFileDir[usFileEntryOffset+5];
ucFileName[6] = ucFileDir[usFileEntryOffset+6];
ucFileName[7] = ucFileDir[usFileEntryOffset+7];
ucFileName[8] = '';
//File type 0x08
ucFileType[0] = ucFileDir[usFileEntryOffset+8];
ucFileType[1] = ucFileDir[usFileEntryOffset+9];
ucFileType[2] = ucFileDir[usFileEntryOffset+10];
ucFileType[3] = '';
//File first caluster 0x1A
usFileOSR = ucFileDir[usFileEntryOffset+26];
usFileOSR |= ucFileDir[usFileEntryOffset+27] << 8;
usFileEntryOffset += 0x20; //Next entry
//End of cache
if(usFileEntryOffset == 0x200)
usFileEntryOffset = 0x00; //First entry
}
bool cTxos::bOpenFile(unsigned short usCalusterNumber)
{
unsigned short usX,
usY,
usFirstAddr = (usFileFRS*usFileBPS),
usLastStart = usFirstAddr;
vDelayUS(100);
ucFileLastBlockOfCal = 0;
ucFileLastCal = 0;
usFileCalusters[0] = usCalusterNumber;
usFileCalusters[255] = 0;
usY = (usFileCalusters[0])*2;
usFirstAddr = (usFileFRS*usFileBPS);
usLastStart = usFirstAddr+(usY&0xfe00);
if(!bSDMMCReceiveBlock(usLastStart))
return 0;
for(usX=0; usX<255;)
{
if(!((usFirstAddr+usY) >= usLastStart && (usFirstAddr+usY) < (usLastStart+512)))
{
usLastStart = usFirstAddr+(usY&0xfe00);
if(!bSDMMCReceiveBlock(usLastStart))
return 0;
}
usY = ucFileBlockData[(usY&0x01ff)]
|(ucFileBlockData[(usY&0x01ff)+1]<<8);
usX++;
if(usY!=0xffff)
usFileCalusters[usX] = usY;
else
{
usFileCalusters[usX] = 0;
break;
}
usY = (usFileCalusters[usX])*2;
}
return 1;
}
bool cTxos::bReadFile()
{
vDelayUS(100);
if(usFileCalusters[ucFileLastCal]==0)
return 0;
if(ucFileLastCal == 255)
if(!bOpenFile(usFileCalusters[ucFileLastCal]))
return 0;
if(!bSDMMCReceiveBlock((( usFileFRS+(usFileSPF * ucFileFAT)+((usFileCalusters[ucFileLastCal]-2)*ucFileSPC) )*usFileBPS)+(usFileTRE*32)+(ucFileLastBlockOfCal*512)))
return 0;
if(ucFileLastBlockOfCal < ucFileMaxBlocksOfCals-1)
ucFileLastBlockOfCal++;
else
{
ucFileLastBlockOfCal = 0;
ucFileLastCal++;
}
return 1;
}
void cTxos::vReadFileGoToAddr(unsigned int uiAddr)//512 bytes step - max 2MB offset from 0 in 8192 format
{
ucFileLastCal = uiAddr/ucFileMaxBlocksOfCals;
ucFileLastBlockOfCal = uiAddr%ucFileMaxBlocksOfCals;
}
最 后 一 个 函 数 移 动 内 存 读 取 位 置 / 位 置,下 面 的 程 序 也 展 示 了 使 用 上 述 函 数 读 取 BMP-16bit-RGB-565 格 式 图 像 的 示 例:
bool cTxos::bDrawBMPFile(unsigned short usCalNumber)
{
unsigned short usX;
unsigned char ucY;
if(!bOpenFile(usCalNumber))
return 0;
if(!bReadFile())
return 0;
if(ucFileBlockData[0]==0x42 && ucFileBlockData[1]==0x4d)
{
usCalNumber = ucFileBlockData[10]|(ucFileBlockData[11]<<8);
for(ucY=240; ucY>0; )
{
ucY--;
for(usX=0; usX<320;usX++)
{
if(usCalNumber == 512)
{
if(!bReadFile())
return 0;
usCalNumber = 0;
}
vPrintPixel(usX,ucY,ucFileBlockData[usCalNumber]|(ucFileBlockData[usCalNumber+1]<<8));
usCalNumber+=2;
}
}
return 1;
}
return 0;
}
***“”电子、编程和 Arduino 项目,包括为工程师、学生和业余爱好者提供的源代码、原理图和 PCB 计划“”***
作者:M. Mahdi K. Kanan – 全栈电子和编程工程师、WiCardTech 创始人