您的位置:首页 > 其它

NAND 设备上所支持的文件系统

2008-04-28 10:09 211 查看
A. JFFS2(没有坏块处理,支持大容量存储的时候需要消耗大量的内存,大量的随机访问降低了NAND设备的读取效率)和YAFFS(速度快,但不支持文件的压缩和解压)
B. 支持DiskOnChip设备的TRUEFFS(True Flash File System). TRUEFFS是M-Systems公司为其产品DiskOnChip开发的文件系统,其规范并不开放。
C. 由SSFDC(Solid State Floppy Disk Card)论坛定义的支持SM卡的DOS-FAT。SM卡的DOS-FAT文件系统是由SSFDC论坛定义的,但它必须用在标准的块设备上。
对于大量用在各类存储卡上的NAND 设备而言,他们几乎都采用FAT文件系统,而在嵌入式操作系统下,还没有驱动程序可以直接让NAND设备采用文件系统,就技术角度来说,FAT文件系统不是很适合NAND设备,因为FAT文件系统的文件分区表需要不断地擦写,而NAND设备的只能有限次的擦写。

在上面已经很明显的提到,NAND设备存在坏块,为和上层文件系统接口,NAND设备的驱动程序必须给文件系统提供一个可靠的存储空间,这就需要ECC(Error Corection Code)校验,坏块标注、地址映射等一系列的技术手段来达到可靠存储目的。
SSFDC软件规范中,详细定义了如何利用NAND设备每个页中的冗余信息来实现上述功能。这个软件规范中,很重要的一个概念就是块的逻辑地址,它将在物理上可能不连续、不可靠的空间分配编号,为他们在逻辑空间上给系统文件提供一个连续可靠的存储空间。
表3给出了SSFDC规范中逻辑地址的标注方法。在系统初始化的时候,驱动程序先将所有的块扫描一遍,读出他们所对应的逻辑地址,并把逻辑地址和虚拟地址的映射表建好。系统运行时,驱动程序通过查询映射表,找到需要访问的逻辑地址所对应的物理地址然后进行数据读写。






表3 冗余字节定义
字节序号
内容
字节序号
内容
512
用户定义数据
520
后256BECC校验和
513
521
514
522
515
523
块逻辑地址
516
数据状态
524
517
块状态
525
前256BECC校验和
518
块逻辑地址1
526
519
527
表4给出了块逻辑地址的存放格式,LA表示逻辑地址,P代表偶校验位。逻辑地址只有10bit,代表只有1024bit的寻址空间。而SSFDC规范将NAND设备分成了多个zone,每个zone 内有1024块,但这物理上的1024块映射到逻辑空间只有1000块,其他的24块就作为备份使用,当有坏块存在时,就可以以备份块将其替换。
表4 逻辑地址格式
D7
D6
D5
D4
D3
D2
D1
D0
0
0
0
1
0
LA9
LA8
LA7
第518 523字节
LA6
LA5
LA4
LA3
LA2
LA1
LA0
P
第519 524字节
有了以上的软件规范,就可以对NAND设备写出较标准的ECC校验,并可以编写检测坏块、标记坏块、建立物理地址和逻辑地址的映射表的程序了。

static int NF_IsBadBlock(U32 block) //检测坏块
{
int i;
unsigned int blockPage;
U8 data;

blockPage=(block<<5); // For 2'nd cycle I/O[7:5]

NF_nFCE_L();
NF_CMD(0x50); // Spare array read command
NF_ADDR(517&0xf); // Read the mark of bad block in spare array(M addr="5") [q6]
NF_ADDR(blockPage&0xff); // The mark of bad block is in 0 page
NF_ADDR((blockPage>>8)&0xff); // For block number A[24:17]
NF_ADDR((blockPage>>16)&0xff); // For block number A[25]

for(i=0;i<10;i++); // wait tWB(100ns) //?????

NF_WAITRB(); // Wait tR(max 12us)

data=NF_RDDATA();

NF_nFCE_H();

if(data!=0xff)
{
Uart_Printf("[block %d has been marked as a bad block(%x)]/n",block,data);
return 1;
}
else
{
return 0;
}
}

static int NF_MarkBadBlock(U32 block) //标记坏块
{
int i;
U32 blockPage=(block<<5);

seBuf[0]=0xff;
seBuf[1]=0xff;
seBuf[2]=0xff;
seBuf[5]=0x44; // Bad blcok mark="0"[q7]

NF_nFCE_L();
NF_CMD(0x50); //????
NF_CMD(0x80); // Write 1st command

NF_ADDR(0x0); // The mark of bad block is
NF_ADDR(blockPage&0xff); // marked 5th spare array
NF_ADDR((blockPage>>8)&0xff); // in the 1st page.
NF_ADDR((blockPage>>16)&0xff);

for(i=0;i<16;i++)
{
NF_WRDATA(seBuf[i]); // Write spare array
}

NF_CMD(0x10); // Write 2nd command

for(i=0;i<10;i++); //tWB = 100ns. ///???????

NF_WAITRB(); // Wait tPROG(200~500us)

NF_CMD(0x70);

for(i=0;i<3;i++); //twhr=60ns////??????

if (NF_RDDATA()&0x1) // Spare arrray write error
{
NF_nFCE_H();
Uart_Printf("[Program error is occurred but ignored]/n");
}
else
{
NF_nFCE_H();
}

Uart_Printf("[block #%d is marked as a bad block]/n",block);
return 1;
}

int search_logic_block(void) //建立物理地址到逻
//辑地址的映射表
{
unsigned int block,i,blockPage,logic_no,zone,zone_i;
U8 SE[16];
for(i=0;i<BLOCK_NR;i++) //初始化全局变量
lg2ph[i]=space_block[i]=0xffff;
logic_number=0;
space_nr=0;

NF_nFCE_L();
zone=BLOCK_NR/1024; //确定NAND设备中zone
//的个数

for(zone_i=0;zone_i<zone;zone_i++)
{
//搜索每个zone 内逻辑地址和物理地址的映射关系
for(block=0;block<1024;block++)
{
blockPage=((block+zone_i*1024)<<BLOCK_ADDRERSS_SHIFT);
NF_WATIRB(); //等待R/B#信号有效

NF_CMD(0x50); // 读取每个block内部第
//0个Page内冗余的16个字节
NF_ADDR(0); // Column 0
NF_ADDR(blockPage&0xff);
NF_ADDR((blockPage>>8)&0xff); // Block & page num.
NF_ADDR((blockPage>>16)&0xff);

NF_WATIRB(); //等待R/B#信号有效
for(i=0;i<16;i++) se[i]=NF_RDDATA(); // Write spare array
NF_WATIRB();

if(se[5]!=0xff)[q8] //检测是否存在坏块
printk("/n/rphysic block %d is bad block/n/r",block);
else if(se[7]!=se[12][q9] )
printk("block address1:%d!=block address2 %d/n/r",se[7],se[12]);
else if((se[6][q10] &0xf8)==0x10)
{
//计算该block对应的逻辑地址
logic_no=((0x7&se[6])<<7)+(se[7]>>1)+zone_i*1000;
if(lg2ph[logic_no]!=0xffff) //说明有2个block拥有相
//同的逻辑地址
printk("physical block %d and block %d have the same logic number %d/n",lg2ph[logic_no],block,logic_no);
else lg2ph[logic_no]=block; //将该block的逻辑地址
//关系记入lg2ph表
logic_number++;
}
else if(se[7]==0xff) //说明该block尚未编号
{space_block[space_nr]=block;
space_nr++;
}
}
}
printk("there are totally %d logic blocks/n/r",logic_number);
NF_nFCE_H();
return logic_number;
}
这段代码的主要作用就是产生数组lg2ph[],这个数组的含义就是“块物理地址=lg2ph[逻辑地址]”。




[q1]发出擦除命令

[q2]确认并擦除

[q3]2410处理器的功能

[q4]为什么要有一个读取的命令???

[q5]读取ECC并写入16字节中

[q6]参看表3

[q7]标记块状态 517字节

[q8]块状态

[q9]块逻辑地址1和块逻辑地址2

[q10]块逻辑地址1

原文地址 http://www.ednchina.com/blog/lanzhucao/28454/message.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: