1.主控相片STR710FZ02T6,ARM7内核,片内集成256K的FLASH,64k的RAM。内部资源有,can,usb,uart,iic,isp,ad,48/io,定时器,中断,中断向量表32个,16级IRQ嵌套。16根数据线,24根地址线。内部总线和两条APB总线将片上系统和外设资源紧密的连接起来,其中内部总线是主系统总线,连接了CPU、存储器和系统时钟等,APB1总线(APB1桥连接的APB总线)连接高速外设,APB2总线(APB2桥连接的APB总线)连接系统通用外设和中断控制。I/O端口包括P0,P1,P2三个16位的端口,其它的外设接口引脚都与I/O端口的引脚功能复用。
2.nandflash的型号是K9F1208U0C,(64M+2M)的存储空间,
写时序
读时序
块得擦除
送指令时序
送地址时序
地址传送
指令表
3.FAT文件系统
4.1 关于DBR.
DBR区(DOS BOOT RECORD)即操作系统引导记录区的意思,通常占用分区的第0扇区共512个字节(特殊情况也要占用其它保留扇区,我们先说第0扇)。在这512个字节中,其实又是由跳转指令,厂商标志和操作系统版本号,BPB(BIOS Parameter Block),扩展BPB,os引导程序,结束标志几部分组成。 以用的最多的FAT32为例说明分区DBR各字节的含义。见图8。
[返回索引]
图8的对应解释见表3
表3 FAT32分区上DBR中各部分的位置划分 |
|||
字节位移 |
字段长度 |
字段名 |
对应图8颜色 |
0x00 |
3个字节 |
跳转指令 |
|
0x03 |
8个字节 |
厂商标志和os版本号 |
|
0x0B |
53个字节 |
BPB |
|
0x40 |
26个字节 |
扩展BPB |
|
0x5A |
420个字节 |
引导程序代码 |
|
0x01FE |
2个字节 |
有效结束标志 |
[返回索引]
图9给出了winhex对图8 DBR的相关参数解释:
[返回索引]
根据上边图例,我们来讨论DBR各字节的参数意义。
MBR将CPU执行转移给引导扇区,因此,引导扇区的前三个字节必须是合法的可执行的基于x86的CPU指令。这通常是一条跳转指令,该指令负责跳过接下来的几个不可执行的字节(BPB和扩展BPB),跳到操作系统引导代码部分。
跳转指令之后是8字节长的OEM ID,它是一个字符串, OEM ID标识了格式化该分区的操作系统的名称和版本号。为了保留与MS-DOS的兼容性,通常Windows 2000格式化该盘是在FAT16和FAT32磁盘上的该字段中记录了“MSDOS 5.0”,在NTFS磁盘上(关于ntfs,另述),Windows 2000记录的是“NTFS”。通常在被Windows 95格式化的磁盘上OEM ID字段出现“MSWIN4.0”,在被Windows 95 OSR2和Windows 98格式化的磁盘上OEM ID字段出现“MSWIN4.1”。
接下来的从偏移0x0B开始的是一段描述能够使可执行引导代码找到相关参数的信息。通常称之为BPB(BIOS Parameter Block),BPB一般开始于相同的位移量,因此,标准的参数都处于一个已知的位置。磁盘容量和几何结构变量都被封在BPB之中。由于引导扇区的第一部分是一个x86跳转指令。因此,将来通过在BPB末端附加新的信息,可以对BPB进行扩展。只需要对该跳转指令作一个小的调整就可以适应BPB的变化。图9已经列出了项目的名称和取值,为了系统的研究,针对图8,将FAT32分区格式的BPB含义和扩展BPB含义释义为表格,见表4和表5。
表4 FAT32分区的BPB字段 |
|||
字节位移 |
字段长度(字节) |
图8对应取值 |
名称和定义 |
0x0B |
2 |
0x0200 |
扇区字节数(Bytes Per Sector) 硬件扇区的大小。本字段合法的十进制值有512、1024、2048和4096。对大多数磁盘来说,本字段的值为512 |
0x0D |
1 |
0x08 |
每簇扇区数(Sectors Per Cluster),一簇中的扇区数。由于FAT32文件系统只能跟踪有限个簇(最多为4 294 967 296个),因此,通过增加每簇扇区数,可以使FAT32文件系统支持最大分区数。一个分区缺省的簇大小取决于该分区的大小。本字段的合法十进制值有1、2、4、8、16、32、64和128。Windows 2000的FAT32实现只能创建最大为32GB的分区。但是,Windows 2000能够访问由其他操作系统(Windows 95、OSR2及其以后的版本)所创建的更大的分区 |
0x0e |
2 |
0x0020 |
保留扇区数(Reserved Sector) 第一个FAT开始之前的扇区数,包括引导扇区。本字段的十进制值一般为32 |
0x10 |
1 |
0x02 |
FAT数(Number of FAT) 该分区上FAT的副本数。本字段的值一般为2 |
0x11 |
2 |
0x0000 |
根目录项数(Root Entries)只有FAT12/FAT16使用此字段。对FAT32分区而言,本字段必须设置为 0 |
0x13 |
2 |
0x0000 |
小扇区数(Small Sector)(只有FAT12/FAT16使用此字段)对FAT32分区而言,本字段必须设置为0 |
0x15 |
1 |
0xF8 |
媒体描述符( Media Descriptor)提供有关媒体被使用的信息。值0xF8表示硬盘,0xF0表示高密度的3.5寸软盘。媒体描述符要用于MS-DOS FAT16磁盘,在Windows 2000中未被使用 |
0x16 |
2 |
0x0000 |
每FAT扇区数(Sectors Per FAT)只被FAT12/FAT16所使用,对FAT32分区而言,本字段必须设置为0 |
0x18 |
2 |
0x003F |
每道扇区数(Sectors Per Track) 包含使用INT13h的磁盘的“每道扇区数”几何结构值。该分区被多个磁头的柱面分成了多个磁道 |
0x1A |
2 |
0x00FF |
磁头数(Number of Head) 本字段包含使用INT 13h的磁盘的“磁头数”几何结构值。例如,在一张1.44MB 3.5英寸的软盘上,本字段的值为 2 |
0x1C |
4 |
0x0000003F |
隐藏扇区数(Hidden Sector) 该分区上引导扇区之前的扇区数。在引导序列计算到根目录的数据区的绝对位移的过程中使用了该值。本字段一般只对那些在中断13h上可见的媒体有意义。在没有分区的媒体上它必须总是为0 |
0x20 |
4 |
0x007D043F |
总扇区数(Large Sector) 本字段包含FAT32分区中总的扇区数 |
0x24 |
4 |
0x00001F32 |
每FAT扇区数(Sectors Per FAT)(只被FAT32使用)该分区每个FAT所占的扇区数。计算机利用这个数和 FAT数以及隐藏扇区数(本表中所描述的)来决定根目录从哪里开始。该计算机还可以从目录中的项数决定该分区的用户数据区从哪里开始 |
0x28 |
2 |
0x00 |
扩展标志(Extended Flag)(只被FAT32使用)该两个字节结构中各位的值为: |
0x2A |
2 |
0x0000 |
文件系统版本(File ystem Version)只供FAT32使用,高字节是主要的修订号,而低字节是次要的修订号。本字段支持将来对该FAT32媒体类型进行扩展。如果本字段非零,以前的Windows版本将不支持这样的分区 |
0x2C |
4 |
0x00000002 |
根目录簇号(Root Cluster Number)(只供FAT32使用) 根目录第一簇的簇号。本字段的值一般为2,但不总是如此 |
0x30 |
2 |
0x0001 |
文件系统信息扇区号(File System Information SectorNumber)(只供FAT32使用) FAT32分区的保留区中的文件系统信息(File System Information, FSINFO)结构的扇区号。其值一般为1。在备份引导扇区(Backup Boot Sector)中保留了该FSINFO结构的一个副本,但是这个副本不保持更新 |
0x34 |
2 |
0x0006 |
备份引导扇区(只供FAT32使用) 为一个非零值,这个非零值表示该分区保存引导扇区的副本的保留区中的扇区号。本字段的值一般为6,建议不要使用其他值 |
0x36 |
12 |
12个字节均为0x00 |
保留(只供FAT32使用)供以后扩充使用的保留空间。本字段的值总为0 |
[返回索引]
表5 FAT32分区的扩展BPB字段 |
|||
字节位移 |
字段长度(字节) |
图8对应取值 |
字段名称和定义 |
0x40 |
1 |
0x80 |
物理驱动器号( Physical Drive Number) 与BIOS物理驱动器号有关。软盘驱动器被标识为0x00,物理硬盘被标识为0x80,而与物理磁盘驱动器无关。一般地,在发出一个INT13h BIOS调用之前设置该值,具体指定所访问的设备。只有当该设备是一个引导设备时,这个值才有意义 |
0x41 |
1 |
0x00 |
保留(Reserved) FAT32分区总是将本字段的值设置为0 |
0x42 |
1 |
0x29 |
扩展引导标签(Extended Boot Signature) 本字段必须要有能被Windows 2000所识别的值0x28或0x29 |
0x43 |
4 |
0x33391CFE |
分区序号(Volume Serial Number) 在格式化磁盘时所产生的一个随机序号,它有助于区分磁盘 |
0x47 |
11 |
"NO NAME" |
卷标(Volume Label) 本字段只能使用一次,它被用来保存卷标号。现在,卷标被作为一个特殊文件保存在根目录中 |
0x52 |
8 |
"FAT32" |
系统ID(System ID) FAT32文件系统中一般取为"FAT32" |
[返回索引]
DBR的偏移0x5A开始的数据为操作系统引导代码。这是由偏移0x00开始的跳转指令所指向的。在图8所列出的偏移0x00~0x02的跳转指令"EB 58 90"清楚地指明了OS引导代码的偏移位置。jump 58H加上跳转指令所需的位移量,即开始于0x5A。此段指令在不同的操作系统上和不同的引导方式上,其内容也是不同的。大多数的资料上都说win98,构建于fat基本分区上的win2000,winxp所使用的DBR只占用基本分区的第0扇区。他们提到,对于fat32,一般的32个基本分区保留扇区只有第0扇区是有用的。实际上,以FAT32构建的操作系统如果是win98,系统会使用基本分区的第0扇区和第2扇区存储os引导代码;以FAT32构建的操作系统如果是win2000或winxp,系统会使用基本分区的第0扇区和第0xC扇区(win2000或winxp,其第0xC的位置由第0扇区的0xAB偏移指出)存储os引导代码。所以,在fat32分区格式上,如果DBR一扇区的内容正确而缺少第2扇区(win98系统)或第0xC扇区(win2000或winxp系统),系统也是无法启动的。如果自己手动设置NTLDR双系统,必须知道这一点。
DBR扇区的最后两个字节一般存储值为0x55AA的DBR有效标志,对于其他的取值,系统将不会执行DBR相关指令。上面提到的其他几个参与os引导的扇区也需以0x55AA为合法结束标志。
TAT表。
格式化FAT16分区时,格式化程序根据分区的大小确定簇的大小,然后根据保留扇区的数目、根目录的扇区数目、数据区可分的簇数与FAT表本身所占空间 来确定FAT表所需的扇区数目,然后将计算后的结果写入DBR的相关位置。
FAT16 DBR参数的偏移0x11处记录了根目录所占扇区的数目。偏移0x16记录了FAT表所占扇区的数据。偏移0x10记录了FAT表的副本数目。系统在得到这几项参数以后,就可以确定数据区的开始扇区偏移了。
FAT16文件系统从根目录所占的32个扇区之后的第一个扇区开始以簇为单位进行数据的处理,这之前仍以扇区为单位。对于根目录之后的第一个簇,系统并不编号为第0簇或第1簇 (可能是留作关键字的原因吧),而是编号为第2簇,也就是说数据区顺序上的第1个簇也是编号上的第2簇。
FAT文件系统之所以有12,16,32不同的版本之分,其根本在于FAT表用来记录任意一簇链接的二进制位数。以FAT16为例,每一簇在FAT表中占据2字节(二进制16位)。所以,FAT16最大可以表示的簇号为0xFFFF(十进制的65535),以32K为簇的大小的话,FAT32可以管理的最大磁盘空间为:32KB×65535=2048MB,这就是为什么FAT16不支持超过2GB分区的原因。
FAT表实际上是一个数据表,以2个字节为单位,我们暂将这个单位称为FAT记录项,通常情况其第1、2个记录项(前4个字节)用作介质描述。从第三个记录项开始记录除根目录外的其他文件及文件夹的簇链情况。根据簇的表现情况FAT用相应的取值来描述,见表10
表10 FAT16记录项的取值含义(16进制) |
|
FAT16记录项的取值 |
对应簇的表现情况 |
0000 |
未分配的簇 |
0002~FFEF |
已分配的簇 |
FFF0~FFF6 |
系统保留 |
FFF7 |
坏簇 |
FFF8~FFFF |
文件结束簇 |
看一幅在winhex所截FAT16的文件分配表,图10:
[返回索引]
[返回索引]
如图,FAT表以"F8 FF FF FF" 开头,此2字节为介质描述单元,并不参与FAT表簇链关系。小红字标出的是FAT扇区每2字节对应的簇号。
相对偏移0x4~0x5偏移为第2簇(顺序上第1簇),此处为FF,表示存储在第2簇上的文件(目录)是个小文件,只占用1个簇便结束了。
第3簇中存放的数据是0x0005,这是一个文件或文件夹的首簇。其内容为第5簇,就是说接下来的簇位于第5簇——〉 FAT表指引我们到达FAT表的第5簇指向,上面写的数据是"FF FF",意即此文件已至尾簇。
第4簇中存放的数据是0x0006,这又是一个文件或文件夹的首簇。其内容为第6簇,就是说接下来的簇位于第6簇——〉FAT表指引我们到达FAT表的第6簇指向,上面写的数据是0x0007,就是说接下来的簇位于第7簇——〉FAT表指引我们到达FAT表的第7簇指向……直到根据FAT链读取到扇区相对偏移0x1A~0x1B,也就是第13簇,上面写的数据是0x000E,也就是指向第14簇——〉14簇的内容为"FF FF",意即此文件已至尾簇。
后面的FAT表数据与上面的道理相同。不再分析。
FAT表记录了磁盘数据文件的存储链表,对于数据的读取而言是极其重要的,以至于Microsoft为其开发的FAT文件系统中的FAT表创建了一份备份,就是我们看到的FAT2。FAT2与FAT1的内容通常是即时同步的,也就是说如果通过正常的系统读写对FAT1做了更改,那么FAT2也同样被更新。如果从这个角度来看,系统的这个功能在数据恢复时是个天灾。
FAT文件系统的目录结构其实是一颗有向的从根到叶的树,这里提到的有向是指对于FAT分区内的任一文件(包括文件夹),均需从根目录寻址来找到。可以这样认为:目录存储结构的入口就是根目录。
FAT文件系统根据根目录来寻址其他文件(包括文件夹),故而根目录的位置必须在磁盘存取数据之前得以确定。FAT文件系统就是根据分区的相关DBR参数与DBR中存放的已经计算好的FAT表(2份)的大小来确定的。格式化以后,跟目录的大小和位置其实都已经确定下来了:位置紧随FAT2之后,大小通常为32个扇区。根目录之后便是数据区第2簇。
FAT文件系统的一个重要思想是把目录(文件夹)当作一个特殊的文件来处理,FAT32甚至将根目录当作文件处理(旁:NTFS将分区参数、安全权限等好多东西抽象为文件更是这个思想的升华),在FAT16中,虽然根目录地位并不等同于普通的文件或者说是目录,但其组织形式和普通的目录(文件夹)并没有不同。FAT分区中所有的文件夹(目录)文件,实际上可以看作是一个存放其他文件(文件夹)入口参数的数据表。所以目录的占用空间的大小并不等同于其下所有数据的大小,但也不等同于0。通常是占很小的空间的,可以看作目录文件是一个简单的二维表文件。其具体存储原理是:
不管目录文件所占空间为多少簇,一簇为多少字节。系统都会以32个字节为单位进行目录文件所占簇的分配。这32个字节以确定的偏移来定义本目录下的一个文件(或文件夹)的属性,实际上是一个简单的二维表。
这32个字节的各字节偏移定义如表11:
表11 FAT16目录项32个字节的表示定义 |
|||
字节偏移(16进制) |
字节数 |
定义 |
|
0x0~0x7 |
8 |
文件名 |
|
0x8~0xA |
3 |
扩展名 |
|
0xB |
1 |
属性字节 |
00000000(读写) |
00000001(只读) |
|||
00000010(隐藏) |
|||
00000100(系统) |
|||
00001000(卷标) |
|||
00010000(子目录) |
|||
00100000(归档) |
|||
0xC~0x15 |
10 |
系统保留 |
|
0x16~0x17 |
2 |
文件的最近修改时间 |
|
0x18~0x19 |
2 |
文件的最近修改日期 |
|
0x1A~0x1B |
2 |
表示文件的首簇号 |
|
0x1C~0x1F |
4 |
表示文件的长度 |
Nandflash于fat的接口函数
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "diskio.h"
#include "nandflash.h"
#include "my_uart.h"
extern u8 write_sta;
/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
return 0 ;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
return 0;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..255) */
)
{
u8 result;
result=FlashSectorRead2(buff, sector, count); /* 页写 */
if(result==0)
return RES_OK;
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
/* The FatFs module will issue multiple sector transfer request
/ (count > 1) to the disk I/O layer. The disk function should process
/ the multiple sector transfer properly Do. not translate it into
/ multiple single sector transfers to the media, or the data read/write
/ performance may be drasticaly decreased. */
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..255) */
)
{
u8 result;
if(write_sta)
result=FlashSectorWriten2(buff, sector, count); /* 使用回写 */
else
result=FlashSectorWriten1(buff, sector, count); /* 格式化硬盘不使用回写 */
if(result==0)
return RES_OK;
return RES_PARERR;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res=RES_OK;
if(drv){ return RES_PARERR ; }
switch(ctrl)
{
case CTRL_SYNC:
break;
case GET_BLOCK_SIZE:
*(DWORD*)buff=4096; /* 块个数 */
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff=1*32*1024; /* 2个页位一个簇 32k*/
break;
case GET_SECTOR_SIZE:
*(DWORD*)buff=512; /* 页大小 */
break;
default:
res=RES_PARERR;
break;
}
return res;
}